Compare commits

...

177 Commits

Author SHA1 Message Date
lightningterror 2fb8a48418 GS/GL: Properly clear fbo states.
Fixes crashes in Renderdoc when re launching OpenGL again.
2026-04-05 10:29:28 +02:00
JordanTheToaster ce472dde8b Deps: Update SDL3 to v3.4.4 2026-04-05 04:12:52 +02:00
lightningterror f56d3b5f2f GS/GL: Drop requirement for GLAD_GL_ARB_draw_buffers_blend.
Currently we don't use hw blend on individual render targets
so we can revert to old behavior while keeping compatibility
with older drivers.
2026-04-05 04:12:39 +02:00
TellowKrinkle 0804b68fc6 Common: Fix build with older ryml 2026-04-04 19:40:48 -05:00
PCSX2 Bot 05c6a95fe5 [ci skip] Qt: Update Base Translation. 2026-04-05 02:20:15 +02:00
RedPanda4552 8a3f4609a6 Discord RPC: Swap Discord app id, use const vars for Discord constants 2026-04-04 15:39:20 -04:00
TellowKrinkle a5867bfd44 Deps: Disable unused SDL modules
Less to build, and avoids picking up unnecessary dependencies
2026-04-04 15:30:58 -04:00
lightningterror 2c608b4293 GS/GL: Backport multidraw fb copy for depth feedbacks. 2026-04-04 04:27:20 +02:00
lightningterror 2c908f4d09 GS/DX11: Check if Depth feedback is enabled before making a copy. 2026-04-04 04:27:20 +02:00
lightningterror c1bf4d5a56 GS/GL: Backport multidraw fb copy from DX11.
Will be used when GL_ARB_texture_barrier  isn't supported.
Can also be used for Depth feedback loops.
2026-04-04 04:27:20 +02:00
lightningterror eab8b92037 GS/DX11: Cleanup some multidraw fb copy code.
Remove skip first barrier check, rely on the one barrier parameter being set to false.
Other misc cleanup.
2026-04-04 04:27:20 +02:00
PCSX2 Bot 4aa72d949f [ci skip] Qt: Update Base Translation. 2026-04-04 02:09:05 +02:00
KamFretoZ 26a86130de Qt: Add a bunch of Open XXX Folder for Game List Entries 2026-04-03 13:00:31 -04:00
chaoticgd 0beb18c9e1 Deps: Update rapidyaml to v0.11.1 2026-04-03 12:41:47 -04:00
KamFretoZ ade5762a45 Qt: Add Option for storing video captures per-games 2026-04-03 12:41:05 -04:00
lightningterror 5cb7abf10c GS/GL: Make sure we always insert a barrier when tex is rt/ds. 2026-04-01 23:05:31 +02:00
JordanTheToaster 7561f7ef70 GameDB: Silent Hill Shattered Memories fixes 2026-03-31 23:42:34 +02:00
lightningterror ac69bb2142 GS/HW: Don't bind source tex when using tex is fb hle.
Slot 2 will be used for fb read instead of slot 0, don't bind it when it's not needed.
2026-03-31 02:07:12 +02:00
PCSX2 Bot 2c7c8e19e2 [ci skip] PAD: Update to latest controller database. 2026-03-30 12:21:27 -04:00
PCSX2 Bot 59d00a0134 [ci skip] Qt: Update Base Translation. 2026-03-30 02:06:50 +02:00
TJnotJT 372fadfb99 GS/HW: Disable depth if zero clear, ZBP == FBP, and depth/RT different bpp. 2026-03-29 21:53:14 +02:00
TJnotJT 406c2c0bbf GS/HW: Cleanup DATE configuration. 2026-03-29 21:10:33 +02:00
TJnotJT a5ba35ce92 GS/HW: Check overlap of required rect with valid area in source lookup.
Check recent transfers for RT in source lookup if it has dirty rects or the valid area does not intersect with the required rect. The latter check is needed in case a recent transfer did not intersect the valid area of the RT.
2026-03-29 21:04:09 +02:00
TellowKrinkle f6b2887ae0 GS: Add unsafe setting warnings for debug settings
It's pretty common to forget to turn them off after debugging...
2026-03-29 11:39:20 -04:00
TellowKrinkle cba474000e Deps: Use strict with shasum check
Catch any mistakes we make with the hash list
2026-03-29 11:38:45 -04:00
TellowKrinkle cb64246288 Deps: Use better GitHub archive URLs 2026-03-29 11:38:45 -04:00
TellowKrinkle 4006be49f8 Deps: Remove empty lines from shasum file
shasum util complains about them
2026-03-29 11:38:45 -04:00
TellowKrinkle 085f1dcb68 Deps: Hash check files before downloading
When working on the build scripts, it's convenient to not have to redownload everything every time you try to run and it fails to build
2026-03-29 11:38:45 -04:00
PCSX2 Bot 1372d71fa7 [ci skip] Qt: Update Base Translation. 2026-03-29 11:28:05 -04:00
TheLastRar 2fda2d512d GS/HW: Reduce number of cached palettes 2026-03-29 11:28:00 -04:00
TheLastRar 1edc304453 OSD: Add option to show descriptor usage in D3D12 2026-03-29 11:28:00 -04:00
TellowKrinkle a291936bf8 GS:SW: Use unaligned loads to reduce constant size on AVX2
Allows more instructions to use 1-byte offsets
2026-03-28 17:49:17 -04:00
TellowKrinkle 9b343bae3e GS:SW: Split g_const into separate structs for 128 and 256 bit vectors
Allows more code to access members with 8b offsets
2026-03-28 17:49:17 -04:00
TellowKrinkle 6336cc82e8 Common: Remove unused functions 2026-03-28 17:49:17 -04:00
TellowKrinkle 3450e3c238 Revert "Core: Reserve memory map as early as possible"
This reverts commit 337daf7ed9.

It's no longer needed
2026-03-28 17:49:17 -04:00
TellowKrinkle 49017c4813 Core: Reserve data and code areas together
They need to stay near each other for the x86 JIT to work
2026-03-28 17:49:17 -04:00
TellowKrinkle 27a88dd333 Common: Allow non-file mappings in SharedMemoryMappingArea 2026-03-28 17:49:17 -04:00
TellowKrinkle 6f4f6cf7de Common: Switch back to Linux allocation routines on macOS
We don't need MAP_FIXED anymore
2026-03-28 17:49:17 -04:00
TellowKrinkle 0020cac123 Core: Map sys memory anywhere 2026-03-28 17:49:17 -04:00
TellowKrinkle 1160758a81 GS:SW: Prepare DrawScanline for being more than 2GB from const data 2026-03-28 17:49:17 -04:00
TellowKrinkle 5c205d6287 EE:Rec: Allow rec memory anywhere 2026-03-28 17:49:17 -04:00
TellowKrinkle e814408026 EE:Rec: Avoid rbx
Will be used for holding a pointer to the PCSX2 text section
2026-03-28 17:49:17 -04:00
KamFretoZ 46e85c4586 VMManager: Make Prefer English also applies to other things 2026-03-27 17:21:33 -04:00
Heit0fff f4b16a8762 GameDB: NCAA Final Four 2004 - disable mVU Flag Hack 2026-03-27 17:07:32 -04:00
TheLastRar cdc8201222 CI: Use latest VS installed on runner 2026-03-27 16:49:58 -04:00
TheLastRar 94c10ca9f9 Deps: Try locating VS2026 if VS2022 is not installed 2026-03-27 16:49:58 -04:00
chaoticgd 724155ba91 Docs: Fix cubeb license 2026-03-26 16:04:49 -04:00
PCSX2 Bot 6ffa916336 [ci skip] Qt: Update Base Translation. 2026-03-26 08:15:16 -04:00
SternXD e3badc754d OSD: Use standard font for input overlay 2026-03-25 17:54:09 +01:00
JordanTheToaster df9783f41f Deps: Update Qt to 6.11.0 2026-03-25 16:15:42 +01:00
chaoticgd e9c6d51566 Qt: Fix position of game list header menu 2026-03-25 15:55:55 +01:00
PCSX2 Bot a8c8223f69 [ci skip] Qt: Update Base Translation. 2026-03-25 11:47:10 +01:00
TellowKrinkle 9b3f827991 GHActions: Accept commit names starting with numbers
[ci skip]
2026-03-25 01:23:12 -05:00
TheLastRar 2d2bfd64ff GHActions: Bump microsoft/setup-msbuild 2026-03-24 12:40:49 -04:00
TellowKrinkle 73a825cbb1 Common:Darwin: Mach exceptions don't need mutex
They run on their own thread, so there's no possibility of concurrent access.
2026-03-24 12:40:37 -04:00
TellowKrinkle 3e0e72e50c Common:Darwin: Don't crash from the mach exception thread
We want crash reports to point to the correct thread.
2026-03-24 12:40:37 -04:00
TellowKrinkle 259350c974 GS: Install page fault handler on GS thread too 2026-03-24 12:40:37 -04:00
PCSX2 Bot e14b4475ff [ci skip] PAD: Update to latest controller database. 2026-03-23 21:30:01 +01:00
Ty b4f030cd37 GHActions: Support '\' and 2026-03-23 09:43:52 -04:00
TellowKrinkle f28c488ecf GHActions: Run arm64 build in Release
We needs its caches on the master branch
2026-03-21 17:12:17 -05:00
PCSX2 Bot 2ac22f8dd9 [ci skip] Qt: Update Base Translation. 2026-03-21 02:32:02 +01:00
TellowKrinkle 5e0b92f1b4 GHActions: Make commit message pattern compatible with reverts
[ci skip]
2026-03-20 18:54:22 -05:00
Ty e1e35982e4 CI: Fix the check commits actions
did not RTFM
2026-03-20 17:50:14 -04:00
TJnotJT 1356f282d0 GS/HW: Don't clamp negative coords to 0 in texture shuffle detection. 2026-03-20 20:48:53 +01:00
TheLastRar 7e8e0d4744 Deps: Bundle ffmpeg on windows 2026-03-20 18:47:11 +01:00
TellowKrinkle 56b20a3a13 GHActions: Build GSRunner on macOS arm build
Should be fast since arm build runs without LTO since we don't need its artifact
2026-03-20 11:13:53 -04:00
TellowKrinkle 10cdacfa30 GHActions: Add macOS arm64 CI 2026-03-20 11:13:53 -04:00
TellowKrinkle 81a20150f2 Core: Use ARCH_ARM64 instead of _M_ARM64
fast_float assumes that _M_ARM64 means compiling for Windows
2026-03-20 11:13:53 -04:00
TellowKrinkle 5e5ea642b0 Deps: Reduce macOS universal build script failures 2026-03-20 11:13:53 -04:00
TellowKrinkle e7733a2d43 Deps: Fix macOS universal dependency build script 2026-03-20 11:13:53 -04:00
Ziemas 3e60e46ae4 IOP Jit: Error on jmup to unaligned address 2026-03-20 11:13:15 -04:00
Ziemas 194037bd4e IOP Jit: Add fallback for unmapped recLUT pages 2026-03-20 11:13:15 -04:00
Ty 5037be3d8f Actions: add a check to ensure commits have a prefix delimited by a colon 2026-03-20 11:12:16 -04:00
refractionpcsx2 8aca0fe288 VIF/MFIFO: Respect MFIFO empty condition on SPR transfers 2026-03-20 11:11:45 -04:00
TheLastRar 0e667a9b0f GS/DX12: Copy constant buffers to default heap 2026-03-20 14:26:12 +01:00
TheLastRar 12940f2e1b GS/DX12: Log if device is UMA 2026-03-20 14:26:12 +01:00
TheLastRar faf6c04dee GS/VK: Restart present pass when uploading large textures 2026-03-20 13:03:57 +01:00
JordanTheToaster 6aadbc18a9 GameDB: Various fixes 2026-03-20 12:54:00 +01:00
JordanTheToaster 2be34a6938 ImGui/GameDB: Add accurate alpha test 2026-03-20 12:54:00 +01:00
TJnotJT daa0d2d3c4 GS: Check if CRTCs have same source after register update.
Previously the check happened before the register update, which could cause it to be incorrect.
2026-03-20 12:40:23 +01:00
TJnotJT 1b4af9deef GS: Fix check for RC1 overwriting RC2 in merge.
Previously, the bbox of each output was not checked, leading to incorrectly assuming that RC2 was overwritten by RC1. This change makes sure that the RC2 bbox is contained in the RC1 bbox to determine that it's overwritten.
2026-03-20 12:40:23 +01:00
Ziemas db6cb43336 vif: warn on invalid unpack instead for crashing 2026-03-20 12:18:56 +01:00
TellowKrinkle 012d352fa7 GHActions: Retry metal toolchain download 2026-03-20 01:42:02 -05:00
PCSX2 Bot 904096cd6e [ci skip] Qt: Update Base Translation. 2026-03-20 01:06:07 +01:00
KamFretoZ b3bb67b43a Qt: Fix recommended value for accurate alpha testing 2026-03-19 20:56:34 +01:00
KamFretoZ deba43640e Qt: Move sstate selector back to interface settings 2026-03-19 20:56:34 +01:00
SternXD d665efdc3a GS/OGL: Query GL_MAX_TEXTURE_SIZE for extended upscale limits
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:50:33 +01:00
SternXD 66493c8dd1 FullscreenUI: add extended internal resolution multipliers for VK/OGL
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:50:33 +01:00
SternXD 9ff85a620e Qt: Temporarily add upscale multiplier if saved value exceeds UI limit
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:50:33 +01:00
SternXD ae1ee7cc3d Qt: Expose extended upscale only when VK/OGL is used
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:50:33 +01:00
SternXD 2392cf7014 Qt: Add Select All and Deselect All buttons for OSD options
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 08fe525a3b OSD: Improve frame time overlay display
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 1cd30601ed FullscreenUI: Add OSD Font Path setting
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 07713e97d7 Qt: Add OSD font picker UI
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD be307f3eb9 GS/ImGui: Add custom OSD font support
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD d9bfdc3fcd Qt/FullscreenUI: Add Bold OSD Text option
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 064a96dfd2 Qt/FullscreenUI: Add OSD Margin setting
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 428e035032 FullscreenUI: Move OSD Settings to it's own tab
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
SternXD 2db9cd0437 Qt: Move OSD settings to its own tab/widget
Signed-off-by: SternXD <stern@sidestore.io>
2026-03-19 20:49:10 +01:00
PCSX2 Bot bd78c33f11 [ci skip] Qt: Update Base Translation. 2026-03-19 01:26:49 +01:00
TellowKrinkle f16774357a GHActions: Add periodic cache clean 2026-03-17 21:12:41 -05:00
TellowKrinkle 00868a1b29 Revert "GHActions: Clean up old caches"
This reverts commit c80866ab5c.

GH Actions refuses to give write perms to caches to PRs from outside the main repo, so this isn't actually very useful
2026-03-17 21:12:41 -05:00
TJnotJT 93212882d0 GS/HW: Depth feedback loops and accurate AFAIL. (#13631)
Add support for depth feedback loops either via texture barriers or copies.
DX12 and OpenGL do depth feedback by creating a temporary color texture to hold Z and using multiple color outputs.
Use the depth feedback for accurate AFAIL (enabled via INI setting).
2026-03-18 02:12:12 +01:00
PCSX2 Bot 7f1ab4043c [ci skip] Qt: Update Base Translation. 2026-03-18 01:07:27 +01:00
TellowKrinkle 65822ecf86 Revert "GHActions: Fix cache clean permissions"
This reverts commit 9dff4f2005.
2026-03-17 13:20:17 -05:00
TellowKrinkle 9dff4f2005 GHActions: Fix cache clean permissions 2026-03-17 14:05:48 -04:00
Ziemas ec8f3b0414 EE JIT: Error on jump to unaligned address 2026-03-17 11:31:56 -04:00
Ziemas dde3c73af7 EE JIT: Add fallback for unmapped recLUT pages.
This prevents guest from segfaulting pcsx2 by jumping to random memory.
2026-03-17 11:31:56 -04:00
JordanTheToaster bc80ea92a3 GameDB: Lots of Z fighting fixes 2026-03-17 16:13:08 +01:00
JordanTheToaster 497dc14d11 GS/HW: Add Limit 24 Bit Depth fix to db 2026-03-17 16:13:08 +01:00
TellowKrinkle c80866ab5c GHActions: Clean up old caches 2026-03-17 11:12:39 -04:00
chaoticgd d856f3f5bd HeapArray: Fix comparison operators 2026-03-17 08:29:18 -04:00
chaoticgd 5d811f03f4 HeapArray: Improve self-assignment behaviour 2026-03-17 08:29:18 -04:00
chaoticgd 600a8b468b Patch: Fix MemoryInterface::CompareBytes functions 2026-03-17 08:58:31 +01:00
PCSX2 Bot e0c5e861be [ci skip] PAD: Update to latest controller database. 2026-03-16 17:33:30 +01:00
chaoticgd d049c395fc SmallString: Improve self-assignment behaviour 2026-03-16 09:41:38 -04:00
dependabot[bot] 6aed46c603 CI: Bump softprops/action-gh-release
Bumps the ci-deps group with 1 update:
[softprops/action-gh-release](https://github.com/softprops/action-gh-release).

Updates `softprops/action-gh-release` from 2.5.0 to 2.6.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
<h2>v2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: support previous_tag for generate_release_notes by <a
href="https://github.com/pocesar"><code>@​pocesar</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/372">softprops/action-gh-release#372</a></li>
</ul>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: recover concurrent asset metadata 404s by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/760">softprops/action-gh-release#760</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify reused draft release behavior by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/759">softprops/action-gh-release#759</a></li>
<li>docs: clarify working_directory input by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/761">softprops/action-gh-release#761</a></li>
<li>ci: verify dist bundle freshness by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/762">softprops/action-gh-release#762</a></li>
<li>fix: clarify immutable prerelease uploads by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/763">softprops/action-gh-release#763</a></li>
</ul>
<h2>v2.5.3</h2>
<!-- raw HTML omitted -->
<p><code>2.5.3</code> is a patch release focused on the remaining
path-handling and release-selection bugs uncovered after
<code>2.5.2</code>.
It fixes
<code>[#639](https://github.com/softprops/action-gh-release/issues/639)</code>,
<code>[#571](https://github.com/softprops/action-gh-release/issues/571)</code>,
<code>[#280](https://github.com/softprops/action-gh-release/issues/280)</code>,
<code>[#614](https://github.com/softprops/action-gh-release/issues/614)</code>,
<code>[#311](https://github.com/softprops/action-gh-release/issues/311)</code>,
<code>[#403](https://github.com/softprops/action-gh-release/issues/403)</code>,
and
<code>[#368](https://github.com/softprops/action-gh-release/issues/368)</code>.
It also adds documentation clarifications for
<code>[#541](https://github.com/softprops/action-gh-release/issues/541)</code>,
<code>[#645](https://github.com/softprops/action-gh-release/issues/645)</code>,
<code>[#542](https://github.com/softprops/action-gh-release/issues/542)</code>,
<code>[#393](https://github.com/softprops/action-gh-release/issues/393)</code>,
and
<code>[#411](https://github.com/softprops/action-gh-release/issues/411)</code>,
where the current behavior is either usage-sensitive or constrained by
GitHub platform limits rather than an action-side runtime bug.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
<h2>2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: support previous_tag for generate_release_notes by <a
href="https://github.com/pocesar"><code>@​pocesar</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/372">softprops/action-gh-release#372</a></li>
</ul>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: recover concurrent asset metadata 404s by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/760">softprops/action-gh-release#760</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>docs: clarify reused draft release behavior by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/759">softprops/action-gh-release#759</a></li>
<li>docs: clarify working_directory input by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/761">softprops/action-gh-release#761</a></li>
<li>ci: verify dist bundle freshness by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/762">softprops/action-gh-release#762</a></li>
<li>fix: clarify immutable prerelease uploads by <a
href="https://github.com/chenrui333"><code>@​chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/763">softprops/action-gh-release#763</a></li>
</ul>
<h2>2.5.3</h2>
<p><code>2.5.3</code> is a patch release focused on the remaining
path-handling and release-selection bugs uncovered after
<code>2.5.2</code>.
It fixes
<code>[#639](https://github.com/softprops/action-gh-release/issues/639)</code>,
<code>[#571](https://github.com/softprops/action-gh-release/issues/571)</code>,
<code>[#280](https://github.com/softprops/action-gh-release/issues/280)</code>,
<code>[#614](https://github.com/softprops/action-gh-release/issues/614)</code>,
<code>[#311](https://github.com/softprops/action-gh-release/issues/311)</code>,
<code>[#403](https://github.com/softprops/action-gh-release/issues/403)</code>,
and
<code>[#368](https://github.com/softprops/action-gh-release/issues/368)</code>.
It also adds documentation clarifications for
<code>[#541](https://github.com/softprops/action-gh-release/issues/541)</code>,
<code>[#645](https://github.com/softprops/action-gh-release/issues/645)</code>,
<code>[#542](https://github.com/softprops/action-gh-release/issues/542)</code>,
<code>[#393](https://github.com/softprops/action-gh-release/issues/393)</code>,
and
<code>[#411](https://github.com/softprops/action-gh-release/issues/411)</code>,
where the current behavior is either usage-sensitive or constrained by
GitHub platform limits rather than an action-side runtime bug.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/softprops/action-gh-release/commit/153bb8e04406b158c6c84fc1615b65b24149a1fe"><code>153bb8e</code></a>
release 2.6.1</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/569deb874d08cd8cc0aa24af7c0b21160fe4b0e4"><code>569deb8</code></a>
fix: preserve discussion category when publishing releases (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/765">#765</a>)</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/26e8ad27a09a225049a7075d7ec1caa2df6ff332"><code>26e8ad2</code></a>
release 2.6.0</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/b959f31e968fb47fb7bb823087fc092d5613e0a4"><code>b959f31</code></a>
fix: clarify immutable prerelease uploads (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/763">#763</a>)</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/8a8510e3a0d8dfc9296171fd405ca8c8ea6206a4"><code>8a8510e</code></a>
ci: verify dist bundle freshness (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/762">#762</a>)</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/438c15ddf5b01e992ef98dc29cea3f9992ab54ac"><code>438c15d</code></a>
docs: clarify working_directory input (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/761">#761</a>)</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/6ca3b5d96e3a0fac11dc53f0809c2cb029e64902"><code>6ca3b5d</code></a>
fix: recover concurrent asset metadata 404s (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/760">#760</a>)</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/11f917660b31d6d56980ea3261f210556a812bd0"><code>11f9176</code></a>
chore: add RELEASE.md</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/1f3f350167714515d2bcf8a18afcc5e8e0a362a8"><code>1f3f350</code></a>
feat: add AGENTS.md</li>
<li><a
href="https://github.com/softprops/action-gh-release/commit/37819cb191890d306d21cfb5ac4e7a358f0a6e4f"><code>37819cb</code></a>
docs: clarify reused draft release behavior (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/759">#759</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/softprops/action-gh-release/compare/a06a81a03ee405af7f2048a818ed3f03bbf83c7b...153bb8e04406b158c6c84fc1615b65b24149a1fe">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=2.5.0&new-version=2.6.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 09:33:56 -04:00
Ziemas f0723a6ec9 vu: 64bit cycle fixes
[SAVEVERSION+]
2026-03-15 08:27:44 -04:00
JordanTheToaster bc624524cf GameDB:Paddington Bear half right fix 2026-03-13 09:43:13 +01:00
PCSX2 Bot d1a44cdae8 [ci skip] Qt: Update Base Translation. 2026-03-13 09:41:49 +01:00
TJnotJT 8a46f9e6ca GSRunner: Disable framerate limit in runner and dump frame timing information. 2026-03-12 18:46:47 +01:00
KamFretoZ eba66a2bb3 FSUI: Add Prefer English Game List Option
This is an addition to #13589
2026-03-12 18:35:17 +01:00
KamFretoZ 7ea5234049 OSD: Make Recommended Blending Accuracy Translatable 2026-03-12 18:35:17 +01:00
KamFretoZ 0b5c37e1c5 Hotkey: Add Cycle Blending Accuracy
Update GS.cpp
2026-03-12 18:35:17 +01:00
KamFretoZ 2f7be602c8 Config/GS: Move more default configs to its own constants 2026-03-12 18:35:17 +01:00
PCSX2 Bot 05289e80a0 [ci skip] Qt: Update Base Translation. 2026-03-12 12:46:17 +01:00
lightningterror 1ddc283ea2 GS/DX11: Check if depth testing and sampling is supported. 2026-03-12 12:32:41 +01:00
JordanTheToaster f969b0d4c7 3rdparty: Update Vulkan-Headers to v1.4.345 2026-03-11 16:51:14 +01:00
JordanTheToaster 1bd475cfab Mac OS: Use Xcode 26.2 2026-03-11 16:51:14 +01:00
JordanTheToaster f678788b6c Deps: Update harfbuzz to 13.0.0 2026-03-11 16:51:14 +01:00
JordanTheToaster 379371f0b5 Deps: Update shaderc to 2026.1 2026-03-11 16:51:14 +01:00
JordanTheToaster 247511fd38 3rdparty: Update rainterface to commit 5d763c2 2026-03-11 16:51:14 +01:00
JordanTheToaster 8de55a1937 Deps: Update zlib to 1.3.2 2026-03-11 16:51:14 +01:00
JordanTheToaster 73010de3b5 3rdparty: Update rcheevos to v12.3.0 2026-03-11 16:51:14 +01:00
JordanTheToaster b29496eb8e 3rdparty: Update libchdr to commit 7891cbe 2026-03-11 16:51:14 +01:00
JordanTheToaster dc88ed97ab 3rdparty: Update CPUInfo to commit 7364b49 2026-03-11 16:51:14 +01:00
JordanTheToaster 10d2e5dd40 3rdparty: Update xbyak to v7.35.2 2026-03-11 16:51:14 +01:00
JordanTheToaster f357fad0ff 3rdparty: Update WIL to v1.0.260126.7 2026-03-11 16:51:14 +01:00
JordanTheToaster 1ae55e8615 Deps: Update libjpegturbo to 3.1.3 2026-03-11 16:51:14 +01:00
JordanTheToaster 012120c344 Deps: Update libpng to v1.6.55 2026-03-11 16:51:14 +01:00
lightningterror e3565eb924 GS/DX11: Further improve shader resource pre binding.
Currently pre binding doesn't work correctly/to it's full capacity as I forgot to update PSUnbindConflictingSRVs.
When doing a pre bind idea is to update local state, then if there are no conflicts to use that newly updated local state instead of unbinding the slot, this will avoid unnecessary re bindings.
2026-03-11 16:27:02 +01:00
KamFretoZ cd9fe1630b Hotkey: Add Reload Patch hotkey 2026-03-11 16:15:30 +01:00
KamFretoZ f5524bab1b Qt/Patch: Cleanup Unused headers and formatting 2026-03-11 16:15:30 +01:00
chaoticgd 471a7203a5 Qt: Disallow writing to EE SIF RX FIFO while hardcore mode is active 2026-03-11 16:01:11 +01:00
chaoticgd 456c062246 Qt: Don't call VMManager::WriteBytesToEESIORXFIFO from the UI thread 2026-03-11 16:01:11 +01:00
Ziemas 2c0bb98cac SPU: Speed up DMA 2026-03-11 15:56:49 +01:00
lightningterror bf4670c855 GS/GL: Clear texture binding when it's bound to RT or DS.
This is already done on DX11/12/VK, this is usually a leftover from a previous draw.
2026-03-11 15:42:58 +01:00
Mrlinkwii 6113f9bcb4 GameDB : fix Xenosaga entries 2026-03-11 12:44:47 +01:00
SternXD fe919d18b2 GSRunner: Fix gsrunner ImGui fonts and host stubs 2026-03-11 12:44:05 +01:00
PCSX2 Bot d0687dd631 [ci skip] Qt: Update Base Translation. 2026-03-11 12:43:28 +01:00
Ziemas 1bf53e6432 AudioStream: Remove manual volume vectorization
Surely the compiler will do this fine now that it's a simple loop.
2026-03-10 10:39:02 +01:00
Ziemas 58a4f1e5e9 SPU: Do DC filtering with float samples 2026-03-10 10:39:02 +01:00
Ziemas ea304becf6 AudioStream: Remove now rendundant copying 2026-03-10 10:39:02 +01:00
Ziemas b0a7d6994b AudioStream/GSCapture: Use float output 2026-03-10 10:39:02 +01:00
PCSX2 Bot bd522e2385 [ci skip] Qt: Update Base Translation. 2026-03-10 10:38:36 +01:00
chaoticgd 27e9accffa Patch: Check all the pointers in a chain for null values 2026-03-09 22:18:53 -04:00
chaoticgd 4f41366600 Patch: Properly skip past pointer write commands if pointer is null 2026-03-09 22:18:53 -04:00
chaoticgd d26701c004 Patch: Reset extended code state (e.g. skip counter) between groups 2026-03-09 22:18:53 -04:00
chaoticgd d7983d81e3 Patch: Use idempotent writes for extended codes 2026-03-09 22:18:53 -04:00
chaoticgd 2e122c3255 Patch: Add unit tests 2026-03-09 22:18:53 -04:00
chaoticgd eef1f837a2 Patch: Use the new MemoryInterface classes to apply patches 2026-03-09 22:18:53 -04:00
chaoticgd e52d8f70ba Misc: Add MemoryInterface classes 2026-03-09 22:18:53 -04:00
PCSX2 Bot d4cf5a998c [ci skip] PAD: Update to latest controller database. 2026-03-09 12:22:43 -04:00
Ziemas 608922dc41 IOP: Override memory size argument to IOPBOOT
This makes the extended IOP ram accessible on regular bootroms
2026-03-08 14:46:09 -04:00
Ziemas 438937ace3 Debugger: Fix IOP thread list mem size check 2026-03-08 14:46:09 -04:00
Ziemas 50605bd0e9 IOP JIT: Switch LUT to DynamicHeapArray 2026-03-08 14:46:09 -04:00
Ziemas c1d46b1866 IOP: TOOL config registers 2026-03-08 14:46:09 -04:00
Ziemas e47b32b2e6 Memory: Combine main and extra memory arrays
There doesn't seem to be any particular reason to not combine them into
one, less sketchy than accessing the extra array by going past the end
of the main one too.
2026-03-08 14:46:09 -04:00
Ziemas f0dc40ac15 USB: Use Ps2MemSize instead of sizeof 2026-03-08 14:46:09 -04:00
Ziemas 15a502cf36 IOP: Enable extension of RAM to devkit spec (8MB) 2026-03-08 14:46:09 -04:00
chaoticgd a1152f5313 Qt: Save cover downloader URLs 2026-03-07 17:51:20 -05:00
chaoticgd 68150c7448 Docs: Remove git rebase markup 2026-03-07 13:37:23 -05:00
chaoticgd 71fe1b809c CMake: Add option to disable position independent code 2026-03-07 13:36:47 -05:00
chaoticgd ec6901b93d CMake: Make sure that position independent code is enabled properly 2026-03-07 13:36:47 -05:00
lightningterror 3c7eb2ac88 GS: Add CAS texture copies counter info. 2026-03-07 15:48:35 +01:00
Ziemas baecf73f4b IopCounters: Cast to u64 to get full 64-bit mask 2026-03-07 09:31:05 -05:00
Ziemas 9a2561d9cf IOP: Switch to 64bit cycle counter
[SAVEVERSION+]
2026-03-07 09:31:05 -05:00
403 changed files with 19241 additions and 43571 deletions
+23
View File
@@ -0,0 +1,23 @@
name: 'Commit Message Check'
on:
pull_request_target:
types:
- opened
- edited
- reopened
- synchronize
jobs:
check-commit-message:
name: Check Commit Message
runs-on: ubuntu-latest
steps:
- name: Check for a commit prefix
uses: gsactions/commit-message-checker@16fa2d5de096ae0d35626443bcd24f1e756cafee
with:
accessToken: ${{ secrets.GITHUB_TOKEN }}
pattern: '^[A-Z0-9][A-Za-z0-9 \["\/\\]+:.+'
excludeTitle: true
excludeDescription: true
checkAllCommitMessages: true
error: 'Commit messages should be capitalized, start with a prefix, delimited by a colon. Example: "Debugger: Add a paste bytes option to the memory view"'
+21
View File
@@ -0,0 +1,21 @@
name: 🧹 Clean Up Old Caches
on:
schedule:
- cron: "0 0 * * *" # Every day at 12am UTC.
workflow_dispatch: # As well as manually.
jobs:
clean:
name: "Clean Up Caches"
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- name: Clean Caches
uses: PCSX2/cache-clean-action@v1.1.0
with:
items: '[{"key": " deps", "count": 4}, {"key": " ccache", "count": 1}, {"key": " flatpak", "count": 1}]'
token: ${{ secrets.GITHUB_TOKEN }}
branch: all
on_failure: error
+2 -6
View File
@@ -27,10 +27,6 @@ on:
required: false
type: boolean
default: false
detail:
required: false
type: string
default: ""
patchesUrl:
required: false
type: string
@@ -95,8 +91,8 @@ jobs:
uses: actions/cache@v5
with:
path: .ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ccache
- name: Install Packages
run: |
+24 -9
View File
@@ -13,6 +13,10 @@ on:
required: false
type: string
default: macos-26
arch:
required: false
type: string
default: x86-64
patchesUrl:
required: false
type: string
@@ -62,11 +66,15 @@ jobs:
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
cat ./pcsx2-qt/DefaultUpdaterChannel.h
- name: Use Xcode 26.0.1
run: sudo xcode-select -s /Applications/Xcode_26.0.1.app
- name: Use Xcode 26.2
run: sudo xcode-select -s /Applications/Xcode_26.2.app
- name: Install Metal Toolchain
run: xcodebuild -downloadComponent MetalToolchain
run: |
for i in {1..5}; do
if xcrun metal -v; then break; fi
xcodebuild -downloadComponent MetalToolchain
done
- name: Prepare Artifact Metadata
id: artifact-metadata
@@ -94,12 +102,12 @@ jobs:
uses: actions/cache@v5
with:
path: ~/deps
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
key: ${{ inputs.os }} ${{ inputs.arch }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: |
.github/workflows/scripts/macos/build-dependencies.sh "$HOME/deps"
.github/workflows/scripts/macos/build-dependencies${{ case(inputs.arch == 'x86-64', '', '-universal') }}.sh "$HOME/deps"
- name: Download patches
run: |
@@ -115,16 +123,16 @@ jobs:
uses: actions/cache@v5
with:
path: .ccache
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ccache
key: ${{ inputs.os }} ${{ inputs.arch }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.arch }} ccache
- name: Generate CMake Files
run: |
cmake -DCMAKE_PREFIX_PATH="$HOME/deps" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES="x86_64" \
-DCMAKE_OSX_ARCHITECTURES="${{ case(inputs.arch == 'x86-64', 'x86_64', inputs.arch) }}" \
-DDISABLE_ADVANCE_SIMD=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=${{ case(inputs.arch == 'x86-64', 'ON', 'OFF') }} \
-DUSE_LINKED_FFMPEG=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
@@ -147,6 +155,11 @@ jobs:
fi
done
- name: Build GSRunner
if: inputs.arch != 'x86-64'
working-directory: build
run: make -j$(getconf _NPROCESSORS_ONLN) pcsx2-gsrunner
- name: Run Tests
working-directory: build
run: make -j$(getconf _NPROCESSORS_ONLN) unittests
@@ -184,6 +197,7 @@ jobs:
app_store_connect_api_key_json_file: 'key.json'
- name: Zip Build Artifacts
if: inputs.arch == 'x86-64'
run: |
TAG="$(git tag --points-at HEAD)"
if [ -z "$TAG" ]; then
@@ -197,6 +211,7 @@ jobs:
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
- name: Upload Artifact
if: inputs.arch == 'x86-64'
uses: actions/upload-artifact@v7
with:
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
+9
View File
@@ -18,3 +18,12 @@ jobs:
artifactPrefixName: "PCSX2-macos-Qt"
sign_and_notarize: true # If we find that notarization takes a long time we should disable that on PR builds
secrets: inherit
build_macos_qt_arm:
name: "arm64"
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
uses: ./.github/workflows/macos_build.yml
with:
jobName: "MacOS arm64 Build"
artifactPrefixName: "PCSX2-macos-Qt-arm64"
arch: arm64
secrets: inherit
+15 -2
View File
@@ -68,7 +68,7 @@ jobs:
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
- name: Create a GitHub Release (Manual)
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
with:
body_path: ./release-notes.md
@@ -77,7 +77,7 @@ jobs:
tag_name: ${{ steps.tag_version.outputs.new_tag }}
- name: Create a GitHub Release (Push)
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
with:
body_path: ./release-notes.md
@@ -151,6 +151,19 @@ jobs:
sign_and_notarize: true
secrets: inherit
# We don't use the artifacts, but we need this for the cache it generates
build_macos_qt_arm:
if: github.repository == 'PCSX2/pcsx2'
needs:
- cut-release
name: "MacOS"
uses: ./.github/workflows/macos_build.yml
with:
jobName: "Generate arm64 Caches"
artifactPrefixName: "PCSX2-macos-Qt-arm64"
arch: arm64
secrets: inherit
# Upload the Artifacts
upload_artifacts:
if: github.repository == 'PCSX2/pcsx2'
@@ -1,16 +1,3 @@
diff --git a/CHANGES b/CHANGES
index 5d3dd16..587b612 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,7 @@ v2024.1
- Update dependencies
- Propagate test/install options to Glslang
-v2024.0
+v2024.0 2024-03-09
- Update dependencies
- Utilities:
- Use Python3 explicitly in utility scripts
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ffcb54b..7c1a6d8 100644
--- a/CMakeLists.txt
@@ -18,53 +18,54 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.2
QT=6.11.0
QTAPNG=1.3.0
FFMPEG=8.0
FREETYPE=2.14.1
HARFBUZZ=12.2.0
HARFBUZZ=13.0.0
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.2
LIBPNG=1.6.53
LIBJPEGTURBO=3.1.3
LIBPNG=1.6.55
LIBWEBP=1.6.0
NVENC=13.0.19.0
SDL=SDL3-3.4.2
SDL=SDL3-3.4.4
LZ4=1.10.0
VULKAN=1.4.328.1
ZSTD=1.5.7
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
mkdir -p deps-build
cd deps-build
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
391998eb432719df26a6a67d8efdc67f8bf2afdd76c1ee3381ebff4fe7527ee2 qtwayland-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
e710e6e760f92922b86e4dd68f6bbe94ef6510919519d1b0068e874b5ad84d37 qtwayland-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
207f96964dc9475b13c1f66565bf145d2658089d65b4cf786d351da2857fc269 harfbuzz-$HARFBUZZ.tar.gz
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
ef39a2e3f9a8a78296c40da701967dd1b0d0d6e267e483863ce70f8a03b4050c $SDL.tar.gz
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a libpng-$LIBPNG-apng.patch.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
c465aa56757e7746ac707f582b6e2d51546569a4a2488c1172fb543aa5fdfc2c vulkan-sdk-$VULKAN.tar.gz
@@ -72,43 +73,47 @@ eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$VULKAN.tar.gz" \
-O "https://github.com/FFmpeg/nv-codec-headers/releases/download/n$NVENC/nv-codec-headers-$NVENC.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE/libbacktrace-$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$VULKAN.tar.gz" \
-O "https://github.com/FFmpeg/nv-codec-headers/releases/download/n$NVENC/nv-codec-headers-$NVENC.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
if [ "$BUILD_FFMPEG" -ne 0 ]; then
echo "Installing vulkan headers..."
@@ -143,9 +148,9 @@ fi
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
unzip "$LIBBACKTRACE.zip"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR"
./configure --prefix="$INSTALLDIR" --with-pic
make
make install
cd ..
@@ -234,7 +239,7 @@ echo "Building SDL..."
rm -fr "$SDL"
tar xf "$SDL.tar.gz"
cd "$SDL"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_X11_XSCRNSAVER=OFF -DSDL_TESTS=OFF -G Ninja
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -DSDL_UNIX_CONSOLE_BUILD=ON -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
@@ -347,6 +352,15 @@ cmake --build build --parallel
ninja -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
@@ -24,6 +24,7 @@ LZ4=1.10.0
ZSTD=1.5.7
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
@@ -33,10 +34,10 @@ SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
grep . > SHASUMS <<EOF
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
@@ -49,30 +50,34 @@ c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE/libbacktrace-$LIBBACKTRACE.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
unzip "$LIBBACKTRACE.zip"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR"
make
@@ -150,7 +155,7 @@ echo "Building SDL..."
rm -fr "$SDL"
tar xf "$SDL.tar.gz"
cd "$SDL"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -DSDL_UNIX_CONSOLE_BUILD=ON -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
@@ -173,6 +178,15 @@ cmake --build build --parallel
ninja -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.4.2.tar.gz",
"sha256": "ef39a2e3f9a8a78296c40da701967dd1b0d0d6e267e483863ce70f8a03b4050c"
"url": "https://libsdl.org/release/SDL3-3.4.4.tar.gz",
"sha256": "ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864"
}
],
"cleanup": [
@@ -15,24 +15,24 @@
{
"type": "git",
"url": "https://github.com/google/shaderc.git",
"commit": "73743588fe9c39f2f1c780a087d94afac691a189"
"commit": "301b4ede53d59b68bf55f95bb26412d9233c8187"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/glslang/archive/7a47e2531cb334982b2a2dd8513dca0a3de4373d.tar.gz",
"sha256": "272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931",
"url": "https://github.com/KhronosGroup/glslang/archive/f0bd0257c308b9a26562c1a30c4748a0219cc951.tar.gz",
"sha256": "bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647",
"dest": "third_party/glslang"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/SPIRV-Headers/archive/b824a462d4256d720bebb40e78b9eb8f78bbb305.tar.gz",
"sha256": "c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c",
"url": "https://github.com/KhronosGroup/SPIRV-Headers/archive/04f10f650d514df88b76d25e83db360142c7b174.tar.gz",
"sha256": "1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded",
"dest": "third_party/spirv-headers"
},
{
"type": "archive",
"url": "https://github.com/KhronosGroup/SPIRV-Tools/archive/971a7b6e8d7740035bbff089bbbf9f42951ecfd5.tar.gz",
"sha256": "06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f",
"url": "https://github.com/KhronosGroup/SPIRV-Tools/archive/fbe4f3ad913c44fe8700545f8ffe35d1382b7093.tar.gz",
"sha256": "cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59",
"dest": "third_party/spirv-tools"
},
{
@@ -14,21 +14,21 @@
"sources": [
{
"type": "archive",
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.53/libpng-1.6.53.tar.xz",
"sha256": "1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4"
"url": "https://downloads.sourceforge.net/project/libpng/libpng16/1.6.55/libpng-1.6.55.tar.xz",
"sha256": "d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d"
},
{
"type": "file",
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.53-apng.patch.gz",
"dest-filename": "libpng-1.6.53-apng.patch.gz",
"sha256": "452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c"
"url": "https://download.sourceforge.net/libpng-apng/libpng-1.6.55-apng.patch.gz",
"dest-filename": "libpng-1.6.55-apng.patch.gz",
"sha256": "017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a"
},
{
"type": "shell",
"commands":
[
"gunzip -f libpng-1.6.53-apng.patch.gz",
"patch -p1 < \"libpng-1.6.53-apng.patch\""
"gunzip -f libpng-1.6.55-apng.patch.gz",
"patch -p1 < \"libpng-1.6.55-apng.patch\""
]
}
],
@@ -0,0 +1,23 @@
{
"name": "rapidyaml",
"buildsystem": "cmake-ninja",
"builddir": true,
"config-opts": [
"-DBUILD_SHARED_LIBS=ON"
],
"build-options": {
"strip": true
},
"sources": [
{
"type": "git",
"url": "https://github.com/biojppm/rapidyaml.git",
"tag": "v0.11.1",
"commit": "119b6042064d3828819e428e32e5a0f3035d5643"
}
],
"cleanup": [
"/include",
"/lib/cmake"
]
}
@@ -35,6 +35,7 @@
"modules/25-plutosvg.json",
"modules/26-libpng.json",
"modules/27-qtapng.json",
"modules/28-rapidyaml.json",
{
"name": "pcsx2",
"buildsystem": "cmake-ninja",
@@ -79,4 +80,3 @@
}
]
}
@@ -7,16 +7,21 @@ merge_binaries() {
ARMDIR=$2
echo "Merging ARM64 binaries from $ARMDIR into fat binaries at $X86DIR..."
IFS="
"
IFS=$'\n'
FILES=()
pushd "$X86DIR"
for X86BIN in $(find . -type f \( -name '*.dylib' -o -name '*.a' -o -perm +111 \)); do
if file "$X86DIR/$X86BIN" | grep "Mach-O.*x86_64" >/dev/null; then
ARMBIN="${ARMDIR}/${X86BIN}"
echo "Merge $ARMBIN to $X86BIN..."
lipo -create "$X86BIN" "$ARMBIN" -o "$X86BIN"
FILES+=("$X86BIN")
fi
done
# If the timestamps of all the files we touched aren't equal, make may recreate them on make install if one depends on another
# Minimize the chance of that by touching them all at once
touch "${FILES[@]}"
popd
}
@@ -38,27 +43,28 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.1
QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.1
HARFBUZZ=12.2.0
SDL=SDL3-3.4.2
HARFBUZZ=13.0.0
SDL=SDL3-3.4.4
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.53
LIBJPEGTURBO=3.1.2
LIBPNG=1.6.55
LIBJPEGTURBO=3.1.3
LIBWEBP=1.6.0
FFMPEG=8.0
MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
mkdir -p deps-build
cd deps-build
@@ -78,68 +84,72 @@ CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
ef39a2e3f9a8a78296c40da701967dd1b0d0d6e267e483863ce70f8a03b4050c $SDL.tar.gz
207f96964dc9475b13c1f66565bf145d2658089d65b4cf786d351da2857fc269 harfbuzz-$HARFBUZZ.tar.gz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a libpng-$LIBPNG-apng.patch.gz
075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c MoltenVK-$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -C - -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/v$MOLTENVK/MoltenVK-$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Installing SDL..."
rm -fr "$SDL"
tar xf "$SDL.tar.gz"
cd "$SDL"
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -DBUILD_SHARED_LIBS=ON
make -C build "-j$NPROCS"
make -C build install
cd ..
@@ -153,7 +163,7 @@ if [ "$BUILD_FFMPEG" -ne 0 ]; then
cd build
LDFLAGS="-dead_strip $LDFLAGS" CFLAGS="-Os $CFLAGS" CXXFLAGS="-Os $CXXFLAGS" \
../configure --prefix="$INSTALLDIR" \
--enable-cross-compile --arch=x86_64 --cc='clang -arch x86_64' --cxx='clang++ -arch x86_64' --disable-x86asm \
--enable-cross-compile --arch=x86_64 --cc='clang -arch x86_64' --cxx='clang++ -arch x86_64' \
--disable-all --disable-autodetect --disable-static --enable-shared \
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
--enable-audiotoolbox --enable-videotoolbox \
@@ -277,7 +287,7 @@ cd ..
# MoltenVK already builds universal binaries, nothing special to do here.
echo "Installing MoltenVK..."
rm -fr "MoltenVK-${MOLTENVK}"
tar xf "v$MOLTENVK.tar.gz"
tar xf "MoltenVK-$MOLTENVK.tar.gz"
cd "MoltenVK-${MOLTENVK}"
./fetchDependencies --macos
make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 MVK_CONFIG_USE_METAL_PRIVATE_API=1
@@ -420,6 +430,15 @@ make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build
make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Cleaning up..."
cd ..
rm -rf deps-build
@@ -20,27 +20,28 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.2
QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.1
HARFBUZZ=12.2.0
SDL=SDL3-3.4.2
HARFBUZZ=13.0.0
SDL=SDL3-3.4.4
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.53
LIBJPEGTURBO=3.1.2
LIBPNG=1.6.55
LIBJPEGTURBO=3.1.3
LIBWEBP=1.6.0
FFMPEG=8.0
MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
mkdir -p deps-build
cd deps-build
@@ -59,68 +60,72 @@ CMAKE_COMMON=(
-DCMAKE_INSTALL_NAME_DIR='$<INSTALL_PREFIX>/lib'
)
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
ef39a2e3f9a8a78296c40da701967dd1b0d0d6e267e483863ce70f8a03b4050c $SDL.tar.gz
207f96964dc9475b13c1f66565bf145d2658089d65b4cf786d351da2857fc269 harfbuzz-$HARFBUZZ.tar.gz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 libpng-$LIBPNG.tar.xz
d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a libpng-$LIBPNG-apng.patch.gz
075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
1b220e3eec1714f0451b0e3652979bd280edf10893f617837b88e6359a804ded shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Installing SDL..."
rm -fr "$SDL"
tar xf "$SDL.tar.gz"
cd "$SDL"
cmake -B build "${CMAKE_COMMON[@]}" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
cmake -B build "${CMAKE_COMMON[@]}" -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -DBUILD_SHARED_LIBS=ON
make -C build "-j$NPROCS"
make -C build install
cd ..
@@ -368,6 +373,15 @@ make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build
make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Cleaning up..."
cd ..
rm -rf deps-build
@@ -2,17 +2,24 @@
setlocal enabledelayedexpansion
echo Setting environment...
rem Favour VS2022 over VS2026 for now.
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" || goto error
) else (
echo Visual Studio 2022 not found.
goto error
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[18, 19)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" || goto error
) else (
echo Visual Studio not found.
goto error
)
)
) else (
echo Visual Studio 2022 not found.
echo Visual Studio not found.
goto error
)
@@ -47,58 +54,60 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set QT=6.10.2
set QTMINOR=6.10
set QT=6.11.0
set QTMINOR=6.11
set QTAPNG=1.3.0
set FREETYPE=2.14.1
set HARFBUZZ=12.2.0
set LIBJPEGTURBO=3.1.2
set LIBPNG=1653
set LIBPNGLONG=1.6.53
set SDL=SDL3-3.4.2
set HARFBUZZ=13.0.0
set LIBJPEGTURBO=3.1.3
set LIBPNG=1655
set LIBPNGLONG=1.6.55
set SDL=SDL3-3.4.4
set LZ4=1.10.0
set WEBP=1.6.0
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZLIB=1.3.2
set ZLIBSHORT=132
set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set SHADERC=2025.4
set SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
set SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
set SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set AGILITYSDK=1.618.5
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip a448a8abc3f9ae8eef19ef3ce247370957c1fada5d58a01b5e281e792f40fa61 || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1655.zip aa45ef52ff7a4e61f34af866b3254b0b243ddc42fe2adb823b0843d2a57c2e86 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 4954d436c95c42aa258d4eb3fb95f8ecc5d7a3dc411f0f41ac2692d34b9b9e9c || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6bd4fbb665f77899a488b381c5b6e9681fc57c60b669738f985fea714f3456c5 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile: "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 0027fc24f947c48dbded13ada7d280be221eb651644e23a8a476f0f1f0a079dd || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" fab72d1a38eacea52710d18edb95dfd75db894ad869675d07a1eb26827da9b15 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 4a118247386ffba9160113f146f2189ba5abe3995db357114d7112ede6bd3cd1 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 9a38cb3b14484f5038d78cd5df89404f2f5b389a6ad91f9f1df4ae71bb9490dc || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" a26383c836a84fab5b03aed5d98e8e27d6c0a9cdbc3b0f462ccfe0a11a3d91ea || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 00ecd73dcaaa956cf2221ce899ce096e9535ba20695483c5277adede462d1bde || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 65b23ace0ff0c64daf51f7741ebb6448899fa4aceefc72403e56f5b95607ca8e || goto error
if %DEBUG%==1 (
echo Building debug and release libraries...
@@ -198,7 +207,7 @@ echo Building SDL...
rmdir /S /Q "%SDL%"
%SEVENZIP% x "%SDL%.zip" || goto error
cd "%SDL%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
@@ -214,7 +223,7 @@ echo Building Qt base...
rmdir /S /Q "qtbase-everywhere-src-%QT%"
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
cd "qtbase-everywhere-src-%QT%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DQT_HOST_PATH="%X64INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake -B build %ARM64TOOLCHAIN% -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DQT_HOST_PATH="%X64INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON -DQT_FEATURE_windows_ioring=OFF %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
@@ -315,6 +324,15 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Building RapidYAML..."
rmdir /S /Q "rapidyaml-%RAPIDYAML%-src"
%SEVENZIP% x "rapidyaml-%RAPIDYAML%-src.zip" || goto error
cd "rapidyaml-%RAPIDYAML%-src" || goto error
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Unpacking Agility SDK
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
@@ -2,22 +2,32 @@
setlocal enabledelayedexpansion
echo Setting environment...
rem Favour VS2022 over VS2026 for now.
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvars64.bat" || goto error
) else (
echo Visual Studio 2022 not found.
goto error
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[18, 19)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvars64.bat" || goto error
) else (
echo Visual Studio not found.
goto error
)
)
) else (
echo Visual Studio 2022 not found.
echo Visual Studio not found.
goto error
)
set SEVENZIP="C:\Program Files\7-Zip\7z.exe"
set PATCH="C:\Program Files\Git\usr\bin\patch.exe"
set BASH="C:\Program Files\Git\usr\bin\bash.exe"
set "UNIX_TOOLS=C:\Program Files\Git\usr\bin\"
if defined DEBUG (
echo DEBUG=%DEBUG%
@@ -25,6 +35,12 @@ if defined DEBUG (
set DEBUG=1
)
if defined BUILD_FFMPEG (
echo BUILD_FFMPEG=%BUILD_FFMPEG%
) else (
set BUILD_FFMPEG=0
)
pushd %~dp0
set "SCRIPTDIR=%CD%"
cd ..\..\..\..
@@ -45,58 +61,80 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set QT=6.10.2
set QTMINOR=6.10
set QT=6.11.0
set QTMINOR=6.11
set QTAPNG=1.3.0
set FFMPEG=8.1
set MESON=1.10.2
set PKGCONF=2.5.1
set AMF=1.5.0
set LIBVPL=2.16.0
set NVENC=13.0.19.0
set LIBOPUS=1.6.1
set LIBSVTAV1=4.0.1
set LIBX264=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
set FREETYPE=2.14.1
set HARFBUZZ=12.2.0
set LIBJPEGTURBO=3.1.2
set LIBPNG=1653
set LIBPNGLONG=1.6.53
set SDL=SDL3-3.4.2
set HARFBUZZ=13.0.0
set LIBJPEGTURBO=3.1.3
set LIBPNG=1655
set LIBPNGLONG=1.6.55
set SDL=SDL3-3.4.4
set LZ4=1.10.0
set WEBP=1.6.0
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZLIB=1.3.2
set ZLIBSHORT=132
set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set SHADERC=2025.4
set SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
set SHADERC_SPIRVHEADERS=b824a462d4256d720bebb40e78b9eb8f78bbb305
set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
set SHADERC_SPIRVHEADERS=04f10f650d514df88b76d25e83db360142c7b174
set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set AGILITYSDK=1.619.0
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "ffmpeg-%FFMPEG%.tar.xz" "https://ffmpeg.org/releases/ffmpeg-%FFMPEG%.tar.xz" b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a || goto error
call :downloadfile "meson-%MESON%.tar.gz" "https://github.com/mesonbuild/meson/releases/download/%MESON%/meson-%MESON%.tar.gz" 7890287d911dd4ee1ebd0efb61ed0321bfcd87c725df923a837cf90c6508f96b || goto error
call :downloadfile "pkgconf-pkgconf-%PKGCONF%.zip" "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-%PKGCONF%.zip" c5b5f88a2ca2324dc5d857e35bb145e24290e326357ea94a86d47b8d7fa15477 || goto error
call :downloadfile "amf-headers-v%AMF%.tar.gz" "https://github.com/GPUOpen-LibrariesAndSDKs/AMF/releases/download/v%AMF%/AMF-headers-v%AMF%.tar.gz" d569647fa26f289affe81a206259fa92f819d06db1e80cc334559953e82a3f01 || goto error
call :downloadfile "libvpl-%LIBVPL%.zip" "https://github.com/intel/libvpl/archive/v%LIBVPL%.zip" 0b2ee8da8b9ef07ed4b52bf9ddee05008ec999b7c3c41944d7a9f804631c398e || goto error
call :downloadfile "nv-codec-headers-%NVENC%.tar.gz" "https://github.com/FFmpeg/nv-codec-headers/releases/download/n%NVENC%/nv-codec-headers-%NVENC%.tar.gz" 13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee || goto error
call :downloadfile "opus-%LIBOPUS%.tar.gz" "https://downloads.xiph.org/releases/opus/opus-%LIBOPUS%.tar.gz" 6ffcb593207be92584df15b32466ed64bbec99109f007c82205f0194572411a1 || goto error
call :downloadfile "SVT-AV1-v%LIBSVTAV1%.zip" "https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v%LIBSVTAV1%/SVT-AV1-v%LIBSVTAV1%.zip" bfafad9af17f87fff75e44ca9b2c10cdd83c576047c3e96229285a8a64c81afc || goto error
call :downloadfile "x264-%LIBX264%.zip" "https://code.videolan.org/videolan/x264/-/archive/%LIBX264%.zip" d95d059eff81cc565165cd058b66e208f0cc9874106a8fe94a811a66cf8a85a2 || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip a448a8abc3f9ae8eef19ef3ce247370957c1fada5d58a01b5e281e792f40fa61 || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1655.zip aa45ef52ff7a4e61f34af866b3254b0b243ddc42fe2adb823b0843d2a57c2e86 || goto error
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 4954d436c95c42aa258d4eb3fb95f8ecc5d7a3dc411f0f41ac2692d34b9b9e9c || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6bd4fbb665f77899a488b381c5b6e9681fc57c60b669738f985fea714f3456c5 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/KDDockWidgets/archive/v%KDDOCKWIDGETS%.zip" 47ddb48197872055f0adf8e90a7235f8a3b795ca1ee3a28ac2c504c673ae3806 || goto error
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" d5edab9a0c4d1b78ba6fe55b425eeef9fefba7d2a101e889d70fd21d481e6cb1 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" fab72d1a38eacea52710d18edb95dfd75db894ad869675d07a1eb26827da9b15 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 4a118247386ffba9160113f146f2189ba5abe3995db357114d7112ede6bd3cd1 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 9a38cb3b14484f5038d78cd5df89404f2f5b389a6ad91f9f1df4ae71bb9490dc || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" a26383c836a84fab5b03aed5d98e8e27d6c0a9cdbc3b0f462ccfe0a11a3d91ea || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" 00ecd73dcaaa956cf2221ce899ce096e9535ba20695483c5277adede462d1bde || goto error
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" 65b23ace0ff0c64daf51f7741ebb6448899fa4aceefc72403e56f5b95607ca8e || goto error
if %DEBUG%==1 (
echo Building debug and release libraries...
@@ -106,6 +144,139 @@ if %DEBUG%==1 (
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG" -DCMAKE_MODULE_LINKER_FLAGS_RELEASE="/DEBUG" -DCMAKE_SHARED_LINKER_FLAGS_MINSIZEREL="/DEBUG" -DCMAKE_MODULE_LINKER_FLAGS_MINSIZEREL="/DEBUG"
if %BUILD_FFMPEG%==1 (
if not "%INSTALLDIR%"=="%INSTALLDIR: =%" (
echo FFmpeg does not support building in paths with spaces.
goto error
)
where nasm /q
set FOUND_NASM=0
if !ERRORLEVEL!==0 (
set FOUND_NASM=1
)
echo "Installing AMF headers"
rmdir /S /Q "amf-headers-v%AMF%"
tar -xf "amf-headers-v%AMF%.tar.gz" || goto error
xcopy "%BUILDDIR%\amf-headers-v%AMF%\AMF" "%INSTALLDIR%\include\AMF\" /y /s || goto error
echo.
echo "Installing libvpl"
rmdir /S /Q "libvpl-%LIBVPL%"
%SEVENZIP% x "libvpl-%LIBVPL%.zip" || goto error
cd "libvpl-%LIBVPL%" || goto error
cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=OFF -DINSTALL_EXAMPLES=OFF -DINSTALL_LIB=OFF -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Installing libopus"
rmdir /S /Q "opus-%LIBOPUS%"
tar -xf "opus-%LIBOPUS%.tar.gz" || goto error
cd "opus-%LIBOPUS%" || goto error
cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=OFF -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Installing libsvtav1"
rmdir /S /Q "SVT-AV1-v%LIBSVTAV1%"
tar -xf "SVT-AV1-v%LIBSVTAV1%.zip" || goto error
cd "SVT-AV1-v%LIBSVTAV1%" || goto error
if !FOUND_NASM!==0 (
set LIBSTVAV1_NASM=-DCOMPILE_C_ONLY=ON
)
cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DBUILD_APPS=OFF -DSVT_AV1_LTO=ON !LIBSTVAV1_NASM! -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Extracting meson"
rmdir /S /Q "meson-%MESON%"
tar xf "meson-%MESON%.tar.gz" || goto error
set MASON_PY=python "%BUILDDIR%\meson-%MESON%\meson.py"
!MASON_PY! -v || goto error
echo.
rem Alternatively we could grab pkg-config-lite from chocolatey or WinGet.
echo "Installing pkgconf"
rmdir /S /Q "pkgconf-pkgconf-%PKGCONF%"
%SEVENZIP% x "pkgconf-pkgconf-%PKGCONF%.zip" || goto error
cd "pkgconf-pkgconf-%PKGCONF%" || goto error
!MASON_PY! setup --buildtype=release --prefix="%INSTALLDIR%" -Dtests=disabled build --backend=ninja || goto error
!MASON_PY! compile -C build || goto error
ninja -C build install || goto error
set PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
set PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
Set "PKG_CONFIG_PATH=%INSTALLDIR%\lib\pkgconfig"
cd .. || goto error
set "OLD_PATH=%PATH%"
set "PATH=%PATH%;%UNIX_TOOLS%"
echo "Installing nvenc headers..."
rmdir /S /Q "nv-codec-headers-%NVENC%"
tar xf "nv-codec-headers-%NVENC%.tar.gz" || goto error
make -C "nv-codec-headers-%NVENC%" PREFIX="%INSTALLDIR%" install || goto error
echo.
set CC=cl
set CXX=cl
echo "Installing libx264"
rmdir /S /Q "x264-%LIBX264%"
%SEVENZIP% x "x264-%LIBX264%.zip" || goto error
cd "x264-%LIBX264%" || goto error
if !FOUND_NASM!==0 (
set LIBX264_NASM=--disable-asm
)
%BASH% configure --prefix="%INSTALLDIR%" --disable-cli --enable-static --extra-cflags="-MD -w -Os -GL" !LIBX264_NASM! || goto error
make -j%NUMBER_OF_PROCESSORS% || goto error
make install || goto error
cd .. || goto error
echo.
echo "Installing FFmpeg..."
rmdir /S /Q "ffmpeg-%FFMPEG%"
tar xf "ffmpeg-%FFMPEG%.tar.xz" || goto error
cd "ffmpeg-%FFMPEG%"
%PATCH% -p1 < "%SCRIPTDIR%\ffmpeg-configure-escape.patch" || goto error
if not !FOUND_NASM!==1 (
rem MSVC LTO gives linker errors when building without nasm.
rem The following patches fixes that issue.
%PATCH% -p1 < "%SCRIPTDIR%\ffmpeg-no-nasm-fix-avc-air.patch" || goto error
%PATCH% -p1 < "%SCRIPTDIR%\ffmpeg-no-nasm-fix-swc-air.patch" || goto error
set FFMPEG_NASM=--disable-x86asm
)
rem FFmpeg's build seems to choke when extra-cflags contain `\`, so use `/` as the path separator.
set VULKAN_INCLUDE=%INSTALLDIR:\=/%/../3rdparty/vulkan/include
rem libvpl needs to have advapi32.lib & ole32.lib added as extra libs.
rem For some reason QSV requires the hevc parser on windows.
rem --enable-small removes the display names of codecs, so instead we specify optflag for minsize
%BASH% configure --prefix="%INSTALLDIR%" --disable-all --disable-autodetect --disable-static --enable-shared --disable-debug ^
--toolchain=msvc --extra-ldflags="-LTCG" --extra-libs="advapi32.lib ole32.lib" !FFMPEG_NASM! --pkg-config="%INSTALLDIR%\bin\pkgconf.exe" ^
--extra-cflags="-MD -GL -I!VULKAN_INCLUDE!" --extra-cxxflags="-MD -GL -I!VULKAN_INCLUDE!" --optflags="-O1" ^
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale ^
--enable-gpl --enable-libx264 --enable-libsvtav1 --enable-libopus --enable-vulkan --enable-ffnvcodec --enable-nvenc --enable-libvpl --enable-amf ^
--enable-d3d11va --enable-mediafoundation ^
--enable-encoder=ffv1,qtrle,libx264*,libsvtav1,aac,flac,libopus,pcm_s16be,pcm_s16le ^
--enable-encoder=h264_qsv,hevc_qsv,av1_qsv ^
--enable-encoder=h264_nvenc,hevc_nvenc,av1_nvenc ^
--enable-encoder=h264_amf,hevc_amf,av1_amf ^
--enable-encoder=h264_vulkan,hevc_vulkan,av1_vulkan ^
--enable-encoder=h264_mf,hevc_mf,av1_mf ^
--enable-parser=hevc ^
--enable-muxer=avi,matroska,mov,mp3,mp4,wav ^
--enable-protocol=file || goto error
make -j%NUMBER_OF_PROCESSORS% || goto error
make install || goto error
cd ..
echo.
set "PATH=!OLD_PATH!"
)
echo Building Zlib...
rmdir /S /Q "zlib-%ZLIB%"
%SEVENZIP% x "zlib%ZLIBSHORT%.zip" || goto error
@@ -195,7 +366,7 @@ echo Building SDL...
rmdir /S /Q "%SDL%"
%SEVENZIP% x "%SDL%.zip" || goto error
cd "%SDL%" || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_VIDEO=OFF -DSDL_POWER=OFF -DSDL_SENSOR=OFF -DSDL_DIALOG=OFF -DSDL_TRAY=OFF -DSDL_TEST_LIBRARY=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
@@ -211,7 +382,7 @@ echo Building Qt base...
rmdir /S /Q "qtbase-everywhere-src-%QT%"
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
cd "qtbase-everywhere-src-%QT%" || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON -DQT_FEATURE_windows_ioring=OFF %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
@@ -312,6 +483,15 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Building RapidYAML..."
rmdir /S /Q "rapidyaml-%RAPIDYAML%-src"
%SEVENZIP% x "rapidyaml-%RAPIDYAML%-src.zip" || goto error
cd "rapidyaml-%RAPIDYAML%-src" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Unpacking Agility SDK
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
@@ -0,0 +1,13 @@
diff --git a/configure b/configure
index 747cbe6f40..c8a029cf19 100755
--- a/configure
+++ b/configure
@@ -5190,7 +5190,7 @@ probe_cc(){
_DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); if (!match($$0, / /)) { print $$0 } }'\'' | xargs -r -d\\n -n1 wslpath -u | awk '\''BEGIN { printf "%s:", "$@" }; { sub(/\r/,""); printf " %s", $$0 }; END { print "" }'\'' > $(@:.o=.d)'
else
- _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)'
+ _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)'
fi
_DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs'
_cflags_speed="-O2"
@@ -0,0 +1,29 @@
diff --git a/libavcodec/x86/lpc_init.c b/libavcodec/x86/lpc_init.c
index f2fca53799..da2c5a526d 100644
--- a/libavcodec/x86/lpc_init.c
+++ b/libavcodec/x86/lpc_init.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "config.h"
#include "libavutil/attributes.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -112,9 +113,13 @@ av_cold void ff_lpc_init_x86(LPCContext *c)
c->lpc_compute_autocorr = lpc_compute_autocorr_sse2;
#endif
+#if HAVE_SSE2_EXTERNAL
if (EXTERNAL_SSE2(cpu_flags))
c->lpc_apply_welch_window = ff_lpc_apply_welch_window_sse2;
+#endif
+#if HAVE_AVX2_EXTERNAL
if (EXTERNAL_AVX2(cpu_flags))
c->lpc_apply_welch_window = ff_lpc_apply_welch_window_avx2;
+#endif
}
--
2.43.0.windows.1
@@ -0,0 +1,177 @@
diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c
index 48a73bd0b2..718b90ec81 100644
--- a/libswscale/x86/rgb2rgb.c
+++ b/libswscale/x86/rgb2rgb.c
@@ -2439,6 +2439,7 @@ av_cold void rgb2rgb_init_x86(void)
deinterleaveBytes = deinterleave_bytes_sse2;
}
#endif
+#if HAVE_SSE3_EXTERNAL
if (EXTERNAL_SSSE3(cpu_flags)) {
shuffle_bytes_0321 = ff_shuffle_bytes_0321_ssse3;
shuffle_bytes_2103 = ff_shuffle_bytes_2103_ssse3;
@@ -2450,6 +2451,7 @@ av_cold void rgb2rgb_init_x86(void)
shuffle_bytes_2130 = ff_shuffle_bytes_2130_ssse3;
shuffle_bytes_1203 = ff_shuffle_bytes_1203_ssse3;
}
+#endif
#if HAVE_AVX_EXTERNAL
if (EXTERNAL_AVX(cpu_flags)) {
deinterleaveBytes = deinterleave_bytes_avx;
diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index 8b6f9bd58a..33b9673779 100644
--- a/libswscale/x86/swscale.c
+++ b/libswscale/x86/swscale.c
@@ -473,6 +473,7 @@ RANGE_CONVERT_FUNCS_DECL(avx2, 16)
av_cold void ff_sws_init_range_convert_x86(SwsInternal *c)
{
+#if HAVE_X86ASM
int cpu_flags = av_get_cpu_flags();
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
if (c->dstBpc <= 14) {
@@ -485,6 +486,7 @@ av_cold void ff_sws_init_range_convert_x86(SwsInternal *c)
} else if (EXTERNAL_SSE4(cpu_flags) && c->dstBpc > 14) {
RANGE_CONVERT_FUNCS(sse4, 16);
}
+#endif
}
av_cold void ff_sws_init_swscale_x86(SwsInternal *c)
@@ -569,6 +571,7 @@ switch(c->dstBpc){ \
else ASSIGN_SCALE_FUNC2(hscalefn, X8, opt1, opt2); \
break; \
}
+#if HAVE_SSE2_EXTERNAL
if (EXTERNAL_SSE2(cpu_flags)) {
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse2, sse2);
ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, sse2, sse2);
@@ -607,6 +610,8 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_SSE3_EXTERNAL
if (EXTERNAL_SSSE3(cpu_flags)) {
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, ssse3, ssse3);
ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, ssse3, ssse3);
@@ -617,6 +622,8 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_SSE4_EXTERNAL
if (EXTERNAL_SSE4(cpu_flags)) {
/* Xto15 don't need special sse4 functions */
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse4, ssse3);
@@ -627,7 +634,9 @@ switch(c->dstBpc){ \
if (c->dstBpc == 16 && !isBE(c->opts.dst_format) && !(c->opts.flags & SWS_ACCURATE_RND))
c->yuv2plane1 = ff_yuv2plane1_16_sse4;
}
+#endif
+#if HAVE_AVX_EXTERNAL
if (EXTERNAL_AVX(cpu_flags)) {
ASSIGN_VSCALEX_FUNC(c->yuv2planeX, avx, ,
HAVE_ALIGNED_STACK || ARCH_X86_64);
@@ -657,6 +666,7 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
#if ARCH_X86_64
#define ASSIGN_AVX2_SCALE_FUNC(hscalefn, filtersize) \
@@ -666,6 +676,7 @@ switch(c->dstBpc){ \
break; \
}
+#if HAVE_AVX2_EXTERNAL
if (EXTERNAL_AVX2_FAST(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_SLOW_GATHER)) {
if ((c->srcBpc == 8) && (c->dstBpc <= 14)) {
ASSIGN_AVX2_SCALE_FUNC(c->hcScale, c->hChrFilterSize);
@@ -697,6 +708,7 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
#define INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(fmt, name, opt) \
@@ -756,6 +768,7 @@ switch(c->dstBpc){ \
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, opt)
+#if HAVE_SSE2_EXTERNAL
if (EXTERNAL_SSE2(cpu_flags)) {
switch (c->opts.src_format) {
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(AV_PIX_FMT_GBRAP, rgb, sse2);
@@ -770,7 +783,9 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_SSE4_EXTERNAL
if (EXTERNAL_SSE4(cpu_flags)) {
switch (c->opts.src_format) {
case AV_PIX_FMT_GBRAP:
@@ -785,7 +800,9 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_AVX2_EXTERNAL
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
switch (c->opts.src_format) {
INPUT_PLANER_RGB_YUVA_ALL_CASES(avx2)
@@ -793,6 +810,7 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
if(c->opts.flags & SWS_FULL_CHR_H_INT) {
@@ -825,6 +843,7 @@ switch(c->dstBpc){ \
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRPF32BE, gbrpf32be, opt) \
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAPF32BE, gbrapf32be, opt)
+#if HAVE_SSE2_EXTERNAL
if (EXTERNAL_SSE2(cpu_flags)) {
switch (c->opts.dst_format) {
YUV2ANYX_GBRAP_CASES(sse2)
@@ -832,7 +851,9 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_SSE4_EXTERNAL
if (EXTERNAL_SSE4(cpu_flags)) {
switch (c->opts.dst_format) {
YUV2ANYX_GBRAP_CASES(sse4)
@@ -840,7 +861,9 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
+#if HAVE_AVX2_EXTERNAL
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
switch (c->opts.dst_format) {
YUV2ANYX_GBRAP_CASES(avx2)
@@ -848,7 +871,8 @@ switch(c->dstBpc){ \
break;
}
}
+#endif
}
-#endif
+#endif /* ARCH_X86_64 */
}
--
2.43.0.windows.1
+12 -4
View File
@@ -105,7 +105,14 @@ jobs:
- name: Setup msbuild
if: inputs.configuration != 'CMake'
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@v3
- name: Locate vcvars
if: inputs.configuration == 'CMake'
shell: cmd
run: |
for /f "usebackq tokens=*" %%i in (`call vswhere -latest -property installationPath`) do set "VSINSTPATH=%%i"
echo VCVARSPATH=%VSINSTPATH%\VC\Auxiliary\Build\vcvars64.bat>>%GITHUB_ENV%
- name: Download patches
shell: cmd
@@ -124,6 +131,7 @@ jobs:
if: steps.cache-deps.outputs.cache-hit != 'true'
env:
DEBUG: 0
BUILD_FFMPEG: 1
run: .github/workflows/scripts/windows/build-dependencies.bat
- name: Generate CMake
@@ -131,14 +139,14 @@ jobs:
id: cmake
shell: cmd
run: |
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
cmake . -B build ${{ inputs.cmakeFlags }} "-DCMAKE_PREFIX_PATH=%cd%\deps" -DQT_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DDISABLE_ADVANCE_SIMD=ON -G Ninja
- name: Build PCSX2
shell: cmd
run: |
if "${{ inputs.configuration }}"=="CMake" (
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
cmake --build build --config Release || exit /b
cmake --install build --config Release || exit /b
) else (
@@ -151,7 +159,7 @@ jobs:
if: inputs.configuration == 'CMake'
shell: cmd
run: |
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
set PATH=%PATH%;%GITHUB_WORKSPACE%\bin
cmake --build build --config Release --target unittests
+9 -7
View File
@@ -155,15 +155,17 @@ executable(
This project can be built using [Bazel](https://bazel.build/install).
You can also use this library as a dependency to your Bazel project. Add to the `WORKSPACE` file:
You can also use this library as a dependency to your Bazel project. Add to your `MODULE.bazel` file:
```python
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
# fetch cpuinfo from Bazel Central Registry: https://registry.bazel.build/modules/cpuinfo
bazel_dep(name = "cpuinfo", version = "0.0.0-20250925-877328f")
git_repository(
name = "org_pytorch_cpuinfo",
branch = "master",
remote = "https://github.com/Vertexwahn/cpuinfo.git",
# Optional: Override it with some specific commit hash
git_override(
module_name = "cpuinfo",
commit = "<replace_with_commit_hash>"
remote = "https://github.com/pytorch/cpuinfo.git",
)
```
@@ -176,7 +178,7 @@ cc_binary(
# ...
],
deps = [
"@org_pytorch_cpuinfo//:cpuinfo",
"@cpuinfo",
],
)
```
+3 -3
View File
@@ -1,11 +1,11 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.18 FATAL_ERROR)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
PROJECT(googletest-download NONE)
INCLUDE(ExternalProject)
ExternalProject_Add(googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
URL_HASH SHA256=40d4ec942217dcc84a9ebe2a68584ada7d4a33a8ee958755763278ea1c5e18ff
URL https://github.com/google/googletest/archive/release-1.8.0.zip
URL_HASH SHA256=f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf
SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest"
BINARY_DIR "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest"
CONFIGURE_COMMAND ""
+23
View File
@@ -431,6 +431,8 @@ enum cpuinfo_uarch {
cpuinfo_uarch_zen4 = 0x0020010C,
/** AMD Zen 5 microarchitecture. */
cpuinfo_uarch_zen5 = 0x0020010D,
/** AMD Zen 6 microarchitecture. */
cpuinfo_uarch_zen6 = 0x0020010E,
/** NSC Geode and AMD Geode GX and LX. */
cpuinfo_uarch_geode = 0x00200200,
@@ -526,6 +528,15 @@ enum cpuinfo_uarch {
/** ARM Cortex-A725. */
cpuinfo_uarch_cortex_a725 = 0x00300574,
/** ARM Lumex-C1-Ultra. */
cpuinfo_uarch_lumex_c1_ultra = 0x00300600,
/** ARM Lumex-C1-Premium. */
cpuinfo_uarch_lumex_c1_premium = 0x00300601,
/** ARM Lumex-C1-Pro. */
cpuinfo_uarch_lumex_c1_pro = 0x00300602,
/** ARM Lumex-C1-Nano. */
cpuinfo_uarch_lumex_c1_nano = 0x00300603,
/** Qualcomm Scorpion. */
cpuinfo_uarch_scorpion = 0x00400100,
/** Qualcomm Krait. */
@@ -538,6 +549,8 @@ enum cpuinfo_uarch {
cpuinfo_uarch_saphira = 0x00400104,
/** Qualcomm Oryon. */
cpuinfo_uarch_oryon = 0x00400105,
/** Qualcomm Oryon V3. */
cpuinfo_uarch_oryon_v3 = 0x00400106,
/** Nvidia Denver. */
cpuinfo_uarch_denver = 0x00500100,
@@ -612,6 +625,16 @@ enum cpuinfo_uarch {
/** Apple A18 pro processor (little cores). */
cpuinfo_uarch_tahiti_sawtooth = 0x00700207,
/** Apple A19 processor (big cores). */
cpuinfo_uarch_tilos_everest = 0x00700208,
/** Apple A19 processor (little cores). */
cpuinfo_uarch_tilos_sawtooth = 0x00700209,
/** Apple M4 processor (big cores). */
cpuinfo_uarch_donan_everest = 0x00700308,
/** Apple M4 processor (little cores). */
cpuinfo_uarch_donan_sawtooth = 0x00700309,
/** Cavium ThunderX. */
cpuinfo_uarch_thunderx = 0x00800100,
/** Cavium ThunderX2 (originally Broadcom Vulkan). */
+3
View File
@@ -69,6 +69,7 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
* - Processors with Cortex-A77 cores
* - Processors with Cortex-A78 cores
* - Processors with Cortex-A510 cores
* - Processors with Cortex-A520 cores
* - Processors with Cortex-A710 cores
* - Processors with Cortex-A715 cores
* - Processors with Cortex-X1 cores
@@ -101,6 +102,7 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
case UINT32_C(0x4100D470): /* Cortex-A710 */
case UINT32_C(0x4100D480): /* Cortex-X2 */
case UINT32_C(0x4100D490): /* Neoverse N2 */
case UINT32_C(0x4100D4B0): /* Cortex-A78C */
case UINT32_C(0x4100D4D0): /* Cortex-A715 */
case UINT32_C(0x4100D4E0): /* Cortex-X3 */
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
@@ -162,6 +164,7 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
case UINT32_C(0x4100D470): /* Cortex-A710 */
case UINT32_C(0x4100D480): /* Cortex-X2 */
case UINT32_C(0x4100D490): /* Neoverse N2 */
case UINT32_C(0x4100D4B0): /* Cortex-A78C */
case UINT32_C(0x4100D4D0): /* Cortex-A715 */
case UINT32_C(0x4100D4E0): /* Cortex-X3 */
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
+8 -8
View File
@@ -1314,7 +1314,7 @@ static bool match_omap(const char* start, const char* end, struct cpuinfo_arm_ch
* ro.board.platform) to match.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
* @param[out] chipset - location where chipset information will be stored upon
* a successful match and decoding.
*
@@ -1607,7 +1607,7 @@ static bool match_and_parse_sunxi(
* @param end - end of the /proc/cpuinfo Hardware string to match.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
* @param[out] chipset - location where chipset information will be stored upon
* a successful match and decoding.
*
@@ -2456,7 +2456,7 @@ static const struct special_map_entry tegra_hardware_map_entries[] = {
* @param[in] platform - /proc/cpuinfo Hardware string.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
@@ -2857,7 +2857,7 @@ static const struct special_map_entry special_board_map_entries[] = {
* @param[in] platform - ro.product.board value.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
@@ -3162,7 +3162,7 @@ static const struct special_map_entry special_platform_map_entries[] = {
* @param[in] platform - ro.board.platform value.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
@@ -3499,7 +3499,7 @@ struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_chipname(
* @param[in,out] chipset - chipset name to fix.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*/
void cpuinfo_arm_fixup_chipset(
struct cpuinfo_arm_chipset chipset[restrict static 1],
@@ -4038,7 +4038,7 @@ static enum cpuinfo_arm_chipset_vendor disambiguate_chipset_vendor(
* described above.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
@@ -4291,7 +4291,7 @@ void cpuinfo_arm_fixup_raspberry_pi_chipset(
* @param[in] hardware - /proc/cpuinfo Hardware string.
* @param cores - number of cores in the chipset.
* @param max_cpu_freq_max - maximum of
* /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
* /sys/devices/system/cpu/cpu<number>/cpufreq/cpu_freq_max values.
*
* @returns Decoded chipset name. If chipset could not be decoded, the resulting
* structure would use `unknown` vendor and series identifiers.
+76 -67
View File
@@ -21,9 +21,11 @@
#ifndef CPUFAMILY_ARM_LIGHTNING_THUNDER
#define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504D2
#endif
// A14 / M1
#ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1B588BB3
#endif
// A15 / M2
#ifndef CPUFAMILY_ARM_AVALANCHE_BLIZZARD
#define CPUFAMILY_ARM_AVALANCHE_BLIZZARD 0xDA33D83D
#endif
@@ -66,6 +68,18 @@
#ifndef CPUFAMILY_ARM_BRAVA
#define CPUFAMILY_ARM_BRAVA 0x17d5b93a
#endif
// M5
#ifndef CPUFAMILY_ARM_HIDRA
#define CPUFAMILY_ARM_HIDRA 0x1d5a87e8
#endif
// A19
#ifndef CPUFAMILY_ARM_TILOS
#define CPUFAMILY_ARM_TILOS 0x01d7a72b
#endif
// A19 Pro
#ifndef CPUFAMILY_ARM_THERA
#define CPUFAMILY_ARM_THERA 0xab345f09
#endif
struct cpuinfo_arm_isa cpuinfo_isa = {
.aes = true,
@@ -118,37 +132,59 @@ static enum cpuinfo_uarch decode_uarch(uint32_t cpu_family, uint32_t core_index,
/* 2x Monsoon + 4x Mistral cores */
return core_index < 2 ? cpuinfo_uarch_monsoon : cpuinfo_uarch_mistral;
case CPUFAMILY_ARM_VORTEX_TEMPEST:
/* Hexa-core: 2x Vortex + 4x Tempest; Octa-core: 4x
* Cortex + 4x Tempest */
/* Hexa-core: 2x Vortex + 4x Tempest; */
/* Octa-core: 4x Cortex + 4x Tempest */
return core_index + 4 < core_count ? cpuinfo_uarch_vortex : cpuinfo_uarch_tempest;
case CPUFAMILY_ARM_LIGHTNING_THUNDER:
/* Hexa-core: 2x Lightning + 4x Thunder; Octa-core
* (presumed): 4x Lightning + 4x Thunder */
/* Hexa-core: 2x Lightning + 4x Thunder; */
/* Octa-core: 4x Lightning + 4x Thunder */
return core_index + 4 < core_count ? cpuinfo_uarch_lightning : cpuinfo_uarch_thunder;
case CPUFAMILY_ARM_FIRESTORM_ICESTORM:
/* Hexa-core: 2x Firestorm + 4x Icestorm; Octa-core: 4x
* Firestorm + 4x Icestorm */
/* Hexa-core: 2x Firestorm + 4x Icestorm; */
/* Octa-core: 4x Firestorm + 4x Icestorm */
return core_index + 4 < core_count ? cpuinfo_uarch_firestorm : cpuinfo_uarch_icestorm;
case CPUFAMILY_ARM_AVALANCHE_BLIZZARD:
/* Hexa-core: 2x Avalanche + 4x Blizzard */
return core_index + 4 < core_count ? cpuinfo_uarch_avalanche : cpuinfo_uarch_blizzard;
case CPUFAMILY_ARM_EVEREST_SAWTOOTH:
/* Hexa-core: 2x Avalanche + 4x Blizzard */
/* Hexa-core: 2x Everest + 4x Sawtooth */
return core_index + 4 < core_count ? cpuinfo_uarch_everest : cpuinfo_uarch_sawtooth;
return core_index + 4 < core_count ? cpuinfo_uarch_avalanche : cpuinfo_uarch_blizzard;
case CPUFAMILY_ARM_IBIZA: /* M3 */
/* 8-core: 4x Coll Everest v2 + 4x Coll Sawtooth v2*/
case CPUFAMILY_ARM_PALMA: /* M3 Max */
/* 14-core: 10x Coll Everest v2 + 4x Coll Sawtooth v2*/
case CPUFAMILY_ARM_COLL:
/* Hexa-core: 2x Avalanche + 4x Blizzard */
/* Hexa-core: 2x Coll Everest v2 + 4x Coll Sawtooth v2 */
return core_index + 4 < core_count ? cpuinfo_uarch_coll_everest : cpuinfo_uarch_coll_sawtooth;
case CPUFAMILY_ARM_LOBOS: /* M3 Pro */
/* 12-core: 6x Coll Everest v2 + 6x Coll Sawtooth v2v2 */
return core_index + 6 < core_count ? cpuinfo_uarch_coll_everest : cpuinfo_uarch_coll_sawtooth;
case CPUFAMILY_ARM_TUPAI:
/* Hexa-core: 2x Avalanche + 4x Blizzard */
/* Hexa-core: 2x Tupai Everest v3 + 4x Tupai Sawtooth v3 */
return core_index + 4 < core_count ? cpuinfo_uarch_tupai_everest : cpuinfo_uarch_tupai_sawtooth;
case CPUFAMILY_ARM_TAHITI:
/* Hexa-core: 2x Avalanche + 4x Blizzard */
/* Hexa-core: 2x Tahiti Everest + 4x Tahiti Sawtooth */
return core_index + 4 < core_count ? cpuinfo_uarch_tahiti_everest
: cpuinfo_uarch_tahiti_sawtooth;
case CPUFAMILY_ARM_DONAN: /* M4 */
/* 10-core: 4x Donan Everest v3 + 6x Donan Sawtooth v3 */
return core_index + 6 < core_count ? cpuinfo_uarch_donan_everest : cpuinfo_uarch_donan_sawtooth;
case CPUFAMILY_ARM_BRAVA: /* M4 Pro */
/* 14-core: 10x Donan Everest v3 + 4x Donan Sawtooth v3 */
return core_index + 4 < core_count ? cpuinfo_uarch_donan_everest : cpuinfo_uarch_donan_sawtooth;
case CPUFAMILY_ARM_TILOS: /* A19 */
case CPUFAMILY_ARM_THERA: /* A19 Pro */
/* Hexa-core: 2x Tilos Everest v4 + 4x Tilos Sawtooth v4 */
return core_index + 4 < core_count ? cpuinfo_uarch_tilos_everest : cpuinfo_uarch_tilos_sawtooth;
case CPUFAMILY_ARM_HIDRA: /* M5 */
/* 10-core: 4x Tilos Everest v4 + 6x Tilos Sawtooth v4 */
return core_index + 6 < core_count ? cpuinfo_uarch_tilos_everest : cpuinfo_uarch_tilos_sawtooth;
default:
/* Use hw.cpusubtype for detection */
break;
@@ -361,10 +397,8 @@ void cpuinfo_arm_mach_init(void) {
* possible. Otherwise, fallback to hardcoded set of CPUs with known
* support.
*/
const uint32_t has_feat_lse = get_sys_info_by_name("hw.optional.arm.FEAT_LSE");
if (has_feat_lse != 0) {
cpuinfo_isa.atomics = true;
} else {
cpuinfo_isa.atomics = get_sys_info_by_name("hw.optional.arm.FEAT_LSE") != 0;
if (!cpuinfo_isa.atomics) {
// Mandatory in ARMv8.1-A, list only cores released before iOS
// 15 / macOS 12
switch (cpu_family) {
@@ -376,10 +410,8 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_rdm = get_sys_info_by_name("hw.optional.arm.FEAT_RDM");
if (has_feat_rdm != 0) {
cpuinfo_isa.rdm = true;
} else {
cpuinfo_isa.rdm = get_sys_info_by_name("hw.optional.arm.FEAT_RDM") != 0;
if (!cpuinfo_isa.rdm) {
// Optional in ARMv8.2-A (implemented in Apple cores),
// list only cores released before iOS 15 / macOS 12
switch (cpu_family) {
@@ -391,10 +423,8 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_fp16 = get_sys_info_by_name("hw.optional.arm.FEAT_FP16");
if (has_feat_fp16 != 0) {
cpuinfo_isa.fp16arith = true;
} else {
cpuinfo_isa.fp16arith = get_sys_info_by_name("hw.optional.arm.FEAT_FP16") != 0;
if (!cpuinfo_isa.fp16arith) {
// Optional in ARMv8.2-A (implemented in Apple cores),
// list only cores released before iOS 15 / macOS 12
switch (cpu_family) {
@@ -406,15 +436,11 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_fhm = get_sys_info_by_name("hw.optional.arm.FEAT_FHM");
if (has_feat_fhm != 0) {
cpuinfo_isa.fhm = true;
} else {
cpuinfo_isa.fhm = get_sys_info_by_name("hw.optional.arm.FEAT_FHM") != 0;
if (!cpuinfo_isa.fhm) {
// Prior to iOS 15, use 'hw.optional.armv8_2_fhm'
const uint32_t has_feat_fhm_legacy = get_sys_info_by_name("hw.optional.armv8_2_fhm");
if (has_feat_fhm_legacy != 0) {
cpuinfo_isa.fhm = true;
} else {
cpuinfo_isa.fhm = get_sys_info_by_name("hw.optional.armv8_2_fhm") != 0;
if (!cpuinfo_isa.fhm) {
// Mandatory in ARMv8.4-A when FP16 arithmetics is
// implemented, list only cores released before iOS 15 /
// macOS 12
@@ -426,17 +452,10 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_bf16 = get_sys_info_by_name("hw.optional.arm.FEAT_BF16");
if (has_feat_bf16 != 0) {
cpuinfo_isa.bf16 = true;
}
const uint32_t has_feat_fcma = get_sys_info_by_name("hw.optional.arm.FEAT_FCMA");
if (has_feat_fcma != 0) {
cpuinfo_isa.fcma = true;
} else {
// Mandatory in ARMv8.3-A, list only cores released before iOS
// 15 / macOS 12
cpuinfo_isa.bf16 = get_sys_info_by_name("hw.optional.arm.FEAT_BF16") != 0;
cpuinfo_isa.fcma = get_sys_info_by_name("hw.optional.arm.FEAT_FCMA") != 0;
if (!cpuinfo_isa.fcma) {
// Mandatory in ARMv8.3-A, list only cores released before iOS 15 / macOS 12
switch (cpu_family) {
case CPUFAMILY_ARM_LIGHTNING_THUNDER:
case CPUFAMILY_ARM_FIRESTORM_ICESTORM:
@@ -444,12 +463,9 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_jscvt = get_sys_info_by_name("hw.optional.arm.FEAT_JSCVT");
if (has_feat_jscvt != 0) {
cpuinfo_isa.jscvt = true;
} else {
// Mandatory in ARMv8.3-A, list only cores released before iOS
// 15 / macOS 12
cpuinfo_isa.jscvt = get_sys_info_by_name("hw.optional.arm.FEAT_JSCVT") != 0;
if (!cpuinfo_isa.jscvt) {
// Mandatory in ARMv8.3-A, list only cores released before iOS 15 / macOS 12
switch (cpu_family) {
case CPUFAMILY_ARM_LIGHTNING_THUNDER:
case CPUFAMILY_ARM_FIRESTORM_ICESTORM:
@@ -457,12 +473,9 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_dotprod = get_sys_info_by_name("hw.optional.arm.FEAT_DotProd");
if (has_feat_dotprod != 0) {
cpuinfo_isa.dot = true;
} else {
// Mandatory in ARMv8.4-A, list only cores released before iOS
// 15 / macOS 12
cpuinfo_isa.dot = get_sys_info_by_name("hw.optional.arm.FEAT_DotProd") != 0;
if (!cpuinfo_isa.dot) {
// Mandatory in ARMv8.4-A, list only cores released before iOS 15 / macOS 12
switch (cpu_family) {
case CPUFAMILY_ARM_LIGHTNING_THUNDER:
case CPUFAMILY_ARM_FIRESTORM_ICESTORM:
@@ -470,20 +483,16 @@ void cpuinfo_arm_mach_init(void) {
}
}
const uint32_t has_feat_i8mm = get_sys_info_by_name("hw.optional.arm.FEAT_I8MM");
if (has_feat_i8mm != 0) {
cpuinfo_isa.i8mm = true;
}
cpuinfo_isa.i8mm = get_sys_info_by_name("hw.optional.arm.FEAT_I8MM") != 0;
cpuinfo_isa.sme = get_sys_info_by_name("hw.optional.arm.FEAT_SME") != 0;
cpuinfo_isa.sme2 = get_sys_info_by_name("hw.optional.arm.FEAT_SME2") != 0;
cpuinfo_isa.sme2p1 = get_sys_info_by_name("hw.optional.arm.FEAT_SME2p1") != 0;
cpuinfo_isa.sme_i16i32 = get_sys_info_by_name("hw.optional.arm.SME_I16I32") != 0;
cpuinfo_isa.sme_bi32i32 = get_sys_info_by_name("hw.optional.arm.SME_BI32I32") != 0;
cpuinfo_isa.sme_b16b16 = get_sys_info_by_name("hw.optional.arm.FEAT_SME_B16B16") != 0;
cpuinfo_isa.sme_f16f16 = get_sys_info_by_name("hw.optional.arm.FEAT_SME_F16F16") != 0;
const uint32_t has_feat_sme = get_sys_info_by_name("hw.optional.arm.FEAT_SME");
if (has_feat_sme != 0) {
cpuinfo_isa.sme = true;
}
const uint32_t has_feat_sme2 = get_sys_info_by_name("hw.optional.arm.FEAT_SME2");
if (has_feat_sme2 != 0) {
cpuinfo_isa.sme2 = true;
}
cpuinfo_isa.smelen = get_sys_info_by_name("hw.optional.arm.sme_max_svl_b");
uint32_t num_clusters = 1;
for (uint32_t i = 0; i < mach_topology.cores; i++) {
+4
View File
@@ -192,6 +192,7 @@ inline static uint32_t midr_score_core(uint32_t midr) {
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
case UINT32_C(0x4100D410): /* Cortex-A78 */
case UINT32_C(0x4100D4B0): /* Cortex-A78C */
case UINT32_C(0x4100D470): /* Cortex-A710 */
case UINT32_C(0x4100D4D0): /* Cortex-A715 */
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
@@ -220,6 +221,9 @@ inline static uint32_t midr_score_core(uint32_t midr) {
case UINT32_C(0x4100D030): /* Cortex-A53 */
case UINT32_C(0x4100D050): /* Cortex-A55 */
case UINT32_C(0x4100D460): /* Cortex-A510 */
#if CPUINFO_ARCH_ARM64
case UINT32_C(0x4100D800): /* Cortex-A520 */
#endif /* CPUINFO_ARCH_ARM64 */
/* Cortex-A53 is usually in LITTLE role, but can be in
* big role w.r.t. Cortex-A35 */
return 2;
+19
View File
@@ -94,6 +94,7 @@ void cpuinfo_arm_decode_vendor_uarch(
*uarch = cpuinfo_uarch_neoverse_v1;
break;
case 0xD41: /* Cortex-A78 */
case 0xD4B: /* Cortex-A78C */
*uarch = cpuinfo_uarch_cortex_a78;
break;
case 0xD44: /* Cortex-X1 */
@@ -125,6 +126,9 @@ void cpuinfo_arm_decode_vendor_uarch(
case 0xD4F: /* Neoverse V2 */
*uarch = cpuinfo_uarch_neoverse_v2;
break;
case 0xD80: /* Cortex-A520 */
*uarch = cpuinfo_uarch_cortex_a520;
break;
case 0xD81: /* Cortex-A720 */
*uarch = cpuinfo_uarch_cortex_a720;
break;
@@ -137,6 +141,18 @@ void cpuinfo_arm_decode_vendor_uarch(
case 0xD87: /* Cortex-A725 */
*uarch = cpuinfo_uarch_cortex_a725;
break;
case 0xD8C:
*uarch = cpuinfo_uarch_lumex_c1_ultra;
break;
case 0xD90:
*uarch = cpuinfo_uarch_lumex_c1_premium;
break;
case 0xD8B:
*uarch = cpuinfo_uarch_lumex_c1_pro;
break;
case 0xD8A:
*uarch = cpuinfo_uarch_lumex_c1_nano;
break;
default:
switch (midr_get_part(midr) >> 8) {
#if CPUINFO_ARCH_ARM
@@ -347,6 +363,9 @@ void cpuinfo_arm_decode_vendor_uarch(
case 0x001:
*uarch = cpuinfo_uarch_oryon;
break;
case 0x002:
*uarch = cpuinfo_uarch_oryon_v3;
break;
case 0xC00:
*uarch = cpuinfo_uarch_falkor;
break;
+8
View File
@@ -249,6 +249,14 @@ static void set_cpuinfo_isa_fields(void) {
// guarantee that, but it holds in practice.
cpuinfo_isa.rdm = dotprod;
// PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE may not be available in older
// Windows versions. If fp16arith was not detected with
// IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE), fall
// back to using the value of dotprod.
if (!cpuinfo_isa.fp16arith) {
cpuinfo_isa.fp16arith = dotprod;
}
/* Windows API reports all or nothing for cryptographic instructions. */
const bool crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0;
cpuinfo_isa.aes = crypto;
+1 -1
View File
@@ -231,7 +231,7 @@ uint32_t cpuinfo_linux_get_processor_min_frequency(uint32_t processor) {
}
bool cpuinfo_linux_get_processor_core_id(uint32_t processor, uint32_t core_id_ptr[restrict static 1]) {
char core_id_filename[PACKAGE_ID_FILENAME_SIZE];
char core_id_filename[CORE_ID_FILENAME_SIZE];
const int chars_formatted =
snprintf(core_id_filename, CORE_ID_FILENAME_SIZE, CORE_ID_FILENAME_FORMAT, processor);
if ((unsigned int)chars_formatted >= CORE_ID_FILENAME_SIZE) {
+2
View File
@@ -612,6 +612,8 @@ uint32_t cpuinfo_x86_normalize_brand_string(const char raw_name[48], char normal
break;
case '@':
parser_state.frequency_separator = char_ptr;
*char_ptr = ' ';
break;
case '\0':
case '\t':
*char_ptr = ' ';
+15 -1
View File
@@ -402,7 +402,21 @@ enum cpuinfo_uarch cpuinfo_x86_decode_uarch(
}
break;
case 0x1a:
return cpuinfo_uarch_zen5;
switch (model_info->extended_model) {
case 0x0: // model 00h..2Fh
case 0x1:
case 0x2:
case 0x4: // model 40h..4Fh
return cpuinfo_uarch_zen5;
case 0x5: // model 50h..5Fh
case 0x8: // model 80h..AFh
case 0x9:
case 0xA:
case 0xC: // model C0h..CFh
return cpuinfo_uarch_zen6;
}
break;
}
break;
case cpuinfo_vendor_hygon:
+8 -27
View File
@@ -1,38 +1,19 @@
# We need to use a custom CMakeLists for GoogleTest, because we can't compile with exceptions on.
add_library(gtest
googletest/src/gtest.cc
googletest/src/gtest-assertion-result.cc
googletest/src/gtest-death-test.cc
googletest/src/gtest-filepath.cc
googletest/src/gtest-matchers.cc
googletest/src/gtest-port.cc
googletest/src/gtest-printers.cc
googletest/src/gtest-test-part.cc
googletest/src/gtest-typed-test.cc
googletest/src/gtest-all.cc
googlemock/src/gmock-all.cc
googlemock/src/gmock_main.cc
)
target_include_directories(gtest PUBLIC
googletest/include
googlemock/include
)
target_include_directories(gtest PRIVATE
googletest
googletest/include
)
target_include_directories(gtest INTERFACE
googletest/include
googlemock
)
target_link_libraries(gtest Threads::Threads)
set_property(TARGET gtest PROPERTY CXX_STANDARD 17)
set_property(TARGET gtest PROPERTY CXX_STANDARD_REQUIRED ON)
add_library(gtest_main
googletest/src/gtest_main.cc
)
target_include_directories(gtest_main PRIVATE
googletest
googletest/include
)
target_include_directories(gtest_main INTERFACE
googletest/include
)
target_link_libraries(gtest_main Threads::Threads)
set_property(TARGET gtest_main PROPERTY CXX_STANDARD 17)
set_property(TARGET gtest_main PROPERTY CXX_STANDARD_REQUIRED ON)
+66 -59
View File
@@ -50,7 +50,6 @@
#include <libchdr/huffman.h>
#include <zstd.h>
#include "LzmaEnc.h"
#include "LzmaDec.h"
#if defined(__PS3__) || defined(__PSL1GHT__)
#define __MACTYPES__
@@ -466,28 +465,6 @@ static void lzma_allocator_free(void* p )
}
}
/*-------------------------------------------------
* lzma_allocator_free_unused
* free unused buffers only
*-------------------------------------------------
*/
static void lzma_allocator_free_unused(lzma_allocator *codec)
{
int i;
for (i = 0; i < MAX_LZMA_ALLOCS; i++)
{
uint32_t *ptr = codec->allocptr[i];
if (ptr && (*ptr & 1) == 0)
{
free(codec->allocptr[i]);
codec->allocptr[i] = NULL;
codec->allocptr2[i] = NULL;
}
}
}
/*-------------------------------------------------
* lzma_fast_alloc - fast malloc for lzma, which
* allocates and frees memory frequently
@@ -583,6 +560,61 @@ static void lzma_fast_free(void *p, void *address)
***************************************************************************
*/
/*-------------------------------------------------
* lzma_compute_aligned_dictionary_size
* Based on LzmaEncProps_Normalize, LzmaEnc_SetProps, LzmaEnc_WriteProperties.
*-------------------------------------------------
*/
static uint32_t lzma_compute_aligned_dictionary_size(uint32_t hunkbytes)
{
const unsigned int level = 9;
const uint32_t reduceSize = hunkbytes;
uint32_t dictSize, alignedDictSize;
/* LzmaEncProps_Normalize */
dictSize = level <= 4 ?
(uint32_t)1 << (level * 2 + 16) :
level <= sizeof(size_t) / 2 + 4 ?
(uint32_t)1 << (level + 20) :
(uint32_t)1 << (sizeof(size_t) / 2 + 24);
if (dictSize > reduceSize)
{
const uint32_t kReduceMin = (uint32_t)1 << 12;
const uint32_t max = MIN(kReduceMin, reduceSize);
dictSize = MAX(max, dictSize);
}
/* LzmaEnc_SetProps */
dictSize = MIN((uint32_t)15 << 28, dictSize); /* kLzmaMaxHistorySize */
/* LzmaEnc_WriteProperties */
/* we write aligned dictionary value to properties for lzma decoder */
if (dictSize >= ((uint32_t)1 << 21))
{
const uint32_t kDictMask = ((uint32_t)1 << 20) - 1;
alignedDictSize = (dictSize + kDictMask) & ~kDictMask;
alignedDictSize = MIN(dictSize, alignedDictSize);
}
else
{
unsigned int i = 11 * 2;
do
{
alignedDictSize = (uint32_t)(2 + (i & 1)) << (i >> 1);
i++;
}
while (alignedDictSize < dictSize);
}
return alignedDictSize;
}
/*-------------------------------------------------
* lzma_codec_init - constructor
*-------------------------------------------------
@@ -590,47 +622,22 @@ static void lzma_fast_free(void *p, void *address)
static chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
{
CLzmaEncHandle enc;
CLzmaEncProps encoder_props;
Byte decoder_props[LZMA_PROPS_SIZE];
SizeT props_size;
lzma_allocator* alloc;
lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
lzma_allocator* alloc = &lzma_codec->allocator;
const uint32_t alignedDictSize = lzma_compute_aligned_dictionary_size(hunkbytes);
unsigned int i;
Byte decoder_props[LZMA_PROPS_SIZE];
decoder_props[0] = 93;
for (i = 0; i < LZMA_PROPS_SIZE - 1; ++i)
decoder_props[1 + i] = (alignedDictSize >> (8 * i)) & 0xFF;
lzma_allocator_init(alloc);
/* construct the decoder */
LzmaDec_Construct(&lzma_codec->decoder);
/* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
* This code assumes that the current version of the encoder imposes the same requirements on the
* decoder as the encoder used to produce the file. This is not necessarily true. The format
* needs to be changed so the encoder properties are written to the file.
* configure the properties like the compressor did */
LzmaEncProps_Init(&encoder_props);
encoder_props.level = 9;
encoder_props.reduceSize = hunkbytes;
LzmaEncProps_Normalize(&encoder_props);
/* convert to decoder properties */
alloc = &lzma_codec->allocator;
lzma_allocator_init(alloc);
enc = LzmaEnc_Create((ISzAlloc*)alloc);
if (!enc)
return CHDERR_DECOMPRESSION_ERROR;
if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
{
LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
return CHDERR_DECOMPRESSION_ERROR;
}
props_size = sizeof(decoder_props);
if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
{
LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
return CHDERR_DECOMPRESSION_ERROR;
}
LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
lzma_allocator_free_unused(alloc);
/* do memory allocations */
if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
return CHDERR_DECOMPRESSION_ERROR;
+14 -1
View File
@@ -1,7 +1,7 @@
#ifndef RA_CONSOLES_H
#define RA_CONSOLES_H
/* this list should match the list in rcheevos/include/rconsoles.h */
/* this list should match the list in rcheevos/include/rc_consoles.h */
enum ConsoleID
{
UnknownConsoleID = 0,
@@ -77,6 +77,19 @@ enum ConsoleID
Zeebo = 70,
Arduboy = 71,
WASM4 = 72,
Arcadia2001 = 73,
IntertonVC4000 = 74,
ElektorTVGamesComputer = 75,
PCEngineCD = 76,
JaguarCD = 77,
DSi = 78,
TI83 = 79,
Uzebox = 80,
FamicomDiskSystem = 81,
Hubs = 100,
Events = 101,
Standalone = 102,
NumConsoleIDs
};
+213 -61
View File
@@ -5,10 +5,23 @@
#include <stdexcept>
#include <string>
#ifndef RA_NOPROGRESS
#include <ShlObj.h>
#else
#define IProgressDialog void
#endif
#ifndef CCONV
#define CCONV __cdecl
#endif
#if defined(_M_X64) || defined(__amd64__)
#define RA_X64
#define RA_INT_DLL L"RA_Integration-x64.dll"
#else
#define RA_INT_DLL L"RA_Integration.dll"
#endif
// Initialization
static const char* (CCONV* _RA_IntegrationVersion)() = nullptr;
static const char* (CCONV* _RA_HostName)() = nullptr;
@@ -270,10 +283,58 @@ void RA_DisableHardcore()
_RA_WarnDisableHardcore(nullptr);
}
static size_t DownloadToFile(char* pData, size_t nDataSize, void* pUserData)
#ifndef RA_NOPROGRESS
static void FormatByteSize(DWORD nSize, wchar_t* sBuffer, size_t nBufferSize)
{
if (nSize < 1024)
{
swprintf_s(sBuffer, nBufferSize, L"%u bytes", nSize);
return;
}
float fSize = nSize;
fSize /= 1024.0;
if (fSize < 1024.0)
{
swprintf_s(sBuffer, nBufferSize, L"%.2f KB", fSize);
return;
}
fSize /= 1024.0;
swprintf_s(sBuffer, nBufferSize, L"%.2f MB", fSize);
}
static void SetProgressMessage(IProgressDialog* pProgressDialog, DWORD nProgress, DWORD nMax)
{
wchar_t sNum[32];
std::wstring sMessage;
FormatByteSize(nProgress, sNum, sizeof(sNum) / sizeof(sNum[0]));
sMessage.append(sNum);
sMessage.append(L" of ");
FormatByteSize(nMax, sNum, sizeof(sNum) / sizeof(sNum[0]));
sMessage.append(sNum);
pProgressDialog->SetLine(2, sMessage.c_str(), FALSE, NULL);
}
#endif
static size_t DownloadToFile(char* pData, size_t nDataSize, void* pUserData, DWORD* pStatusCode)
{
FILE* file = (FILE*)pUserData;
return fwrite(pData, 1, nDataSize, file);
size_t nBytesWritten = fwrite(pData, 1, nDataSize, file);
if (nBytesWritten != nDataSize)
{
std::string sMessage;
sMessage = "Error " + std::to_string(errno) + " writing file: " + strerror(errno);
MessageBoxA(nullptr, sMessage.c_str(), "Error", MB_OK | MB_ICONERROR);
*pStatusCode = 0;
}
return nBytesWritten;
}
typedef struct DownloadBuffer
@@ -283,7 +344,7 @@ typedef struct DownloadBuffer
size_t nOffset;
} DownloadBuffer;
static size_t DownloadToBuffer(char* pData, size_t nDataSize, void* pUserData)
static size_t DownloadToBuffer(char* pData, size_t nDataSize, void* pUserData, DWORD* pStatusCode)
{
DownloadBuffer* pBuffer = (DownloadBuffer*)pUserData;
const size_t nRemaining = pBuffer->nBufferSize - pBuffer->nOffset;
@@ -299,10 +360,10 @@ static size_t DownloadToBuffer(char* pData, size_t nDataSize, void* pUserData)
return nDataSize;
}
typedef size_t (DownloadFunc)(char* pData, size_t nDataSize, void* pUserData);
typedef size_t (DownloadFunc)(char* pData, size_t nDataSize, void* pUserData, DWORD* pStatusCode);
static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage, const char* sPostData,
DownloadFunc fnDownload, void* pDownloadUserData, DWORD* pBytesRead, DWORD* pStatusCode)
DownloadFunc fnDownload, void* pDownloadUserData, DWORD* pBytesRead, DWORD* pStatusCode, IProgressDialog* pProgressDialog)
{
BOOL bResults = FALSE, bSuccess = FALSE;
HINTERNET hSession = nullptr, hConnect = nullptr, hRequest = nullptr;
@@ -355,6 +416,8 @@ static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage,
mbstowcs_s(&nTemp, wBuffer, sizeof(wBuffer) / sizeof(wBuffer[0]), sHostName, nHostnameLen);
#else
nTemp = mbstowcs(wBuffer, sHostName, nHostnameLen);
if (nTemp > 0)
wBuffer[nTemp] = '\0';
#endif
if (nTemp > 0)
@@ -373,6 +436,8 @@ static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage,
mbstowcs_s(&nTemp, wBuffer, sizeof(wBuffer) / sizeof(wBuffer[0]), sRequestedPage, strlen(sRequestedPage) + 1);
#else
nTemp = mbstowcs(wBuffer, sRequestedPage, strlen(sRequestedPage) + 1);
if (nTemp > 0)
wBuffer[nTemp] = '\0';
#endif
hRequest = WinHttpOpenRequest(hConnect,
@@ -410,12 +475,28 @@ static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage,
}
else
{
char buffer[16384];
const DWORD nBufferSize = 16384;
char* pBuffer = (char*)malloc(nBufferSize);
DWORD dwSize = sizeof(DWORD);
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, pStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX);
bSuccess = (*pStatusCode == 200);
const DWORD nDefaultTotalBytes = 3 * 1024 * 1024;
DWORD nTotalBytes = nDefaultTotalBytes;
bSuccess = TRUE;
do
#ifndef RA_NOPROGRESS
if (pProgressDialog)
{
dwSize = nBufferSize;
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, pBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX))
{
nTotalBytes = wcstoul((const wchar_t*)pBuffer, NULL, 10);
SetProgressMessage(pProgressDialog, 0, nTotalBytes);
}
}
#endif
while (bSuccess)
{
nBytesAvailable = 0;
WinHttpQueryDataAvailable(hRequest, &nBytesAvailable);
@@ -424,20 +505,17 @@ static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage,
do
{
if (nBytesAvailable > sizeof(buffer))
nBytesToRead = sizeof(buffer);
if (nBytesAvailable > nBufferSize)
nBytesToRead = nBufferSize;
else
nBytesToRead = nBytesAvailable;
nBytesFetched = 0;
if (WinHttpReadData(hRequest, buffer, nBytesToRead, &nBytesFetched))
if (WinHttpReadData(hRequest, pBuffer, nBytesToRead, &nBytesFetched))
{
size_t nBytesWritten = fnDownload(buffer, nBytesFetched, pDownloadUserData);
size_t nBytesWritten = fnDownload(pBuffer, nBytesFetched, pDownloadUserData, pStatusCode);
if (nBytesWritten < nBytesFetched)
{
if (*pStatusCode == 200)
*pStatusCode = 998;
bSuccess = FALSE;
break;
}
@@ -453,8 +531,27 @@ static BOOL DoBlockingHttpCall(const char* sHostUrl, const char* sRequestedPage,
bSuccess = FALSE;
break;
}
#ifndef RA_NOPROGRESS
if (pProgressDialog)
{
if (pProgressDialog->HasUserCancelled())
{
bSuccess = FALSE;
*pStatusCode = 0;
break;
}
pProgressDialog->SetProgress(*pBytesRead, nTotalBytes);
if (nTotalBytes != nDefaultTotalBytes)
SetProgressMessage(pProgressDialog, *pBytesRead, nTotalBytes);
}
#endif
} while (nBytesAvailable > 0);
} while (TRUE);
};
free(pBuffer);
}
WinHttpCloseHandle(hRequest);
@@ -502,7 +599,7 @@ static BOOL DoBlockingHttpCallWithRetry(const char* sHostUrl, const char* sReque
downloadBuffer.pBuffer = pBufferOut;
downloadBuffer.nBufferSize = nBufferOutSize;
if (DoBlockingHttpCall(sHostUrl, sRequestedPage, sPostData, DownloadToBuffer, &downloadBuffer, pBytesRead, pStatusCode) != FALSE)
if (DoBlockingHttpCall(sHostUrl, sRequestedPage, sPostData, DownloadToBuffer, &downloadBuffer, pBytesRead, pStatusCode, NULL) != FALSE)
return TRUE;
if (!IsNetworkError(*pStatusCode))
@@ -515,26 +612,54 @@ static BOOL DoBlockingHttpCallWithRetry(const char* sHostUrl, const char* sReque
}
static BOOL DoBlockingHttpCallWithRetry(const char* sHostUrl, const char* sRequestedPage, const char* sPostData,
FILE* pFile, DWORD* pBytesRead, DWORD* pStatusCode)
FILE* pFile, DWORD* pBytesRead, DWORD* pStatusCode, const wchar_t* sMessage)
{
int nRetries = 4;
do
{
fseek(pFile, 0, SEEK_SET);
if (DoBlockingHttpCall(sHostUrl, sRequestedPage, sPostData, DownloadToFile, pFile, pBytesRead, pStatusCode) != FALSE)
return TRUE;
IProgressDialog* pProgressDialog = NULL;
#ifndef RA_NOPROGRESS
HRESULT hrInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_IProgressDialog, (LPVOID*)&pProgressDialog);
if (!IsNetworkError(*pStatusCode))
return FALSE;
if (SUCCEEDED(hr))
{
if (sMessage)
pProgressDialog->SetLine(1, sMessage, FALSE, NULL);
pProgressDialog->StartProgressDialog(NULL, NULL, PROGDLG_NORMAL, NULL);
}
#endif
--nRetries;
} while (nRetries);
BOOL success = FALSE;
int nRetries = 4;
do
{
fseek(pFile, 0, SEEK_SET);
if (DoBlockingHttpCall(sHostUrl, sRequestedPage, sPostData, DownloadToFile, pFile, pBytesRead, pStatusCode, pProgressDialog) != FALSE)
{
success = TRUE;
break;
}
return FALSE;
if (!IsNetworkError(*pStatusCode))
break;
--nRetries;
} while (nRetries);
#ifndef RA_NOPROGRESS
if (pProgressDialog)
{
pProgressDialog->StopProgressDialog();
pProgressDialog->Release();
}
if (hrInit == S_OK)
CoUninitialize();
#endif
return success;
}
#ifndef RA_UTEST
static std::wstring GetIntegrationPath()
static std::wstring GetIntegrationPath(const wchar_t* sFilename)
{
wchar_t sBuffer[2048];
DWORD iIndex = GetModuleFileNameW(0, sBuffer, 2048);
@@ -542,29 +667,33 @@ static std::wstring GetIntegrationPath()
--iIndex;
#if defined(_MSC_VER) && _MSC_VER >= 1400
wcscpy_s(&sBuffer[iIndex], sizeof(sBuffer)/sizeof(sBuffer[0]) - iIndex, L"RA_Integration.dll");
wcscpy_s(&sBuffer[iIndex], sizeof(sBuffer)/sizeof(sBuffer[0]) - iIndex, sFilename);
#else
wcscpy(&sBuffer[iIndex], L"RA_Integration.dll");
wcscpy(&sBuffer[iIndex], sFilename);
#endif
return std::wstring(sBuffer);
}
#endif
#if 0
static void FetchIntegrationFromWeb(char* sLatestVersionUrl, DWORD* pStatusCode)
{
DWORD nBytesRead = 0;
const wchar_t* sDownloadFilename = L"RA_Integration.download";
const wchar_t* sFilename = L"RA_Integration.dll";
const wchar_t* sOldFilename = L"RA_Integration.old";
const std::wstring sDownloadFilename = GetIntegrationPath(RA_INT_DLL ".download");
const std::wstring sOldFilename = GetIntegrationPath(RA_INT_DLL ".old");
const std::wstring sNewFilename = GetIntegrationPath(RA_INT_DLL);
std::wstring sFilename = sNewFilename;
#ifdef RA_X64
if (GetFileAttributesW(sFilename.c_str()) == INVALID_FILE_ATTRIBUTES)
sFilename = GetIntegrationPath(L"RA_Integration.dll");
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400
FILE* pf;
errno_t nErr = _wfopen_s(&pf, sDownloadFilename, L"wb");
errno_t nErr = _wfopen_s(&pf, sDownloadFilename.c_str(), L"wb");
#else
FILE* pf = _wfopen(sDownloadFilename, L"wb");
FILE* pf = _wfopen(sDownloadFilename.c_str(), L"wb");
#endif
if (!pf)
@@ -573,12 +702,13 @@ static void FetchIntegrationFromWeb(char* sLatestVersionUrl, DWORD* pStatusCode)
wchar_t sErrBuffer[2048];
_wcserror_s(sErrBuffer, sizeof(sErrBuffer) / sizeof(sErrBuffer[0]), nErr);
std::wstring sErrMsg = std::wstring(L"Unable to write ") + sOldFilename + L"\n" + sErrBuffer;
std::wstring sErrMsg = std::wstring(L"Unable to write " RA_INT_DLL L".download\n") + sErrBuffer;
#else
std::wstring sErrMsg = std::wstring(L"Unable to write ") + sOldFilename + L"\n" + _wcserror(errno);
std::wstring sErrMsg = std::wstring(L"Unable to write " RA_INT_DLL L".download\n") + _wcserror(errno);
#endif
MessageBoxW(nullptr, sErrMsg.c_str(), L"Error", MB_OK | MB_ICONERROR);
*pStatusCode = 0;
return;
}
@@ -594,36 +724,36 @@ static void FetchIntegrationFromWeb(char* sLatestVersionUrl, DWORD* pStatusCode)
}
*pSplit++ = '\0';
if (DoBlockingHttpCallWithRetry(sLatestVersionUrl, pSplit, nullptr, pf, &nBytesRead, pStatusCode))
if (DoBlockingHttpCallWithRetry(sLatestVersionUrl, pSplit, nullptr, pf, &nBytesRead, pStatusCode, "Downloading " RA_INT_DLL))
{
fclose(pf);
/* wait up to one second for the DLL to actually be released - sometimes it's not immediate */
for (int i = 0; i < 10; i++)
{
if (GetModuleHandleW(sFilename) == nullptr)
if (GetModuleHandleW(sFilename.c_str()) == nullptr)
break;
Sleep(100);
}
// delete the last old dll if it's still present
DeleteFileW(sOldFilename);
DeleteFileW(sOldFilename.c_str());
// if there's a dll present, rename it
if (GetFileAttributesW(sFilename) != INVALID_FILE_ATTRIBUTES &&
!MoveFileW(sFilename, sOldFilename))
if (GetFileAttributesW(sFilename.c_str()) != INVALID_FILE_ATTRIBUTES &&
!MoveFileW(sFilename.c_str(), sOldFilename.c_str()))
{
MessageBoxW(nullptr, L"Could not rename old dll", L"Error", MB_OK | MB_ICONERROR);
}
// rename the download to be the dll
else if (!MoveFileW(sDownloadFilename, sFilename))
else if (!MoveFileW(sDownloadFilename.c_str(), sNewFilename.c_str()))
{
MessageBoxW(nullptr, L"Could not rename new dll", L"Error", MB_OK | MB_ICONERROR);
}
// delete the old dll
DeleteFileW(sOldFilename);
DeleteFileW(sOldFilename.c_str());
}
else
{
@@ -631,8 +761,6 @@ static void FetchIntegrationFromWeb(char* sLatestVersionUrl, DWORD* pStatusCode)
}
}
#endif
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
static std::string GetLastErrorAsString()
{
@@ -657,9 +785,15 @@ static const char* CCONV _RA_InstallIntegration()
{
SetErrorMode(0);
std::wstring sIntegrationPath = GetIntegrationPath();
std::wstring sIntegrationPath = GetIntegrationPath(RA_INT_DLL);
DWORD dwAttrib = GetFileAttributesW(sIntegrationPath.c_str());
#ifdef RA_X64
if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
sIntegrationPath = GetIntegrationPath(L"RA_Integration.dll");
dwAttrib = GetFileAttributesW(sIntegrationPath.c_str());
}
#endif
if (dwAttrib == INVALID_FILE_ATTRIBUTES)
return "0.0";
@@ -667,7 +801,23 @@ static const char* CCONV _RA_InstallIntegration()
if (g_hRADLL == nullptr)
{
char buffer[1024];
sprintf_s(buffer, 1024, "Could not load RA_Integration.dll: %d\n%s\n", ::GetLastError(), GetLastErrorAsString().c_str());
if (::GetLastError() == ERROR_BAD_EXE_FORMAT)
{
#ifdef RA_X64
sprintf_s(buffer, sizeof(buffer), "Could not load RA_Integration-x64.dll (error %d)\nAre you trying to load the 32-bit version?\n", ::GetLastError());
#else
sprintf_s(buffer, sizeof(buffer), "Could not load RA_Integration.dll (error %d)\nAre you trying to load the 64-bit version?\n", ::GetLastError());
#endif
}
else
{
#ifdef RA_X64
sprintf_s(buffer, sizeof(buffer), "Could not load RA_Integration-x64.dll (error %d)\n%s\n", ::GetLastError(), GetLastErrorAsString().c_str());
#else
sprintf_s(buffer, sizeof(buffer), "Could not load RA_Integration.dll (error %d)\n%s\n", ::GetLastError(), GetLastErrorAsString().c_str());
#endif
}
MessageBoxA(nullptr, buffer, "Warning", MB_OK | MB_ICONWARNING);
return "0.0";
@@ -876,7 +1026,7 @@ static void RA_InitCommon(HWND hMainHWND, int nEmulatorID, const char* sClientNa
GetJsonField(buffer, "LatestVersion", sVersionBuffer, sizeof(sVersionBuffer));
const unsigned long long nLatestDLLVer = ParseVersion(sVersionBuffer);
#if defined(_M_X64) || defined(__amd64__)
#ifdef RA_X64
GetJsonField(buffer, "LatestVersionUrlX64", sLatestVersionUrl, sizeof(sLatestVersionUrl));
#else
GetJsonField(buffer, "LatestVersionUrl", sLatestVersionUrl, sizeof(sLatestVersionUrl));
@@ -930,16 +1080,18 @@ static void RA_InitCommon(HWND hMainHWND, int nEmulatorID, const char* sClientNa
if (nMBReply == IDYES)
{
//FetchIntegrationFromWeb(sLatestVersionUrl, &nStatusCode);
nStatusCode = 0;
FetchIntegrationFromWeb(sLatestVersionUrl, &nStatusCode);
if (nStatusCode == 200)
nVerInstalled = ParseVersion(_RA_InstallIntegration());
if (nVerInstalled < nLatestDLLVer)
if (nStatusCode != 0) // 0 indicates an error was already reported
{
sprintf_s(buffer, sizeof(buffer), "Failed to update toolset (status code %u).", nStatusCode);
MessageBoxA(hMainHWND, buffer, "Error", MB_OK | MB_ICONERROR);
if (nStatusCode == 200)
nVerInstalled = ParseVersion(_RA_InstallIntegration());
if (nVerInstalled < nLatestDLLVer)
{
sprintf_s(buffer, sizeof(buffer), "Failed to update toolset (status code %u).", nStatusCode);
MessageBoxA(hMainHWND, buffer, "Error", MB_OK | MB_ICONERROR);
}
}
}
-91
View File
@@ -1,91 +0,0 @@
add_library(pcsx2-rapidyaml
include/c4/base64.hpp
include/c4/blob.hpp
include/c4/charconv.hpp
include/c4/compiler.hpp
include/c4/config.hpp
include/c4/cpu.hpp
include/c4/dump.hpp
include/c4/error.hpp
include/c4/export.hpp
include/c4/format.hpp
include/c4/language.hpp
include/c4/memory_util.hpp
include/c4/platform.hpp
include/c4/preprocessor.hpp
include/c4/std/std.hpp
include/c4/std/std_fwd.hpp
include/c4/std/string.hpp
include/c4/std/string_fwd.hpp
include/c4/std/string_view.hpp
include/c4/std/tuple.hpp
include/c4/std/vector.hpp
include/c4/std/vector_fwd.hpp
include/c4/substr.hpp
include/c4/substr_fwd.hpp
include/c4/szconv.hpp
include/c4/types.hpp
include/c4/utf.hpp
include/c4/windows.hpp
include/c4/windows_pop.hpp
include/c4/windows_push.hpp
include/c4/yml/common.hpp
include/c4/yml/detail/dbgprint.hpp
include/c4/yml/detail/stack.hpp
include/c4/yml/emit.def.hpp
include/c4/yml/emit.hpp
include/c4/yml/event_handler_stack.hpp
include/c4/yml/event_handler_tree.hpp
include/c4/yml/filter_processor.hpp
include/c4/yml/fwd.hpp
include/c4/yml/export.hpp
include/c4/yml/node.hpp
include/c4/yml/node_type.hpp
include/c4/yml/parse.hpp
include/c4/yml/parse_engine.def.hpp
include/c4/yml/parse_engine.hpp
include/c4/yml/parser_state.hpp
include/c4/yml/reference_resolver.hpp
include/c4/yml/preprocess.hpp
include/c4/yml/std/map.hpp
include/c4/yml/std/std.hpp
include/c4/yml/std/string.hpp
include/c4/yml/std/vector.hpp
include/c4/yml/tag.hpp
include/c4/yml/tree.hpp
include/c4/yml/version.hpp
include/c4/yml/writer.hpp
include/c4/yml/yml.hpp
include/ryml.hpp
include/ryml_std.hpp
src/c4/base64.cpp
src/c4/error.cpp
src/c4/format.cpp
src/c4/language.cpp
src/c4/memory_util.cpp
src/c4/utf.cpp
src/c4/yml/common.cpp
src/c4/yml/node.cpp
src/c4/yml/parse.cpp
src/c4/yml/preprocess.cpp
src/c4/yml/tree.cpp
src/c4/yml/node_type.cpp
src/c4/yml/reference_resolver.cpp
src/c4/yml/tag.cpp
src/c4/yml/version.cpp
)
target_include_directories(pcsx2-rapidyaml PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/../fast_float/include"
)
target_include_directories(pcsx2-rapidyaml INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_compile_definitions(pcsx2-rapidyaml PUBLIC
"C4_NO_DEBUG_BREAK"
)
add_library(rapidyaml::rapidyaml ALIAS pcsx2-rapidyaml)
-141
View File
@@ -1,141 +0,0 @@
#ifndef _C4_BASE64_HPP_
#define _C4_BASE64_HPP_
/** @file base64.hpp encoding/decoding for base64.
* @see https://en.wikipedia.org/wiki/Base64
* @see https://www.base64encode.org/
* */
#include "c4/charconv.hpp"
#include "c4/blob.hpp"
namespace c4 {
/** @defgroup doc_base64 Base64 encoding/decoding
* @see https://en.wikipedia.org/wiki/Base64
* @see https://www.base64encode.org/
* @{ */
/** check that the given buffer is a valid base64 encoding
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT bool base64_valid(csubstr encoded);
/** base64-encode binary data.
* @param encoded [out] output buffer for encoded data
* @param data [in] the input buffer with the binary data
*
* @return the number of bytes needed to return the output (ie the
* required size for @p encoded). No writes occur beyond the end of
* the output buffer, so it is safe to do a speculative call where the
* encoded buffer is empty, or maybe too small. The caller should
* ensure that the returned size is smaller than the size of the
* encoded buffer.
*
* @note the result depends on endianness. If transfer between
* little/big endian systems is desired, the caller should normalize
* @p data before encoding.
*
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT size_t base64_encode(substr encoded, cblob data);
/** decode the base64 encoding in the given buffer
* @param encoded [in] the encoded base64
* @param data [out] the output buffer
*
* @return the number of bytes needed to return the output (ie the
* required size for @p data). No writes occur beyond the end of the
* output buffer, so it is safe to do a speculative call where the
* data buffer is empty, or maybe too small. The caller should ensure
* that the returned size is smaller than the size of the data buffer.
*
* @note the result depends on endianness. If transfer between
* little/big endian systems is desired, the caller should normalize
* @p data after decoding.
*
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT size_t base64_decode(csubstr encoded, blob data);
/** @} */ // base64
namespace fmt {
/** @addtogroup doc_format_specifiers
* @{ */
/** @defgroup doc_base64_fmt Base64
* @{ */
template<typename CharOrConstChar>
struct base64_wrapper_
{
blob_<CharOrConstChar> data;
base64_wrapper_() : data() {}
base64_wrapper_(blob_<CharOrConstChar> blob) : data(blob) {}
};
/** a tag type to mark a payload as base64-encoded */
using const_base64_wrapper = base64_wrapper_<cbyte>;
/** a tag type to mark a payload to be encoded as base64 */
using base64_wrapper = base64_wrapper_<byte>;
/** mark a variable to be written in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE const_base64_wrapper cbase64(Args const& C4_RESTRICT ...args)
{
return const_base64_wrapper(cblob(args...));
}
/** mark a csubstr to be written in base64 format */
C4_ALWAYS_INLINE const_base64_wrapper cbase64(csubstr s)
{
return const_base64_wrapper(cblob(s.str, s.len));
}
/** mark a variable to be written in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE const_base64_wrapper base64(Args const& C4_RESTRICT ...args)
{
return const_base64_wrapper(cblob(args...));
}
/** mark a csubstr to be written in base64 format */
C4_ALWAYS_INLINE const_base64_wrapper base64(csubstr s)
{
return const_base64_wrapper(cblob(s.str, s.len));
}
/** mark a variable to be read in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE base64_wrapper base64(Args &... args)
{
return base64_wrapper(blob(args...));
}
/** mark a variable to be read in base64 format */
C4_ALWAYS_INLINE base64_wrapper base64(substr s)
{
return base64_wrapper(blob(s.str, s.len));
}
/** @} */ // base64_fmt
/** @} */ // format_specifiers
} // namespace fmt
/** write a variable in base64 format
* @ingroup doc_to_chars */
inline size_t to_chars(substr buf, fmt::const_base64_wrapper b)
{
return base64_encode(buf, b.data);
}
/** read a variable in base64 format
* @ingroup doc_from_chars */
inline size_t from_chars(csubstr buf, fmt::base64_wrapper *b)
{
return base64_decode(buf, b->data);
}
} // namespace c4
#endif /* _C4_BASE64_HPP_ */
-71
View File
@@ -1,71 +0,0 @@
#ifndef _C4_BLOB_HPP_
#define _C4_BLOB_HPP_
#include "c4/types.hpp"
#include "c4/error.hpp"
/** @file blob.hpp Mutable and immutable binary data blobs.
*/
namespace c4 {
template<class T>
struct blob_;
namespace detail {
template<class T> struct is_blob_type : std::integral_constant<bool, false> {};
template<class T> struct is_blob_type<blob_<T>> : std::integral_constant<bool, true> {};
template<class T> struct is_blob_value_type : std::integral_constant<bool, (std::is_fundamental<T>::value || std::is_trivially_copyable<T>::value)> {};
} // namespace
// NOLINTBEGIN(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
template<class T>
struct blob_
{
static_assert(std::is_same<T, byte>::value || std::is_same<T, cbyte>::value, "must be either byte or cbyte");
static_assert(sizeof(T) == 1u, "must be either byte or cbyte");
public:
T * buf;
size_t len;
public:
C4_ALWAYS_INLINE blob_() noexcept = default;
C4_ALWAYS_INLINE blob_(blob_ const& that) noexcept = default;
C4_ALWAYS_INLINE blob_(blob_ && that) noexcept = default;
C4_ALWAYS_INLINE blob_& operator=(blob_ && that) noexcept = default;
C4_ALWAYS_INLINE blob_& operator=(blob_ const& that) noexcept = default;
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> const& that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> && that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> && that) noexcept { buf = that.buf; len = that.len; } // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> const& that) noexcept { buf = that.buf; len = that.len; } // NOLINT
C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
#define _C4_REQUIRE_BLOBTYPE(ty) class=typename std::enable_if<((!detail::is_blob_type<ty>::value) && (detail::is_blob_value_type<ty>::value)), T>::type
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast<T*>(&var)), len(sizeof(U)) {} // NOLINT
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); } // NOLINT
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast<T*>(&var); len = sizeof(U); return *this; } // NOLINT
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast<T*>(arr)), len(sizeof(U) * N) {} // NOLINT
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast<T*>(arr); len = sizeof(U) * N; return *this; } // NOLINT
#undef _C4_REQUIRE_BLOBTYPE
};
// NOLINTEND(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
/** an immutable binary blob */
using cblob = blob_<cbyte>;
/** a mutable binary blob */
using blob = blob_< byte>;
C4_MUST_BE_TRIVIAL_COPY(blob);
C4_MUST_BE_TRIVIAL_COPY(cblob);
} // namespace c4
#endif // _C4_BLOB_HPP_
-168
View File
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Very good intro:
@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
See also:
@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="c4::basic_substring&lt;*&gt;">
<DisplayString>{str,[len]} (sz={len})</DisplayString>
<StringView>str,[len]</StringView>
<Expand>
<Item Name="[size]">len</Item>
<ArrayItems>
<Size>len</Size>
<ValuePointer>str</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::span&lt;*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::spanrs&lt;*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- display span<char>/span<const char> as a string too -->
<Type Name="c4::span&lt;char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::span&lt;const char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- display spanrs<char>/spanrs<const char> as a string too -->
<Type Name="c4::spanrs&lt;char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::spanrs&lt;const char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- =========================================================================================== -->
<Type Name="c4::string_impl&lt;*,*,*,*&gt;">
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]} (sz={(($T3*)this)->m_size})</DisplayString>
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
<Expand>
<Synthetic Name="m_str">
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]}</DisplayString>
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
</Synthetic>
<Synthetic Name="m_size">
<DisplayString>{(($T3*)this)->m_size}</DisplayString>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_substring&lt;*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_substringrs&lt;*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
<Synthetic Name="[capacity]">
<DisplayString>{m_capacity}</DisplayString>
</Synthetic>
<Synthetic Name="[full]">
<DisplayString>{m_str,[m_capacity]}</DisplayString>
<StringView>m_str,[m_capacity]</StringView>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_string&lt;*,*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
<Synthetic Name="[full]">
<DisplayString>{m_str,[m_capacity]}</DisplayString>
<StringView>m_str,[m_capacity]</StringView>
</Synthetic>
</Expand>
</Type>
<!-- enum symbols -->
<Type Name="c4::EnumSymbols&lt;*&gt;::Sym">
<DisplayString>{value} - {name}</DisplayString>
<Expand>
<Item Name="[value]">value</Item>
<Item Name="[name]">name</Item>
</Expand>
</Type>
<Type Name="c4::EnumSymbols&lt;*&gt;">
<DisplayString>{m_symbols,[m_num]} (sz={m_num})</DisplayString>
<Expand>
<Item Name="[size]">m_num</Item>
<ArrayItems>
<Size>m_num</Size>
<ValuePointer>m_symbols</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
File diff suppressed because it is too large Load Diff
-120
View File
@@ -1,120 +0,0 @@
#ifndef _C4_COMPILER_HPP_
#define _C4_COMPILER_HPP_
/** @file compiler.hpp Provides compiler information macros
* @ingroup basic_headers */
#include "c4/platform.hpp"
// Compilers:
// C4_MSVC
// Visual Studio 2022: MSVC++ 17, 1930
// Visual Studio 2019: MSVC++ 16, 1920
// Visual Studio 2017: MSVC++ 15
// Visual Studio 2015: MSVC++ 14
// Visual Studio 2013: MSVC++ 13
// Visual Studio 2013: MSVC++ 12
// Visual Studio 2012: MSVC++ 11
// Visual Studio 2010: MSVC++ 10
// Visual Studio 2008: MSVC++ 09
// Visual Studio 2005: MSVC++ 08
// C4_CLANG
// C4_GCC
// C4_ICC (intel compiler)
/** @see http://sourceforge.net/p/predef/wiki/Compilers/ for a list of compiler identifier macros */
/** @see https://msdn.microsoft.com/en-us/library/b0084kay.aspx for VS2013 predefined macros */
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_MSVC
# define C4_MSVC_VERSION_2022 17
# define C4_MSVC_VERSION_2019 16
# define C4_MSVC_VERSION_2017 15
# define C4_MSVC_VERSION_2015 14
# define C4_MSVC_VERSION_2013 12
# define C4_MSVC_VERSION_2012 11
# if _MSC_VER >= 1930
# define C4_MSVC_VERSION C4_MSVC_VERSION_2022 // visual studio 2022
# define C4_MSVC_2022
# elif _MSC_VER >= 1920
# define C4_MSVC_VERSION C4_MSVC_VERSION_2019 // visual studio 2019
# define C4_MSVC_2019
# elif _MSC_VER >= 1910
# define C4_MSVC_VERSION C4_MSVC_VERSION_2017 // visual studio 2017
# define C4_MSVC_2017
# elif _MSC_VER == 1900
# define C4_MSVC_VERSION C4_MSVC_VERSION_2015 // visual studio 2015
# define C4_MSVC_2015
# elif _MSC_VER == 1800
# error "MSVC version not supported"
# define C4_MSVC_VERSION C4_MSVC_VERSION_2013 // visual studio 2013
# define C4_MSVC_2013
# elif _MSC_VER == 1700
# error "MSVC version not supported"
# define C4_MSVC_VERSION C4_MSVC_VERSION_2012 // visual studio 2012
# define C4_MSVC_2012
# elif _MSC_VER == 1600
# error "MSVC version not supported"
# define C4_MSVC_VERSION 10 // visual studio 2010
# define C4_MSVC_2010
# elif _MSC_VER == 1500
# error "MSVC version not supported"
# define C4_MSVC_VERSION 09 // visual studio 2008
# define C4_MSVC_2008
# elif _MSC_VER == 1400
# error "MSVC version not supported"
# define C4_MSVC_VERSION 08 // visual studio 2005
# define C4_MSVC_2005
# else
# error "MSVC version not supported"
# endif // _MSC_VER
#else
# define C4_MSVC_VERSION 0 // visual studio not present
# define C4_GCC_LIKE
# ifdef __INTEL_COMPILER // check ICC before checking GCC, as ICC defines __GNUC__ too
# define C4_ICC
# define C4_ICC_VERSION __INTEL_COMPILER
# elif defined(__APPLE_CC__)
# define C4_XCODE
# if defined(__clang__)
# define C4_CLANG
# ifndef __apple_build_version__
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
# else
# define C4_CLANG_VERSION __apple_build_version__
# endif
# else
# define C4_XCODE_VERSION __APPLE_CC__
# endif
# elif defined(__clang__)
# define C4_CLANG
# ifndef __apple_build_version__
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
# else
# define C4_CLANG_VERSION __apple_build_version__
# endif
# elif defined(__GNUC__)
# ifdef __MINGW32__
# define C4_MINGW
# endif
# define C4_GCC
# if defined(__GNUC_PATCHLEVEL__)
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
# else
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, 0)
# endif
# if __GNUC__ < 5
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 8
// provided by cmake sub-project
# include "c4/gcc-4.8.hpp"
# else
// we do not support GCC < 4.8:
// * misses std::is_trivially_copyable
// * misses std::align
// * -Wshadow has false positives when a local function parameter has the same name as a method
# error "GCC < 4.8 is not supported"
# endif
# endif
# endif
#endif // defined(C4_WIN) && defined(_MSC_VER)
#endif /* _C4_COMPILER_HPP_ */
-39
View File
@@ -1,39 +0,0 @@
#ifndef _C4_CONFIG_HPP_
#define _C4_CONFIG_HPP_
/** @defgroup basic_headers Basic headers
* @brief Headers providing basic macros, platform+cpu+compiler information,
* C++ facilities and basic typedefs. */
/** @file config.hpp Contains configuration defines and includes the basic_headers.
* @ingroup basic_headers */
//#define C4_DEBUG
#define C4_ERROR_SHOWS_FILELINE
//#define C4_ERROR_SHOWS_FUNC
//#define C4_ERROR_THROWS_EXCEPTION
//#define C4_NO_ALLOC_DEFAULTS
//#define C4_REDEFINE_CPPNEW
#ifndef C4_SIZE_TYPE
# define C4_SIZE_TYPE size_t
#endif
#ifndef C4_STR_SIZE_TYPE
# define C4_STR_SIZE_TYPE C4_SIZE_TYPE
#endif
#ifndef C4_TIME_TYPE
# define C4_TIME_TYPE double
#endif
#include "c4/export.hpp"
#include "c4/preprocessor.hpp"
#include "c4/platform.hpp"
#include "c4/cpu.hpp"
#include "c4/compiler.hpp"
#include "c4/language.hpp"
#include "c4/types.hpp"
#endif // _C4_CONFIG_HPP_
-205
View File
@@ -1,205 +0,0 @@
#ifndef _C4_CPU_HPP_
#define _C4_CPU_HPP_
/** @file cpu.hpp Provides processor information macros
* @ingroup basic_headers */
// see also https://sourceforge.net/p/predef/wiki/Architectures/
// see also https://sourceforge.net/p/predef/wiki/Endianness/
// see also https://github.com/googlesamples/android-ndk/blob/android-mk/hello-jni/jni/hello-jni.c
// see also http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
#ifdef __ORDER_LITTLE_ENDIAN__
# define _C4EL __ORDER_LITTLE_ENDIAN__
#else
# define _C4EL 1234
#endif
#ifdef __ORDER_BIG_ENDIAN__
# define _C4EB __ORDER_BIG_ENDIAN__
#else
# define _C4EB 4321
#endif
// mixed byte order (eg, PowerPC or ia64)
#define _C4EM 1111 // NOLINT
// NOTE: to find defined macros in a platform,
// g++ <flags> -dM -E - </dev/null | sort
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
# define C4_CPU_X86_64
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EL
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define C4_CPU_X86
# define C4_WORDSIZE 4
# define C4_BYTE_ORDER _C4EL
#elif defined(__arm__) || defined(_M_ARM) \
|| defined(__TARGET_ARCH_ARM) || defined(__aarch64__) || defined(_M_ARM64)
# if defined(__aarch64__) || defined(_M_ARM64)
# define C4_CPU_ARM64
# define C4_CPU_ARMV8
# define C4_WORDSIZE 8
# else
# define C4_CPU_ARM
# define C4_WORDSIZE 4
# if defined(__ARM_ARCH_8__) || defined(__ARM_ARCH_8A__) \
|| (defined(__ARCH_ARM) && __ARCH_ARM >= 8) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 8)
# define C4_CPU_ARMV8
# elif defined(__ARM_ARCH_7__) || defined(_ARM_ARCH_7) \
|| defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) \
|| defined(__ARM_ARCH_7EM__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 7) \
|| (defined(_M_ARM) && _M_ARM >= 7)
# define C4_CPU_ARMV7
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) \
|| defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_6KZ__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 6)
# define C4_CPU_ARMV6
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 5) \
|| defined(__ARM_ARCH_5TEJ__) \
|| defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5T__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 5)
# define C4_CPU_ARMV5
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 4) \
|| defined(__ARM_ARCH_4T__) \
|| defined(__ARM_ARCH_4__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 4)
# define C4_CPU_ARMV4
# else
# error "unknown CPU architecture: ARM"
# endif
# endif
# if defined(__ARMEL__) || defined(__LITTLE_ENDIAN__) || defined(__AARCH64EL__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
|| defined(_MSC_VER) // winarm64 does not provide any of the above macros,
// but advises little-endianess:
// https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170
// So if it is visual studio compiling, we'll assume little endian.
# define C4_BYTE_ORDER _C4EL
# elif defined(__ARMEB__) || defined(__BIG_ENDIAN__) || defined(__AARCH64EB__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
# define C4_BYTE_ORDER _C4EB
# elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_PDP_ENDIAN__)
# define C4_BYTE_ORDER _C4EM
# else
# error "unknown endianness"
# endif
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define C4_CPU_IA64
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EM
// itanium is bi-endian - check byte order below
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \
|| defined(_M_MPPC) || defined(_M_PPC)
# if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
# define C4_CPU_PPC64
# define C4_WORDSIZE 8
# else
# define C4_CPU_PPC
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EM
// ppc is bi-endian - check byte order below
#elif defined(__s390x__) || defined(__zarch__) || defined(__SYSC_ZARCH_)
# define C4_CPU_S390_X
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EB
#elif defined(__xtensa__) || defined(__XTENSA__)
# define C4_CPU_XTENSA
# define C4_WORDSIZE 4
// not sure about this...
# if defined(__XTENSA_EL__) || defined(__xtensa_el__)
# define C4_BYTE_ORDER _C4EL
# else
# define C4_BYTE_ORDER _C4EB
# endif
#elif defined(__riscv)
# if __riscv_xlen == 64
# define C4_CPU_RISCV64
# define C4_WORDSIZE 8
# else
# define C4_CPU_RISCV32
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EL
#elif defined(__EMSCRIPTEN__)
# define C4_BYTE_ORDER _C4EL
# define C4_WORDSIZE 4
#elif defined(__loongarch__)
# if defined(__loongarch64)
# define C4_CPU_LOONGARCH64
# define C4_WORDSIZE 8
# else
# define C4_CPU_LOONGARCH
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EL
#elif defined(__mips__) || defined(_mips) || defined(mips)
# if defined(__mips)
# if __mips == 64
# define C4_CPU_MIPS64
# define C4_WORDSIZE 8
# elif __mips == 32
# define C4_CPU_MIPS32
# define C4_WORDSIZE 4
# endif
# elif defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
# define C4_CPU_MIPS64
# define C4_WORDSIZE 8
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
# define C4_CPU_MIPS32
# define C4_WORDSIZE 4
# else
# error "unknown mips architecture"
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define C4_BYTE_ORDER _C4EB
# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define C4_BYTE_ORDER _C4EL
# else
# error "unknown mips endianness"
# endif
#elif defined(__sparc__) || defined(__sparc) || defined(sparc)
# if defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
# define C4_CPU_SPARC64
# define C4_WORDSIZE 8
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
# define C4_CPU_SPARC32
# define C4_WORDSIZE 4
# else
# error "unknown sparc architecture"
# endif
# define C4_BYTE_ORDER _C4EB
#elif defined(SWIG)
# error "please define CPU architecture macros when compiling with swig"
#else
# error "unknown CPU architecture"
#endif
#define C4_LITTLE_ENDIAN (C4_BYTE_ORDER == _C4EL)
#define C4_BIG_ENDIAN (C4_BYTE_ORDER == _C4EB)
#define C4_MIXED_ENDIAN (C4_BYTE_ORDER == _C4EM)
#endif /* _C4_CPU_HPP_ */
-798
View File
@@ -1,798 +0,0 @@
#ifndef C4_DUMP_HPP_
#define C4_DUMP_HPP_
#include <c4/substr.hpp>
/** @file dump.hpp This file provides functions to dump several
* arguments as strings to a user-provided function sink, for example
* to implement a type-safe printf()-like function (where the sink
* would just be a plain call to putchars()). The function sink can be
* passed either by dynamic dispatching or by static dispatching (as a
* template argument). There are analogs to @ref c4::cat() (@ref
* c4::cat_dump() and @ref c4::cat_dump_resume()), @ref c4::catsep()
* (@ref catsetp_dump() and @ref catsep_dump_resume()) and @ref
* c4::format() (@ref c4::format_dump() and @ref
* c4::format_dump_resume()). The analogs have two types: immediate
* and resuming. An analog of immediate type cannot be retried when
* the work buffer is too small; this means that successful dumps in
* the first (successful) arguments will be dumped again in the
* subsequent attempt to call. An analog of resuming type will only
* ever dump as-yet-undumped arguments, through the use of @ref
* DumpResults return type. */
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup dump_building_blocks Basic building blocks for dumping.
*
* The basic building block: given an argument and a
* buffer, serialize the argument to the buffer using @ref
* c4::to_chars(), and dump the buffer to the provided sink
* function. When the argument is a string, no serialization is
* performed, and the argument is dumped directly to the sink.
*
* @{ */
/** Type of the function to be used as the sink. This function
* receives as its argument the string with characters to send to the
* sink.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
* */
using SinkPfn = void (*)(csubstr str);
/** a traits class to use in SFINAE with @ref c4::dump() to select if
* a type is treated as string type (which is dumped directly to the
* sink, using to_csubstr()), or if the type is treated as a value,
* which is first serialized to a buffer using to_chars(), and then
* the serialization serialized as */
template<class T> struct dump_directly : public std::false_type {};
template<> struct dump_directly<csubstr> : public std::true_type {};
template<> struct dump_directly< substr> : public std::true_type {};
template<> struct dump_directly<const char*> : public std::true_type {};
template<> struct dump_directly< char*> : public std::true_type {};
template<size_t N> struct dump_directly<const char (&)[N]> : public std::true_type {};
template<size_t N> struct dump_directly< char (&)[N]> : public std::true_type {};
template<size_t N> struct dump_directly<const char[N]> : public std::true_type {};
template<size_t N> struct dump_directly< char[N]> : public std::true_type {};
/** Dump a string-type object to the (statically dispatched) sink. The
* string is dumped directly, without any intermediate serialization.
*
* @return the number of bytes needed to serialize the string-type
* object, which is always 0 because there is no serialization
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
*
* @see dump_directly<T>
*/
template<SinkPfn sinkfn, class Arg>
inline auto dump(substr buf, Arg const& a)
-> typename std::enable_if<dump_directly<Arg>::value, size_t>::type
{
C4_ASSERT(!buf.overlaps(a));
C4_UNUSED(buf);
// dump directly, no need to serialize to the buffer
sinkfn(to_csubstr(a));
return 0; // no space was used in the buffer
}
/** Dump a string-type object to the (dynamically dispatched)
* sink. The string is dumped directly, without any intermediate
* serialization to the buffer.
*
* @return the number of bytes needed to serialize the string-type
* object, which is always 0 because there is no serialization
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
*
* @see dump_directly<T>
* */
template<class SinkFn, class Arg>
inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a)
-> typename std::enable_if<dump_directly<Arg>::value, size_t>::type
{
C4_UNUSED(buf);
C4_ASSERT(!buf.overlaps(a));
// dump directly, no need to serialize to the buffer
std::forward<SinkFn>(sinkfn)(to_csubstr(a));
return 0; // no space was used in the buffer
}
/** Dump a value to the sink. Given an argument @p a and a buffer @p
* buf, serialize the argument to the buffer using @ref to_chars(),
* and then dump the buffer to the (statically dispatched) sink
* function passed as the template argument. If the buffer is too
* small to serialize the argument, the sink function is not called.
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @see dump_directly<T>
*
* @return the number of characters required to serialize the
* argument. */
template<SinkPfn sinkfn, class Arg>
inline auto dump(substr buf, Arg const& a)
-> typename std::enable_if<!dump_directly<Arg>::value, size_t>::type
{
// serialize to the buffer
const size_t sz = to_chars(buf, a);
// dump the buffer to the sink
if(C4_LIKELY(sz <= buf.len))
{
// NOTE: don't do this:
//sinkfn(buf.first(sz));
// ... but do this instead:
sinkfn({buf.str, sz});
// ... this is needed because Release builds for armv5 and
// armv6 were failing for the first call, with the wrong
// buffer being passed into the function (!)
}
return sz;
}
/** Dump a value to the sink. Given an argument @p a and a buffer @p
* buf, serialize the argument to the buffer using @ref
* c4::to_chars(), and then dump the buffer to the (dynamically
* dispatched) sink function, passed as @p sinkfn. If the buffer is too
* small to serialize the argument, the sink function is not called.
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @see @ref dump_directly<T>
*
* @return the number of characters required to serialize the
* argument. */
template<class SinkFn, class Arg>
inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a)
-> typename std::enable_if<!dump_directly<Arg>::value, size_t>::type
{
// serialize to the buffer
const size_t sz = to_chars(buf, a);
// dump the buffer to the sink
if(C4_LIKELY(sz <= buf.len))
{
// NOTE: don't do this:
//std::forward<SinkFn>(sinkfn)(buf.first(sz));
// ... but do this instead:
std::forward<SinkFn>(sinkfn)({buf.str, sz});
// ... this is needed because Release builds for armv5 and
// armv6 were failing for the first call, with the wrong
// buffer being passed into the function (!)
}
return sz;
}
/** An opaque type used by resumeable dump functions like @ref
* cat_dump_resume(), @ref catsep_dump_resume() or @ref
* format_dump_resume(). */
struct DumpResults
{
enum : size_t { noarg = (size_t)-1 };
size_t bufsize = 0;
size_t lastok = noarg;
bool success_until(size_t expected) const { return lastok == noarg ? false : lastok >= expected; }
bool write_arg(size_t arg) const { return lastok == noarg || arg > lastok; }
size_t argfail() const { return lastok + 1; }
};
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup cat_dump Dump several arguments to a sink,
* concatenated. This is the analog to @ref c4::cat(), with the
* significant difference that each argument is immediately sent to
* the sink (resulting in multiple calls to the sink function, once
* per argument), whereas equivalent usage of c4::cat() would first
* serialize all the arguments to the buffer, and then call the sink
* once at the end. As a consequence, the size needed for the buffer
* is only the maximum of the size needed for the arguments, whereas
* with c4::cat(), the size needed for the buffer would be the sum of
* the size needed for the arguments. When the size of dump
*
* @{ */
/// @cond dev
// terminates the variadic recursion
template<class SinkFn>
size_t cat_dump(SinkFn &&, substr) // NOLINT
{
return 0;
}
// terminates the variadic recursion
template<SinkPfn sinkfn>
size_t cat_dump(substr) // NOLINT
{
return 0;
}
/// @endcond
/** Dump several arguments to the (dynamically dispatched) sink
* function, as if through c4::cat(). For each argument, @ref dump()
* is called with the buffer and sink. If any of the arguments is too
* large for the buffer, no subsequent argument is sent to the sink,
* (but all the arguments are still processed to compute the size
* required for the buffer). This function can be safely called with an
* empty buffer.
*
* @return the size required for the buffer, which is the maximum size
* across all arguments
*
* @note subsequent calls with the same set of arguments will dump
* again the first successful arguments. If each argument must only be
* sent once to the sink (for example with printf-like behavior), use
* instead @ref cat_dump_resume(). */
template<class SinkFn, class Arg, class... Args>
size_t cat_dump(SinkFn &&sinkfn, substr buf, Arg const& a, Args const& ...more)
{
const size_t size_for_a = dump(std::forward<SinkFn>(sinkfn), buf, a);
if(C4_UNLIKELY(size_for_a > buf.len))
buf.len = 0; // ensure no more calls to the sink
const size_t size_for_more = cat_dump(std::forward<SinkFn>(sinkfn), buf, more...);
return size_for_more > size_for_a ? size_for_more : size_for_a;
}
/** Dump several arguments to the (statically dispatched) sink
* function, as if through c4::cat(). For each argument, @ref dump()
* is called with the buffer and sink. If any of the arguments is too
* large for the buffer, no subsequent argument is sent to the sink,
* (but all the arguments are still processed to compute the size
* required for the buffer). This function can be safely called with an
* empty buffer.
*
* @return the size required for the buffer, which is the maximum size
* across all arguments
*
* @note subsequent calls with the same set of arguments will dump
* again the first successful arguments. If each argument must only be
* sent once to the sink (for example with printf-like behavior), use
* instead @ref cat_dump_resume(). */
template<SinkPfn sinkfn, class Arg, class... Args>
size_t cat_dump(substr buf, Arg const& a, Args const& ...more)
{
const size_t size_for_a = dump<sinkfn>(buf, a);
if(C4_UNLIKELY(size_for_a > buf.len))
buf.len = 0; // ensure no more calls to the sink
const size_t size_for_more = cat_dump<sinkfn>(buf, more...);
return size_for_more > size_for_a ? size_for_more : size_for_a;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminates the variadic recursion
template<SinkPfn sinkfn>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, DumpResults results, substr)
{
return results;
}
// terminates the variadic recursion
template<class SinkFn>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, SinkFn &&, DumpResults results, substr) // NOLINT
{
return results;
}
template<SinkPfn sinkfn, class Arg, class... Args>
DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
size_t sz = dump<sinkfn>(buf, a); // yield to the specialized function
if(currarg == results.lastok + 1 && sz <= buf.len)
results.lastok = currarg;
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
}
return detail::cat_dump_resume<sinkfn>(currarg + 1u, results, buf, more...);
}
template<class SinkFn, class Arg, class... Args>
DumpResults cat_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), buf, a); // yield to the specialized function
if(currarg == results.lastok + 1 && sz <= buf.len)
results.lastok = currarg;
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
}
return detail::cat_dump_resume(currarg + 1u, std::forward<SinkFn>(sinkfn), results, buf, more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
return detail::cat_dump_resume<sinkfn>(0u, DumpResults{}, buf, a, more...);
}
template<class SinkFn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(SinkFn &&sinkfn, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
return detail::cat_dump_resume(0u, std::forward<SinkFn>(sinkfn), DumpResults{}, buf, a, more...);
}
template<SinkPfn sinkfn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(results.bufsize > buf.len)
return results;
return detail::cat_dump_resume<sinkfn>(0u, results, buf, a, more...);
}
template<class SinkFn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(results.bufsize > buf.len)
return results;
return detail::cat_dump_resume(0u, std::forward<SinkFn>(sinkfn), results, buf, a, more...);
}
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
// terminate the recursion
template<class SinkFn, class Sep>
size_t catsep_dump(SinkFn &&, substr, Sep const& C4_RESTRICT) // NOLINT
{
return 0;
}
// terminate the recursion
template<SinkPfn sinkfn, class Sep>
size_t catsep_dump(substr, Sep const& C4_RESTRICT) // NOLINT
{
return 0;
}
/// @endcond
/** take the function pointer as a function argument */
template<class SinkFn, class Sep, class Arg, class... Args>
size_t catsep_dump(SinkFn &&sinkfn, substr buf, Sep const& sep, Arg const& a, Args const& ...more)
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), buf, a);
if(C4_UNLIKELY(sz > buf.len))
buf.len = 0; // ensure no more calls
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
{
size_t szsep = dump(std::forward<SinkFn>(sinkfn), buf, sep);
if(C4_UNLIKELY(szsep > buf.len))
buf.len = 0; // ensure no more calls
sz = sz > szsep ? sz : szsep;
}
size_t size_for_more = catsep_dump(std::forward<SinkFn>(sinkfn), buf, sep, more...);
return size_for_more > sz ? size_for_more : sz;
}
/** take the function pointer as a template argument */
template<SinkPfn sinkfn, class Sep, class Arg, class... Args>
size_t catsep_dump(substr buf, Sep const& sep, Arg const& a, Args const& ...more)
{
size_t sz = dump<sinkfn>(buf, a);
if(C4_UNLIKELY(sz > buf.len))
buf.len = 0; // ensure no more calls
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
{
size_t szsep = dump<sinkfn>(buf, sep);
if(C4_UNLIKELY(szsep > buf.len))
buf.len = 0; // ensure no more calls
sz = sz > szsep ? sz : szsep;
}
size_t size_for_more = catsep_dump<sinkfn>(buf, sep, more...);
return size_for_more > sz ? size_for_more : sz;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
template<SinkPfn sinkfn, class Arg>
void catsep_dump_resume_(size_t currarg, DumpResults *C4_RESTRICT results, substr *buf, Arg const& a)
{
if(C4_LIKELY(results->write_arg(currarg)))
{
size_t sz = dump<sinkfn>(*buf, a);
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
if(C4_LIKELY(sz <= buf->len))
results->lastok = currarg;
else
buf->len = 0;
}
}
template<class SinkFn, class Arg>
void catsep_dump_resume_(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
{
if(C4_LIKELY(results->write_arg(currarg)))
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), *buf, a);
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
if(C4_LIKELY(sz <= buf->len))
results->lastok = currarg;
else
buf->len = 0;
}
}
template<SinkPfn sinkfn, class Sep, class Arg>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const&, Arg const& a)
{
detail::catsep_dump_resume_<sinkfn>(currarg, results, buf, a);
}
template<class SinkFn, class Sep, class Arg>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const&, Arg const& a)
{
detail::catsep_dump_resume_(currarg, std::forward<SinkFn>(sinkfn), results, buf, a);
}
template<SinkPfn sinkfn, class Sep, class Arg, class... Args>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& sep, Arg const& a, Args const& ...more)
{
detail::catsep_dump_resume_<sinkfn>(currarg , results, buf, a);
detail::catsep_dump_resume_<sinkfn>(currarg + 1u, results, buf, sep);
detail::catsep_dump_resume <sinkfn>(currarg + 2u, results, buf, sep, more...);
}
template<class SinkFn, class Sep, class Arg, class... Args>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& sep, Arg const& a, Args const& ...more)
{
detail::catsep_dump_resume_(currarg , std::forward<SinkFn>(sinkfn), results, buf, a);
detail::catsep_dump_resume_(currarg + 1u, std::forward<SinkFn>(sinkfn), results, buf, sep);
detail::catsep_dump_resume (currarg + 2u, std::forward<SinkFn>(sinkfn), results, buf, sep, more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(substr buf, Sep const& sep, Args const& ...args)
{
DumpResults results;
detail::catsep_dump_resume<sinkfn>(0u, &results, &buf, sep, args...);
return results;
}
template<class SinkFn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(SinkFn &&sinkfn, substr buf, Sep const& sep, Args const& ...args)
{
DumpResults results;
detail::catsep_dump_resume(0u, std::forward<SinkFn>(sinkfn), &results, &buf, sep, args...);
return results;
}
template<SinkPfn sinkfn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumpResults results, substr buf, Sep const& sep, Args const& ...args)
{
detail::catsep_dump_resume<sinkfn>(0u, &results, &buf, sep, args...);
return results;
}
template<class SinkFn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, Sep const& sep, Args const& ...args)
{
detail::catsep_dump_resume(0u, std::forward<SinkFn>(sinkfn), &results, &buf, sep, args...);
return results;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminate the recursion
C4_ALWAYS_INLINE size_t _format_dump_compute_size()
{
return 0u;
}
template<class T>
C4_ALWAYS_INLINE auto _format_dump_compute_size(T const&)
-> typename std::enable_if<dump_directly<T>::value, size_t>::type
{
return 0u; // no buffer needed
}
template<class T>
C4_ALWAYS_INLINE auto _format_dump_compute_size(T const& v)
-> typename std::enable_if<!dump_directly<T>::value, size_t>::type
{
return to_chars(substr{}, v);
}
template<class Arg, class... Args>
size_t _format_dump_compute_size(Arg const& a, Args const& ...more)
{
const size_t sz = _format_dump_compute_size(a); // don't call to_chars() directly
const size_t rest = _format_dump_compute_size(more...);
return sz > rest ? sz : rest;
}
} // namespace detail
// terminate the recursion
template<class SinkFn>
C4_ALWAYS_INLINE size_t format_dump(SinkFn &&sinkfn, substr, csubstr fmt)
{
// we can dump without using buf, so no need to check it
std::forward<SinkFn>(sinkfn)(fmt);
return 0u;
}
// terminate the recursion
/** take the function pointer as a template argument */
template<SinkPfn sinkfn>
C4_ALWAYS_INLINE size_t format_dump(substr, csubstr fmt)
{
// we can dump without using buf, so no need to check it
sinkfn(fmt);
return 0u;
}
/// @endcond
/** take the function pointer as a function argument */
template<class SinkFn, class Arg, class... Args>
C4_NO_INLINE size_t format_dump(SinkFn &&sinkfn, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we can dump without using buf
// but we'll only dump if the buffer is ok
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_UNLIKELY(pos == csubstr::npos))
{
std::forward<SinkFn>(sinkfn)(fmt);
return 0u;
}
std::forward<SinkFn>(sinkfn)(fmt.first(pos)); // we can dump without using buf
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
pos = dump(std::forward<SinkFn>(sinkfn), buf, a); // reuse pos to get needed_size
// dump no more if the buffer was exhausted
size_t size_for_more;
if(C4_LIKELY(pos <= buf.len))
size_for_more = format_dump(std::forward<SinkFn>(sinkfn), buf, fmt, more...);
else
size_for_more = detail::_format_dump_compute_size(more...);
return size_for_more > pos ? size_for_more : pos;
}
/** take the function pointer as a template argument */
template<SinkPfn sinkfn, class Arg, class... Args>
C4_NO_INLINE size_t format_dump(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& ...more)
{
// we can dump without using buf
// but we'll only dump if the buffer is ok
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_UNLIKELY(pos == csubstr::npos))
{
sinkfn(fmt);
return 0u;
}
sinkfn(fmt.first(pos)); // we can dump without using buf
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
pos = dump<sinkfn>(buf, a); // reuse pos to get needed_size
// dump no more if the buffer was exhausted
size_t size_for_more;
if(C4_LIKELY(pos <= buf.len))
size_for_more = format_dump<sinkfn>(buf, fmt, more...);
else
size_for_more = detail::_format_dump_compute_size(more...);
return size_for_more > pos ? size_for_more : pos;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminate the recursion
template<SinkPfn sinkfn>
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr, csubstr fmt)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
// we can dump without using buf
sinkfn(fmt);
results.lastok = currarg;
}
return results;
}
// terminate the recursion
template<class SinkFn>
DumpResults format_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr, csubstr fmt)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
// we can dump without using buf
std::forward<SinkFn>(sinkfn)(fmt);
results.lastok = currarg;
}
return results;
}
template<SinkPfn sinkfn, class Arg, class... Args>
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we need to process the format even if we're not
// going to print the first arguments because we're resuming
const size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_LIKELY(pos != csubstr::npos))
{
if(C4_LIKELY(results.write_arg(currarg)))
{
sinkfn(fmt.first(pos));
results.lastok = currarg;
}
if(C4_LIKELY(results.write_arg(currarg + 1u)))
{
const size_t len = dump<sinkfn>(buf, a);
results.bufsize = len > results.bufsize ? len : results.bufsize;
if(C4_LIKELY(len <= buf.len))
{
results.lastok = currarg + 1u;
}
else
{
const size_t rest = _format_dump_compute_size(more...);
results.bufsize = rest > results.bufsize ? rest : results.bufsize;
return results;
}
}
}
else
{
if(C4_LIKELY(results.write_arg(currarg)))
{
sinkfn(fmt);
results.lastok = currarg;
}
return results;
}
// NOTE: sparc64 had trouble with reassignment to fmt, and
// was passing the original fmt to the recursion:
//fmt = fmt.sub(pos + 2); // DONT!
return detail::format_dump_resume<sinkfn>(currarg + 2u, results, buf, fmt.sub(pos + 2), more...);
}
template<class SinkFn, class Arg, class... Args>
DumpResults format_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we need to process the format even if we're not
// going to print the first arguments because we're resuming
const size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_LIKELY(pos != csubstr::npos))
{
if(C4_LIKELY(results.write_arg(currarg)))
{
std::forward<SinkFn>(sinkfn)(fmt.first(pos));
results.lastok = currarg;
}
if(C4_LIKELY(results.write_arg(currarg + 1u)))
{
const size_t len = dump(std::forward<SinkFn>(sinkfn), buf, a);
results.bufsize = len > results.bufsize ? len : results.bufsize;
if(C4_LIKELY(len <= buf.len))
{
results.lastok = currarg + 1u;
}
else
{
const size_t rest = _format_dump_compute_size(more...);
results.bufsize = rest > results.bufsize ? rest : results.bufsize;
return results;
}
}
}
else
{
if(C4_LIKELY(results.write_arg(currarg)))
{
std::forward<SinkFn>(sinkfn)(fmt);
results.lastok = currarg;
}
return results;
}
// NOTE: sparc64 had trouble with reassignment to fmt, and
// was passing the original fmt to the recursion:
//fmt = fmt.sub(pos + 2); // DONT!
return detail::format_dump_resume(currarg + 2u, std::forward<SinkFn>(sinkfn), results, buf, fmt.sub(pos + 2), more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume<sinkfn>(0u, DumpResults{}, buf, fmt, args...);
}
template<class SinkFn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(SinkFn &&sinkfn, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume(0u, std::forward<SinkFn>(sinkfn), DumpResults{}, buf, fmt, args...);
}
template<SinkPfn sinkfn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(DumpResults results, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume<sinkfn>(0u, results, buf, fmt, args...);
}
template<class SinkFn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume(0u, std::forward<SinkFn>(sinkfn), results, buf, fmt, args...);
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
#endif /* C4_DUMP_HPP_ */
-440
View File
@@ -1,440 +0,0 @@
#ifndef _C4_ERROR_HPP_
#define _C4_ERROR_HPP_
/** @file error.hpp Facilities for error reporting and runtime assertions. */
/** @defgroup error_checking Error checking */
#include "c4/config.hpp"
#ifdef _DOXYGEN_
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
* will throw an exception
* @ingroup error_checking */
# define C4_EXCEPTIONS_ENABLED
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
* will throw an exception
* @see C4_EXCEPTIONS_ENABLED
* @ingroup error_checking */
# define C4_ERROR_THROWS_EXCEPTION
/** evaluates to noexcept when C4_ERROR might be called and
* exceptions are disabled. Otherwise, defaults to nothing.
* @ingroup error_checking */
# define C4_NOEXCEPT
#endif // _DOXYGEN_
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
# define C4_NOEXCEPT
#else
# define C4_NOEXCEPT noexcept
#endif
namespace c4 {
namespace detail {
struct fail_type__ {};
} // detail
} // c4
#define C4_STATIC_ERROR(dummy_type, errmsg) \
static_assert(std::is_same<dummy_type, c4::detail::fail_type__>::value, errmsg)
//-----------------------------------------------------------------------------
#define C4_ASSERT_SAME_TYPE(ty1, ty2) \
C4_STATIC_ASSERT(std::is_same<ty1 C4_COMMA_X ty2>::value)
#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \
C4_STATIC_ASSERT( ! std::is_same<ty1 C4_COMMA_X ty2>::value)
//-----------------------------------------------------------------------------
#ifdef _DOXYGEN_
/** utility macro that triggers a breakpoint when
* the debugger is attached and NDEBUG is not defined.
* @ingroup error_checking */
# define C4_DEBUG_BREAK()
#endif // _DOXYGEN_
#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
# define C4_DEBUG_BREAK()
#else
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wundef"
# if !defined(__APPLE_CC__)
# if __clang_major__ >= 10
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
# endif
# else
# if __clang_major__ >= 13
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
# endif
# endif
# elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wundef"
# endif
# include <c4/ext/debugbreak/debugbreak.h>
# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }
# ifdef __clang__
# pragma clang diagnostic pop
# elif defined(__GNUC__)
# pragma GCC diagnostic pop
# endif
#endif
namespace c4 {
C4CORE_EXPORT bool is_debugger_attached();
} // namespace c4
//-----------------------------------------------------------------------------
#ifdef __clang__
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
* clang requires switching off compiler warnings for pedantic mode.
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
/* GCC also issues a warning for zero-args calls to variadic macros.
* This warning is switched on with -pedantic and apparently there is no
* easy way to turn it off as with clang. But marking this as a system
* header works.
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
* @see http://stackoverflow.com/questions/35587137/ */
# pragma GCC system_header
#endif
//-----------------------------------------------------------------------------
namespace c4 {
typedef enum : uint32_t {
/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().
* Without effect otherwise. */
ON_ERROR_DEBUGBREAK = 0x01u << 0u,
/** when an error happens log a message. */
ON_ERROR_LOG = 0x01u << 1u,
/** when an error happens invoke a callback if it was set with
* set_error_callback(). */
ON_ERROR_CALLBACK = 0x01u << 2u,
/** when an error happens call std::terminate(). */
ON_ERROR_ABORT = 0x01u << 3u,
/** when an error happens and exceptions are enabled throw an exception.
* Without effect otherwise. */
ON_ERROR_THROW = 0x01u << 4u,
/** the default flags. */
ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT
} ErrorFlags_e;
using error_flags = uint32_t;
C4CORE_EXPORT void set_error_flags(error_flags f);
C4CORE_EXPORT error_flags get_error_flags();
using error_callback_type = void (*)(const char* msg, size_t msg_size);
C4CORE_EXPORT void set_error_callback(error_callback_type cb);
C4CORE_EXPORT error_callback_type get_error_callback();
//-----------------------------------------------------------------------------
/** RAII class controling the error settings inside a scope. */
struct ScopedErrorSettings // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
{
error_flags m_flags;
error_callback_type m_callback;
explicit ScopedErrorSettings(error_callback_type cb)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_callback(cb);
}
explicit ScopedErrorSettings(error_flags flags)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_flags(flags);
}
explicit ScopedErrorSettings(error_flags flags, error_callback_type cb)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_flags(flags);
set_error_callback(cb);
}
~ScopedErrorSettings()
{
set_error_flags(m_flags);
set_error_callback(m_callback);
}
};
//-----------------------------------------------------------------------------
/** source location */
struct srcloc;
// watchout: for VS the [[noreturn]] needs to come before other annotations like C4CORE_EXPORT
[[noreturn]] C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);
# define C4_ERROR(msg, ...) \
do { \
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
{ \
C4_DEBUG_BREAK() \
} \
c4::handle_error(C4_SRCLOC(), msg, ## __VA_ARGS__); \
} while(0)
# define C4_WARNING(msg, ...) \
c4::handle_warning(C4_SRCLOC(), msg, ## __VA_ARGS__)
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
struct srcloc
{
const char *file = "";
const char *func = "";
int line = 0;
};
#define C4_SRCLOC() c4::srcloc{__FILE__, C4_PRETTY_FUNC, __LINE__}
#elif defined(C4_ERROR_SHOWS_FILELINE)
struct srcloc
{
const char *file;
int line;
};
#define C4_SRCLOC() c4::srcloc{__FILE__, __LINE__}
#elif ! defined(C4_ERROR_SHOWS_FUNC)
struct srcloc
{
};
#define C4_SRCLOC() c4::srcloc()
#else
# error not implemented
#endif
//-----------------------------------------------------------------------------
// assertions
// Doxygen needs this so that only one definition counts
#ifdef _DOXYGEN_
/** Explicitly enables assertions, independently of NDEBUG status.
* This is meant to allow enabling assertions even when NDEBUG is defined.
* Defaults to undefined.
* @ingroup error_checking */
# define C4_USE_ASSERT
/** assert that a condition is true; this is turned off when NDEBUG
* is defined and C4_USE_ASSERT is not true.
* @ingroup error_checking */
# define C4_ASSERT
/** same as C4_ASSERT(), additionally prints a printf-formatted message
* @ingroup error_checking */
# define C4_ASSERT_MSG
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults
* to noexcept
* @ingroup error_checking */
# define C4_NOEXCEPT_A
#endif // _DOXYGEN_
#ifndef C4_USE_ASSERT
# ifdef NDEBUG
# define C4_USE_ASSERT 0
# else
# define C4_USE_ASSERT 1
# endif
#endif
#if C4_USE_ASSERT
# define C4_ASSERT(cond) C4_CHECK(cond)
# define C4_ASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
# define C4_ASSERT_IF(predicate, cond) if(predicate) { C4_ASSERT(cond); }
# define C4_NOEXCEPT_A C4_NOEXCEPT
#else
# define C4_ASSERT(cond)
# define C4_ASSERT_MSG(cond, /*fmt, */...)
# define C4_ASSERT_IF(predicate, cond)
# define C4_NOEXCEPT_A noexcept
#endif
//-----------------------------------------------------------------------------
// extreme assertions
// Doxygen needs this so that only one definition counts
#ifdef _DOXYGEN_
/** Explicitly enables extreme assertions; this is meant to allow enabling
* assertions even when NDEBUG is defined. Defaults to undefined.
* @ingroup error_checking */
# define C4_USE_XASSERT
/** extreme assertion: can be switched off independently of
* the regular assertion; use for example for bounds checking in hot code.
* Turned on only when C4_USE_XASSERT is defined
* @ingroup error_checking */
# define C4_XASSERT
/** same as C4_XASSERT(), and additionally prints a printf-formatted message
* @ingroup error_checking */
# define C4_XASSERT_MSG
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults to noexcept
* @ingroup error_checking */
# define C4_NOEXCEPT_X
#endif // _DOXYGEN_
#ifndef C4_USE_XASSERT
# define C4_USE_XASSERT C4_USE_ASSERT
#endif
#if C4_USE_XASSERT
# define C4_XASSERT(cond) C4_CHECK(cond)
# define C4_XASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
# define C4_XASSERT_IF(predicate, cond) if(predicate) { C4_XASSERT(cond); }
# define C4_NOEXCEPT_X C4_NOEXCEPT
#else
# define C4_XASSERT(cond)
# define C4_XASSERT_MSG(cond, /*fmt, */...)
# define C4_XASSERT_IF(predicate, cond)
# define C4_NOEXCEPT_X noexcept
#endif
//-----------------------------------------------------------------------------
// checks: never switched-off
/** Check that a condition is true, or raise an error when not
* true. Unlike C4_ASSERT(), this check is not disabled in non-debug
* builds.
* @see C4_ASSERT
* @ingroup error_checking
*
* @todo add constexpr-compatible compile-time assert:
* https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
*/
#define C4_CHECK(cond) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
C4_ERROR("check failed: %s", #cond); \
} \
} while(0)
/** like C4_CHECK(), and additionally log a printf-style message.
* @see C4_CHECK
* @ingroup error_checking */
#define C4_CHECK_MSG(cond, fmt, ...) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
C4_ERROR("check failed: " #cond "\n" fmt, ## __VA_ARGS__); \
} \
} while(0)
//-----------------------------------------------------------------------------
// Common error conditions
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
#define C4_NOT_IMPLEMENTED_MSG(/*msg, */...) C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__)
#define C4_NOT_IMPLEMENTED_IF(condition) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); } } while(0)
#define C4_NOT_IMPLEMENTED_IF_MSG(condition, /*msg, */...) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__); } } while(0)
#define C4_NEVER_REACH() do { C4_ERROR("never reach this point"); C4_UNREACHABLE(); } while(0)
#define C4_NEVER_REACH_MSG(/*msg, */...) do { C4_ERROR("never reach this point: " __VA_ARGS__); C4_UNREACHABLE(); } while(0)
//-----------------------------------------------------------------------------
// helpers for warning suppression
// idea adapted from https://github.com/onqtam/doctest/
// TODO: add C4_MESSAGE() https://stackoverflow.com/questions/18252351/custom-preprocessor-macro-for-a-conditional-pragma-message-xxx?rq=1
#ifdef C4_MSVC
#define C4_SUPPRESS_WARNING_MSVC_PUSH __pragma(warning(push))
#define C4_SUPPRESS_WARNING_MSVC(w) __pragma(warning(disable : w))
#define C4_SUPPRESS_WARNING_MSVC_POP __pragma(warning(pop))
#else // C4_MSVC
#define C4_SUPPRESS_WARNING_MSVC_PUSH
#define C4_SUPPRESS_WARNING_MSVC(w)
#define C4_SUPPRESS_WARNING_MSVC_POP
#endif // C4_MSVC
#ifdef C4_CLANG
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
#define C4_SUPPRESS_WARNING_CLANG_PUSH _Pragma("clang diagnostic push")
#define C4_SUPPRESS_WARNING_CLANG(w) C4_PRAGMA_TO_STR(clang diagnostic ignored w)
#define C4_SUPPRESS_WARNING_CLANG_POP _Pragma("clang diagnostic pop")
#else // C4_CLANG
#define C4_SUPPRESS_WARNING_CLANG_PUSH
#define C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_CLANG_POP
#endif // C4_CLANG
#ifdef C4_GCC
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
#define C4_SUPPRESS_WARNING_GCC_PUSH _Pragma("GCC diagnostic push")
#define C4_SUPPRESS_WARNING_GCC(w) C4_PRAGMA_TO_STR(GCC diagnostic ignored w)
#define C4_SUPPRESS_WARNING_GCC_POP _Pragma("GCC diagnostic pop")
#else // C4_GCC
#define C4_SUPPRESS_WARNING_GCC_PUSH
#define C4_SUPPRESS_WARNING_GCC(w)
#define C4_SUPPRESS_WARNING_GCC_POP
#endif // C4_GCC
#define C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_MSVC_PUSH \
C4_SUPPRESS_WARNING_MSVC(w)
#define C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_CLANG_PUSH \
C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_GCC_PUSH \
C4_SUPPRESS_WARNING_GCC(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_PUSH \
C4_SUPPRESS_WARNING_GCC_PUSH \
C4_SUPPRESS_WARNING_CLANG_PUSH
#define C4_SUPPRESS_WARNING_GCC_CLANG(w) \
C4_SUPPRESS_WARNING_GCC(w) \
C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_POP \
C4_SUPPRESS_WARNING_GCC_POP \
C4_SUPPRESS_WARNING_CLANG_POP
} // namespace c4
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif /* _C4_ERROR_HPP_ */
-18
View File
@@ -1,18 +0,0 @@
#ifndef C4_EXPORT_HPP_
#define C4_EXPORT_HPP_
#ifdef _WIN32
#ifdef C4CORE_SHARED
#ifdef C4CORE_EXPORTS
#define C4CORE_EXPORT __declspec(dllexport)
#else
#define C4CORE_EXPORT __declspec(dllimport)
#endif
#else
#define C4CORE_EXPORT
#endif
#else
#define C4CORE_EXPORT
#endif
#endif /* C4CORE_EXPORT_HPP_ */
File diff suppressed because it is too large Load Diff
-358
View File
@@ -1,358 +0,0 @@
#ifndef _C4_LANGUAGE_HPP_
#define _C4_LANGUAGE_HPP_
/** @file language.hpp Provides language standard information macros and
* compiler agnostic utility macros: namespace facilities, function attributes,
* variable attributes, etc.
* @ingroup basic_headers */
#include "c4/preprocessor.hpp"
#include "c4/compiler.hpp"
/* Detect C++ standard.
* @see http://stackoverflow.com/a/7132549/5875572 */
#ifndef C4_CPP
# if defined(_MSC_VER) && !defined(__clang__)
# if _MSC_VER >= 1910 // >VS2015: VS2017, VS2019, VS2022
# if (!defined(_MSVC_LANG))
# error _MSVC not defined
# endif
# if _MSVC_LANG >= 201705L
# define C4_CPP 20
# define C4_CPP20
# elif _MSVC_LANG == 201703L
# define C4_CPP 17
# define C4_CPP17
# elif _MSVC_LANG >= 201402L
# define C4_CPP 14
# define C4_CPP14
# elif _MSVC_LANG >= 201103L
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# else
# if _MSC_VER == 1900
# define C4_CPP 14 // VS2015 is c++14 https://devblogs.microsoft.com/cppblog/c111417-features-in-vs-2015-rtm/
# define C4_CPP14
# elif _MSC_VER == 1800 // VS2013
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# endif
# elif defined(__INTEL_COMPILER) // https://software.intel.com/en-us/node/524490
# ifdef __INTEL_CXX20_MODE__ // not sure about this
# define C4_CPP 20
# define C4_CPP20
# elif defined __INTEL_CXX17_MODE__ // not sure about this
# define C4_CPP 17
# define C4_CPP17
# elif defined __INTEL_CXX14_MODE__ // not sure about this
# define C4_CPP 14
# define C4_CPP14
# elif defined __INTEL_CXX11_MODE__
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# else
# ifndef __cplusplus
# error __cplusplus is not defined?
# endif
# if __cplusplus == 1
# error cannot handle __cplusplus==1
# elif __cplusplus >= 201709L
# define C4_CPP 20
# define C4_CPP20
# elif __cplusplus >= 201703L
# define C4_CPP 17
# define C4_CPP17
# elif __cplusplus >= 201402L
# define C4_CPP 14
# define C4_CPP14
# elif __cplusplus >= 201103L
# define C4_CPP 11
# define C4_CPP11
# elif __cplusplus >= 199711L
# error C++ lesser than C++11 not supported
# endif
# endif
#else
# ifdef C4_CPP == 20
# define C4_CPP20
# elif C4_CPP == 17
# define C4_CPP17
# elif C4_CPP == 14
# define C4_CPP14
# elif C4_CPP == 11
# define C4_CPP11
# elif C4_CPP == 98
# define C4_CPP98
# error C++ lesser than C++11 not supported
# else
# error C4_CPP must be one of 20, 17, 14, 11, 98
# endif
#endif
#ifdef C4_CPP20
# define C4_CPP17
# define C4_CPP14
# define C4_CPP11
#elif defined(C4_CPP17)
# define C4_CPP14
# define C4_CPP11
#elif defined(C4_CPP14)
# define C4_CPP11
#endif
/** lifted from this answer: http://stackoverflow.com/a/20170989/5875572 */
#if defined(_MSC_VER) && !defined(__clang__)
# if _MSC_VER < 1900
# define C4_CONSTEXPR11
# define C4_CONSTEXPR14
# elif _MSC_VER < 2000
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14
# else
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14 constexpr
# endif
#else
# if __cplusplus < 201103
# define C4_CONSTEXPR11
# define C4_CONSTEXPR14
# elif __cplusplus == 201103
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14
# else
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14 constexpr
# endif
#endif // _MSC_VER
#if C4_CPP < 17
#define C4_IF_CONSTEXPR
#define C4_INLINE_CONSTEXPR constexpr
#else
#define C4_IF_CONSTEXPR constexpr
#define C4_INLINE_CONSTEXPR inline constexpr
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# if (defined(_CPPUNWIND) && (_CPPUNWIND == 1))
# define C4_EXCEPTIONS
# endif
#else
# if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
# define C4_EXCEPTIONS
# endif
#endif
#ifdef C4_EXCEPTIONS
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) exc_code
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { exc_code } while(0)
#else
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) setjmp_code
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { setjmp_code } while(0)
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# if defined(_CPPRTTI)
# define C4_RTTI
# endif
#else
# if defined(__GXX_RTTI)
# define C4_RTTI
# endif
#endif
#ifdef C4_RTTI
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_rtti
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_rtti } while(0)
#else
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_no_rtti
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_no_rtti } while(0)
#endif
//------------------------------------------------------------
#define _C4_BEGIN_NAMESPACE(ns) namespace ns {
#define _C4_END_NAMESPACE(ns) }
// MSVC cant handle the C4_FOR_EACH macro... need to fix this
//#define C4_BEGIN_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_BEGIN_NAMESPACE, , __VA_ARGS__)
//#define C4_END_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_END_NAMESPACE, , __VA_ARGS__)
#define C4_BEGIN_NAMESPACE(ns) namespace ns {
#define C4_END_NAMESPACE(ns) }
#define C4_BEGIN_HIDDEN_NAMESPACE namespace /*hidden*/ {
#define C4_END_HIDDEN_NAMESPACE } /* namespace hidden */
//------------------------------------------------------------
#ifndef C4_API
# if defined(_MSC_VER) && !defined(__clang__)
# if defined(C4_EXPORT)
# define C4_API __declspec(dllexport)
# elif defined(C4_IMPORT)
# define C4_API __declspec(dllimport)
# else
# define C4_API
# endif
# else
# define C4_API
# endif
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_RESTRICT __restrict
# define C4_RESTRICT_FN __declspec(restrict)
# define C4_NO_INLINE __declspec(noinline)
# define C4_ALWAYS_INLINE inline __forceinline
/** these are not available in VS AFAIK */
# define C4_CONST
# define C4_PURE
# define C4_FLATTEN
# define C4_HOT /** @todo */
# define C4_COLD /** @todo */
# define C4_ASSUME(...) __assume(__VA_ARGS__)
# define C4_EXPECT(x, y) x /** @todo */
# define C4_LIKELY(x) x
# define C4_UNLIKELY(x) x
# define C4_UNREACHABLE() _c4_msvc_unreachable()
# define C4_ATTR_FORMAT(...) /** */
# define C4_NORETURN [[noreturn]]
# if _MSC_VER >= 1700 // VS2012
# define C4_NODISCARD _Check_return_
# else
# define C4_NODISCARD
# endif
[[noreturn]] __forceinline void _c4_msvc_unreachable() { __assume(false); } ///< https://stackoverflow.com/questions/60802864/emulating-gccs-builtin-unreachable-in-visual-studio
# define C4_UNREACHABLE_AFTER_ERR() /* */
#else
///< @todo assuming gcc-like compiler. check it is actually so.
/** for function attributes in GCC,
* @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes */
/** for __builtin functions in GCC,
* @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */
# define C4_RESTRICT __restrict__
# define C4_RESTRICT_FN __attribute__((restrict))
# define C4_NO_INLINE __attribute__((noinline))
# define C4_ALWAYS_INLINE inline __attribute__((always_inline))
# define C4_CONST __attribute__((const))
# define C4_PURE __attribute__((pure))
/** force inlining of every callee function */
# define C4_FLATTEN __atribute__((flatten))
/** mark a function as hot, ie as having a visible impact in CPU time
* thus making it more likely to inline, etc
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
# define C4_HOT __attribute__((hot))
/** mark a function as cold, ie as NOT having a visible impact in CPU time
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
# define C4_COLD __attribute__((cold))
# define C4_EXPECT(x, y) __builtin_expect(x, y) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
# define C4_LIKELY(x) __builtin_expect(x, 1)
# define C4_UNLIKELY(x) __builtin_expect(x, 0)
# define C4_UNREACHABLE() __builtin_unreachable()
# define C4_ATTR_FORMAT(...) //__attribute__((format (__VA_ARGS__))) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
# define C4_NORETURN __attribute__((noreturn))
# define C4_NODISCARD __attribute__((warn_unused_result))
# define C4_UNREACHABLE_AFTER_ERR() C4_UNREACHABLE()
// C4_ASSUME
// see https://stackoverflow.com/questions/63493968/reproducing-clangs-builtin-assume-for-gcc
// preferred option: C++ standard attribute
# ifdef __has_cpp_attribute
# if __has_cpp_attribute(assume) >= 202207L
# define C4_ASSUME(...) [[assume(__VA_ARGS__)]]
# endif
# endif
// first fallback: compiler intrinsics/attributes for assumptions
# ifndef C4_ASSUME
# if defined(__clang__)
# define C4_ASSUME(...) __builtin_assume(__VA_ARGS__)
# elif defined(__GNUC__)
# if __GNUC__ >= 13
# define C4_ASSUME(...) __attribute__((__assume__(__VA_ARGS__)))
# endif
# endif
# endif
// second fallback: possibly evaluating uses of unreachable()
// Set this to 1 if you want to allow assumptions to possibly evaluate.
# ifndef C4_ASSUME_ALLOW_EVAL
# define C4_ASSUME_ALLOW_EVAL 0
# endif
# if !defined(C4_ASSUME) && (C4_ASSUME_ALLOW_EVAL)
# define C4_ASSUME(...) do { if (!bool(__VA_ARGS__)) C4_UNREACHABLE(); ) while(0)
# endif
// last fallback: define macro as doing nothing
# ifndef C4_ASSUME
# define C4_ASSUME(...)
# endif
#endif
#if C4_CPP >= 14
# define C4_DEPRECATED(msg) [[deprecated(msg)]]
#else
# if defined(_MSC_VER)
# define C4_DEPRECATED(msg) __declspec(deprecated(msg))
# else // defined(__GNUC__) || defined(__clang__)
# define C4_DEPRECATED(msg) __attribute__((deprecated(msg)))
# endif
#endif
#ifdef _MSC_VER
# define C4_FUNC __FUNCTION__
# define C4_PRETTY_FUNC __FUNCSIG__
#else /// @todo assuming gcc-like compiler. check it is actually so.
# define C4_FUNC __FUNCTION__
# define C4_PRETTY_FUNC __PRETTY_FUNCTION__
#endif
/** prevent compiler warnings about a specific var being unused */
#define C4_UNUSED(var) (void)var
#if C4_CPP >= 17
#define C4_STATIC_ASSERT(cond) static_assert(cond)
#else
#define C4_STATIC_ASSERT(cond) static_assert((cond), #cond)
#endif
#define C4_STATIC_ASSERT_MSG(cond, msg) static_assert((cond), #cond ": " msg)
/** @def C4_DONT_OPTIMIZE idea lifted from GoogleBenchmark.
* @see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark_api.h */
namespace c4 {
namespace detail {
#ifdef __GNUC__
# define C4_DONT_OPTIMIZE(var) c4::detail::dont_optimize(var)
template< class T >
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); } // NOLINT
#else
# define C4_DONT_OPTIMIZE(var) c4::detail::use_char_pointer(reinterpret_cast< const char* >(&var))
void use_char_pointer(char const volatile*);
#endif
} // namespace detail
} // namespace c4
/** @def C4_KEEP_EMPTY_LOOP prevent an empty loop from being optimized out.
* @see http://stackoverflow.com/a/7084193/5875572 */
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_KEEP_EMPTY_LOOP { char c; C4_DONT_OPTIMIZE(c); }
#else
# define C4_KEEP_EMPTY_LOOP { asm(""); }
#endif
/** @def C4_VA_LIST_REUSE_MUST_COPY
* @todo <jpmag> I strongly suspect that this is actually only in UNIX platforms. revisit this. */
#ifdef __GNUC__
# define C4_VA_LIST_REUSE_MUST_COPY
#endif
#endif /* _C4_LANGUAGE_HPP_ */
-782
View File
@@ -1,782 +0,0 @@
#ifndef _C4_MEMORY_UTIL_HPP_
#define _C4_MEMORY_UTIL_HPP_
#include "c4/config.hpp"
#include "c4/error.hpp"
#include "c4/compiler.hpp"
#include "c4/cpu.hpp"
#ifdef C4_MSVC
#include <intrin.h>
#endif
#include <string.h>
#if (defined(__GNUC__) && __GNUC__ >= 10) || defined(__has_builtin)
#define _C4_USE_LSB_INTRINSIC(which) __has_builtin(which)
#define _C4_USE_MSB_INTRINSIC(which) __has_builtin(which)
#elif defined(C4_MSVC)
#define _C4_USE_LSB_INTRINSIC(which) true
#define _C4_USE_MSB_INTRINSIC(which) true
#else
// let's try our luck
#define _C4_USE_LSB_INTRINSIC(which) true
#define _C4_USE_MSB_INTRINSIC(which) true
#endif
/** @file memory_util.hpp Some memory utilities. */
// NOLINTBEGIN(google-runtime-int)
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
/** set the given memory to zero */
C4_ALWAYS_INLINE void mem_zero(void* mem, size_t num_bytes)
{
memset(mem, 0, num_bytes);
}
/** set the given memory to zero */
template<class T>
C4_ALWAYS_INLINE void mem_zero(T* mem, size_t num_elms)
{
memset(mem, 0, sizeof(T) * num_elms);
}
/** set the given memory to zero */
template<class T>
C4_ALWAYS_INLINE void mem_zero(T* mem)
{
memset(mem, 0, sizeof(T));
}
C4_ALWAYS_INLINE C4_CONST bool mem_overlaps(void const* a, void const* b, size_t sza, size_t szb)
{
// thanks @timwynants
return (((const char*)b + szb) > a && b < ((const char*)a+sza));
}
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template<class T>
C4_ALWAYS_INLINE C4_CONST bool is_aligned(T *ptr, uintptr_t alignment=alignof(T))
{
return (uintptr_t(ptr) & (alignment - uintptr_t(1))) == uintptr_t(0);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// least significant bit
/** @name msb Compute the least significant bit
* @note the input value must be nonzero
* @note the input type must be unsigned
*/
/** @{ */
// https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
#define _c4_lsb_fallback \
unsigned c = 0; \
v = (v ^ (v - 1)) >> 1; /* Set v's trailing 0s to 1s and zero rest */ \
for(; v; ++c) \
v >>= 1; \
return (unsigned) c
// u8
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
// upcast to use the intrinsic, it's cheaper.
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, (unsigned long)v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u16
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, (unsigned long)v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u32
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u64 in 64bits
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzl)
#if defined(C4_MSVC)
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward64(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctzl((unsigned long)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u64 in 32bits
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzll)
#if defined(C4_MSVC)
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward64(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctzll((unsigned long long)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
#undef _c4_lsb_fallback
/** @} */
namespace detail {
template<class I, I val, unsigned num_bits, bool finished> struct _lsb11;
template<class I, I val, unsigned num_bits>
struct _lsb11<I, val, num_bits, false>
{
enum : unsigned { num = _lsb11<I, (val>>1), num_bits+I(1), (((val>>1)&I(1))!=I(0))>::num };
};
template<class I, I val, unsigned num_bits>
struct _lsb11<I, val, num_bits, true>
{
enum : unsigned { num = num_bits };
};
} // namespace detail
/** TMP version of lsb(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see lsb */
template<class I, I number>
struct lsb11
{
static_assert(number != 0, "lsb: number must be nonzero");
enum : unsigned { value = detail::_lsb11<I, number, 0, ((number&I(1))!=I(0))>::num};
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// most significant bit
/** @name msb Compute the most significant bit
* @note the input value must be nonzero
* @note the input type must be unsigned
*/
/** @{ */
#define _c4_msb8_fallback \
unsigned n = 0; \
if(v & I(0xf0)) v >>= 4, n |= I(4); \
if(v & I(0x0c)) v >>= 2, n |= I(2); \
if(v & I(0x02)) v >>= 1, n |= I(1); \
return n
#define _c4_msb16_fallback \
unsigned n = 0; \
if(v & I(0xff00)) v >>= 8, n |= I(8); \
if(v & I(0x00f0)) v >>= 4, n |= I(4); \
if(v & I(0x000c)) v >>= 2, n |= I(2); \
if(v & I(0x0002)) v >>= 1, n |= I(1); \
return n
#define _c4_msb32_fallback \
unsigned n = 0; \
if(v & I(0xffff0000)) v >>= 16, n |= 16; \
if(v & I(0x0000ff00)) v >>= 8, n |= 8; \
if(v & I(0x000000f0)) v >>= 4, n |= 4; \
if(v & I(0x0000000c)) v >>= 2, n |= 2; \
if(v & I(0x00000002)) v >>= 1, n |= 1; \
return n
#define _c4_msb64_fallback \
unsigned n = 0; \
if(v & I(0xffffffff00000000)) v >>= 32, n |= I(32); \
if(v & I(0x00000000ffff0000)) v >>= 16, n |= I(16); \
if(v & I(0x000000000000ff00)) v >>= 8, n |= I(8); \
if(v & I(0x00000000000000f0)) v >>= 4, n |= I(4); \
if(v & I(0x000000000000000c)) v >>= 2, n |= I(2); \
if(v & I(0x0000000000000002)) v >>= 1, n |= I(1); \
return n
// u8
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, (unsigned long)v);
return bit;
#else
_c4_msb8_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb8_fallback;
#endif
}
// u16
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, (unsigned long)v);
return bit;
#else
_c4_msb16_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb16_fallback;
#endif
}
// u32
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, v);
return bit;
#else
_c4_msb32_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb32_fallback;
#endif
}
// u64 in 64bits
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clzl)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse64(&bit, v);
return bit;
#else
_c4_msb64_fallback;
#endif
#else
return 63u - (unsigned)__builtin_clzl((unsigned long)v);
#endif
#else
_c4_msb64_fallback;
#endif
}
// u64 in 32bits
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clzll)
#ifdef C4_MSVC
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse64(&bit, v);
return bit;
#else
_c4_msb64_fallback;
#endif
#else
return 63u - (unsigned)__builtin_clzll((unsigned long long)v);
#endif
#else
_c4_msb64_fallback;
#endif
}
#undef _c4_msb8_fallback
#undef _c4_msb16_fallback
#undef _c4_msb32_fallback
#undef _c4_msb64_fallback
/** @} */
namespace detail {
template<class I, I val, I num_bits, bool finished> struct _msb11;
template<class I, I val, I num_bits>
struct _msb11< I, val, num_bits, false>
{
enum : unsigned { num = _msb11<I, (val>>1), num_bits+I(1), ((val>>1)==I(0))>::num };
};
template<class I, I val, I num_bits>
struct _msb11<I, val, num_bits, true>
{
static_assert(val == 0, "bad implementation");
enum : unsigned { num = (unsigned)(num_bits-1) };
};
} // namespace detail
/** TMP version of msb(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see msb */
template<class I, I number>
struct msb11
{
enum : unsigned { value = detail::_msb11<I, number, 0, (number==I(0))>::num };
};
#undef _C4_USE_LSB_INTRINSIC
#undef _C4_USE_MSB_INTRINSIC
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// there is an implicit conversion below; it happens when E or B are
// narrower than int, and thus any operation will upcast the result to
// int, and then downcast to assign
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wconversion")
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= base;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= base;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, B base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= base;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= base;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class Base, Base base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
B bbase = B(base);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= bbase;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= bbase;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
for(E e = 0; e < exponent; ++e)
r *= base;
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, B base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
for(E e = 0; e < exponent; ++e)
r *= base;
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class Base, Base base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
B bbase = B(base);
for(E e = 0; e < exponent; ++e)
r *= bbase;
return r;
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** return a mask with all bits set [first_bit,last_bit[; this function
* is constexpr-14 because of the local variables */
template<class I>
C4_CONSTEXPR14 I contiguous_mask(I first_bit, I last_bit)
{
I r = 0;
for(I i = first_bit; i < last_bit; ++i)
{
r |= (I(1) << i);
}
return r;
}
namespace detail {
template<class I, I val, I first, I last, bool finished>
struct _ctgmsk11;
template<class I, I val, I first, I last>
struct _ctgmsk11< I, val, first, last, true>
{
enum : I { value = _ctgmsk11<I, val|(I(1)<<first), first+I(1), last, (first+1!=last)>::value };
};
template<class I, I val, I first, I last>
struct _ctgmsk11< I, val, first, last, false>
{
enum : I { value = val };
};
} // namespace detail
/** TMP version of contiguous_mask(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see contiguous_mask */
template<class I, I first_bit, I last_bit>
struct contiguous_mask11
{
enum : I { value = detail::_ctgmsk11<I, I(0), first_bit, last_bit, (first_bit!=last_bit)>::value };
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** use Empty Base Class Optimization to reduce the size of a pair of
* potentially empty types*/
namespace detail {
typedef enum {
tpc_same,
tpc_same_empty,
tpc_both_empty,
tpc_first_empty,
tpc_second_empty,
tpc_general
} TightPairCase_e;
template<class First, class Second>
constexpr TightPairCase_e tpc_which_case()
{
return std::is_same<First, Second>::value ?
std::is_empty<First>::value ?
tpc_same_empty
:
tpc_same
:
std::is_empty<First>::value && std::is_empty<Second>::value ?
tpc_both_empty
:
std::is_empty<First>::value ?
tpc_first_empty
:
std::is_empty<Second>::value ?
tpc_second_empty
:
tpc_general
;
}
template<class First, class Second, TightPairCase_e Case>
struct tight_pair
{
private:
First m_first;
Second m_second;
public:
using first_type = First;
using second_type = Second;
tight_pair() : m_first(), m_second() {}
tight_pair(First const& f, Second const& s) : m_first(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_same_empty> : public First
{
static_assert(std::is_same<First, Second>::value, "bad implementation");
using first_type = First;
using second_type = Second;
tight_pair() : First() {}
tight_pair(First const& f, Second const& /*s*/) : First(f) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); } // NOLINT
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); } // NOLINT
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_both_empty> : public First, public Second
{
using first_type = First;
using second_type = Second;
tight_pair() : First(), Second() {}
tight_pair(First const& f, Second const& s) : First(f), Second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_same> : public First
{
Second m_second;
using first_type = First;
using second_type = Second;
tight_pair() : First() {}
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_first_empty> : public First
{
Second m_second;
using first_type = First;
using second_type = Second;
tight_pair() : First(), m_second() {}
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_second_empty> : public Second
{
First m_first;
using first_type = First;
using second_type = Second;
tight_pair() : Second(), m_first() {}
tight_pair(First const& f, Second const& s) : Second(s), m_first(f) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
};
} // namespace detail
template<class First, class Second>
using tight_pair = detail::tight_pair<First, Second, detail::tpc_which_case<First,Second>()>;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
// NOLINTEND(google-runtime-int)
#endif /* _C4_MEMORY_UTIL_HPP_ */
-46
View File
@@ -1,46 +0,0 @@
#ifndef _C4_PLATFORM_HPP_
#define _C4_PLATFORM_HPP_
/** @file platform.hpp Provides platform information macros
* @ingroup basic_headers */
// see also https://sourceforge.net/p/predef/wiki/OperatingSystems/
#if defined(_WIN64)
# define C4_WIN
# define C4_WIN64
#elif defined(_WIN32)
# define C4_WIN
# define C4_WIN32
#elif defined(__ANDROID__)
# define C4_ANDROID
#elif defined(__APPLE__)
# include "TargetConditionals.h"
# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
# define C4_IOS
# elif TARGET_OS_MAC || TARGET_OS_OSX
# define C4_MACOS
# else
# error "Unknown Apple platform"
# endif
#elif defined(__linux__) || defined(__linux)
# define C4_UNIX
# define C4_LINUX
#elif defined(__unix__) || defined(__unix)
# define C4_UNIX
#elif defined(__arm__) || defined(__aarch64__)
# define C4_ARM
#elif defined(__xtensa__) || defined(__XTENSA__)
# define C4_XTENSA
#elif defined(SWIG)
# define C4_SWIG
#else
# error "unknown platform"
#endif
#if defined(__posix) || defined(C4_UNIX) || defined(C4_LINUX)
# define C4_POSIX
#endif
#endif /* _C4_PLATFORM_HPP_ */
-123
View File
@@ -1,123 +0,0 @@
#ifndef _C4_PREPROCESSOR_HPP_
#define _C4_PREPROCESSOR_HPP_
/** @file preprocessor.hpp Contains basic macros and preprocessor utilities.
* @ingroup basic_headers */
#ifdef __clang__
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
* clang requires switching off compiler warnings for pedantic mode.
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
/* GCC also issues a warning for zero-args calls to variadic macros.
* This warning is switched on with -pedantic and apparently there is no
* easy way to turn it off as with clang. But marking this as a system
* header works.
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
* @see http://stackoverflow.com/questions/35587137/ */
# pragma GCC system_header
#endif
#define C4_WIDEN(str) L"" str
#define C4_COUNTOF(arr) (sizeof(arr)/sizeof((arr)[0]))
#define C4_EXPAND(arg) arg
/** useful in some macro calls with template arguments */
#define C4_COMMA ,
/** useful in some macro calls with template arguments
* @see C4_COMMA */
#define C4_COMMA_X C4_COMMA
/** expand and quote */
#define C4_XQUOTE(arg) _C4_XQUOTE(arg)
#define _C4_XQUOTE(arg) C4_QUOTE(arg)
#define C4_QUOTE(arg) #arg
/** expand and concatenate */
#define C4_XCAT(arg1, arg2) _C4_XCAT(arg1, arg2)
#define _C4_XCAT(arg1, arg2) C4_CAT(arg1, arg2)
#define C4_CAT(arg1, arg2) arg1##arg2
#define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch))
/** A preprocessor foreach. Spectacular trick taken from:
* http://stackoverflow.com/a/1872506/5875572
* The first argument is for a macro receiving a single argument,
* which will be called with every subsequent argument. There is
* currently a limit of 32 arguments, and at least 1 must be provided.
*
Example:
@code{.cpp}
struct Example {
int a;
int b;
int c;
};
// define a one-arg macro to be called
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(Example, field)
#define PRN_STRUCT_OFFSETS_(structure, field) printf(C4_XQUOTE(structure) ":" C4_XQUOTE(field)" - offset=%zu\n", offsetof(structure, field));
// now call the macro for a, b and c
C4_FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
@endcode */
#define C4_FOR_EACH(what, ...) C4_FOR_EACH_SEP(what, ;, __VA_ARGS__)
/** same as C4_FOR_EACH(), but use a custom separator between statements.
* If a comma is needed as the separator, use the C4_COMMA macro.
* @see C4_FOR_EACH
* @see C4_COMMA
*/
#define C4_FOR_EACH_SEP(what, sep, ...) _C4_FOR_EACH_(_C4_FOR_EACH_NARG(__VA_ARGS__), what, sep, __VA_ARGS__)
/// @cond dev
#define _C4_FOR_EACH_01(what, sep, x) what(x) sep
#define _C4_FOR_EACH_02(what, sep, x, ...) what(x) sep _C4_FOR_EACH_01(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_03(what, sep, x, ...) what(x) sep _C4_FOR_EACH_02(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_04(what, sep, x, ...) what(x) sep _C4_FOR_EACH_03(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_05(what, sep, x, ...) what(x) sep _C4_FOR_EACH_04(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_06(what, sep, x, ...) what(x) sep _C4_FOR_EACH_05(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_07(what, sep, x, ...) what(x) sep _C4_FOR_EACH_06(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_08(what, sep, x, ...) what(x) sep _C4_FOR_EACH_07(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_09(what, sep, x, ...) what(x) sep _C4_FOR_EACH_08(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_10(what, sep, x, ...) what(x) sep _C4_FOR_EACH_09(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_11(what, sep, x, ...) what(x) sep _C4_FOR_EACH_10(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_12(what, sep, x, ...) what(x) sep _C4_FOR_EACH_11(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_13(what, sep, x, ...) what(x) sep _C4_FOR_EACH_12(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_14(what, sep, x, ...) what(x) sep _C4_FOR_EACH_13(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_15(what, sep, x, ...) what(x) sep _C4_FOR_EACH_14(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_16(what, sep, x, ...) what(x) sep _C4_FOR_EACH_15(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_17(what, sep, x, ...) what(x) sep _C4_FOR_EACH_16(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_18(what, sep, x, ...) what(x) sep _C4_FOR_EACH_17(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_19(what, sep, x, ...) what(x) sep _C4_FOR_EACH_18(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_20(what, sep, x, ...) what(x) sep _C4_FOR_EACH_19(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_21(what, sep, x, ...) what(x) sep _C4_FOR_EACH_20(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_22(what, sep, x, ...) what(x) sep _C4_FOR_EACH_21(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_23(what, sep, x, ...) what(x) sep _C4_FOR_EACH_22(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_24(what, sep, x, ...) what(x) sep _C4_FOR_EACH_23(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_25(what, sep, x, ...) what(x) sep _C4_FOR_EACH_24(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_26(what, sep, x, ...) what(x) sep _C4_FOR_EACH_25(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_27(what, sep, x, ...) what(x) sep _C4_FOR_EACH_26(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_28(what, sep, x, ...) what(x) sep _C4_FOR_EACH_27(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_29(what, sep, x, ...) what(x) sep _C4_FOR_EACH_28(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_30(what, sep, x, ...) what(x) sep _C4_FOR_EACH_29(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_31(what, sep, x, ...) what(x) sep _C4_FOR_EACH_30(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_32(what, sep, x, ...) what(x) sep _C4_FOR_EACH_31(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_NARG(...) _C4_FOR_EACH_NARG_(__VA_ARGS__, _C4_FOR_EACH_RSEQ_N())
#define _C4_FOR_EACH_NARG_(...) _C4_FOR_EACH_ARG_N(__VA_ARGS__)
#define _C4_FOR_EACH_ARG_N(_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...) N
#define _C4_FOR_EACH_RSEQ_N() 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01
#define _C4_FOR_EACH_(N, what, sep, ...) C4_XCAT(_C4_FOR_EACH_, N)(what, sep, __VA_ARGS__)
/// @endcond
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif /* _C4_PREPROCESSOR_HPP_ */
-11
View File
@@ -1,11 +0,0 @@
#ifndef _C4_STD_STD_HPP_
#define _C4_STD_STD_HPP_
/** @file std.hpp includes all c4-std interop files */
#include "c4/std/vector.hpp"
#include "c4/std/string.hpp"
#include "c4/std/string_view.hpp"
#include "c4/std/tuple.hpp"
#endif // _C4_STD_STD_HPP_
-10
View File
@@ -1,10 +0,0 @@
#ifndef _C4_STD_STD_FWD_HPP_
#define _C4_STD_STD_FWD_HPP_
/** @file std_fwd.hpp includes all c4-std interop fwd files */
#include "c4/std/vector_fwd.hpp"
#include "c4/std/string_fwd.hpp"
//#include "c4/std/tuple_fwd.hpp"
#endif // _C4_STD_STD_FWD_HPP_
-97
View File
@@ -1,97 +0,0 @@
#ifndef _C4_STD_STRING_HPP_
#define _C4_STD_STRING_HPP_
/** @file string.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <string>
namespace c4 {
//-----------------------------------------------------------------------------
/** get a writeable view to an existing std::string.
* When the string is empty, the returned view will be pointing
* at the character with value '\0', but the size will be zero.
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
*/
C4_ALWAYS_INLINE c4::substr to_substr(std::string &s) noexcept
{
#if C4_CPP < 11
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::substr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
/** get a readonly view to an existing std::string.
* When the string is empty, the returned view will be pointing
* at the character with value '\0', but the size will be zero.
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
*/
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string const& s) noexcept
{
#if C4_CPP < 11
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::csubstr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
//-----------------------------------------------------------------------------
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) == 0; }
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) != 0; }
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) >= 0; }
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) > 0; }
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) <= 0; }
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) < 0; }
C4_ALWAYS_INLINE bool operator== (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) == 0; }
C4_ALWAYS_INLINE bool operator!= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) != 0; }
C4_ALWAYS_INLINE bool operator>= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) <= 0; }
C4_ALWAYS_INLINE bool operator> (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) < 0; }
C4_ALWAYS_INLINE bool operator<= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) >= 0; }
C4_ALWAYS_INLINE bool operator< (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) > 0; }
//-----------------------------------------------------------------------------
/** copy an std::string to a writeable string view */
inline size_t to_chars(c4::substr buf, std::string const& s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t len = buf.len < s.size() ? buf.len : s.size();
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len)
{
C4_ASSERT(s.data() != nullptr);
C4_ASSERT(buf.str != nullptr);
memcpy(buf.str, s.data(), len);
}
return s.size(); // return the number of needed chars
}
/** copy a string view to an existing std::string */
inline bool from_chars(c4::csubstr buf, std::string * s)
{
s->resize(buf.len);
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(buf.len)
{
C4_ASSERT(buf.str != nullptr);
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}
} // namespace c4
#endif // _C4_STD_STRING_HPP_
-59
View File
@@ -1,59 +0,0 @@
#ifndef _C4_STD_STRING_FWD_HPP_
#define _C4_STD_STRING_FWD_HPP_
/** @file string_fwd.hpp */
#ifndef DOXYGEN
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr_fwd.hpp"
#endif
#include <cstddef>
// forward declarations for std::string
#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
#include <bits/stringfwd.h> // use the fwd header in glibcxx
#elif defined(_LIBCPP_VERSION) || defined(__APPLE_CC__)
#include <iosfwd> // use the fwd header in stdlibc++
#elif defined(_MSC_VER)
#include "c4/error.hpp"
//! @todo is there a fwd header in msvc?
namespace std {
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4643) // Forward declaring 'char_traits' in namespace std is not permitted by the C++ Standard.
template<typename> struct char_traits;
template<typename> class allocator;
template<typename _CharT, typename _Traits, typename _Alloc> class basic_string;
using string = basic_string<char, char_traits<char>, allocator<char>>;
C4_SUPPRESS_WARNING_MSVC_POP
} /* namespace std */
#else
#error "unknown standard library"
#endif
namespace c4 {
c4::substr to_substr(std::string &s) noexcept;
c4::csubstr to_csubstr(std::string const& s) noexcept;
bool operator== (c4::csubstr ss, std::string const& s);
bool operator!= (c4::csubstr ss, std::string const& s);
bool operator>= (c4::csubstr ss, std::string const& s);
bool operator> (c4::csubstr ss, std::string const& s);
bool operator<= (c4::csubstr ss, std::string const& s);
bool operator< (c4::csubstr ss, std::string const& s);
bool operator== (std::string const& s, c4::csubstr ss);
bool operator!= (std::string const& s, c4::csubstr ss);
bool operator>= (std::string const& s, c4::csubstr ss);
bool operator> (std::string const& s, c4::csubstr ss);
bool operator<= (std::string const& s, c4::csubstr ss);
bool operator< (std::string const& s, c4::csubstr ss);
size_t to_chars(c4::substr buf, std::string const& s);
bool from_chars(c4::csubstr buf, std::string * s);
} // namespace c4
#endif // DOXYGEN
#endif // _C4_STD_STRING_FWD_HPP_
-71
View File
@@ -1,71 +0,0 @@
#ifndef _C4_STD_STRING_VIEW_HPP_
#define _C4_STD_STRING_VIEW_HPP_
/** @file string_view.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/language.hpp"
#endif
#if (C4_CPP >= 17 && defined(__cpp_lib_string_view)) || defined(__DOXYGEN__)
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <string_view>
namespace c4 {
//-----------------------------------------------------------------------------
/** create a csubstr from an existing std::string_view. */
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string_view s) noexcept
{
return c4::csubstr(s.data(), s.size());
}
//-----------------------------------------------------------------------------
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) == 0; }
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) != 0; }
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) >= 0; }
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) > 0; }
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) <= 0; }
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) < 0; }
C4_ALWAYS_INLINE bool operator== (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) == 0; }
C4_ALWAYS_INLINE bool operator!= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) != 0; }
C4_ALWAYS_INLINE bool operator<= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) >= 0; }
C4_ALWAYS_INLINE bool operator< (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) > 0; }
C4_ALWAYS_INLINE bool operator>= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) <= 0; }
C4_ALWAYS_INLINE bool operator> (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) < 0; }
//-----------------------------------------------------------------------------
/** copy an std::string_view to a writeable substr */
inline size_t to_chars(c4::substr buf, std::string_view s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t sz = s.size();
size_t len = buf.len < sz ? buf.len : sz;
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len)
{
C4_ASSERT(s.data() != nullptr);
C4_ASSERT(buf.str != nullptr);
memcpy(buf.str, s.data(), len);
}
return sz; // return the number of needed chars
}
} // namespace c4
#endif // C4_STRING_VIEW_AVAILABLE
#endif // _C4_STD_STRING_VIEW_HPP_
-184
View File
@@ -1,184 +0,0 @@
#ifndef _C4_STD_TUPLE_HPP_
#define _C4_STD_TUPLE_HPP_
/** @file tuple.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/format.hpp"
#endif
#include <tuple>
/** this is a work in progress */
#undef C4_TUPLE_TO_CHARS
namespace c4 {
#ifdef C4_TUPLE_TO_CHARS
namespace detail {
template< size_t Curr, class... Types >
struct tuple_helper
{
static size_t do_cat(substr buf, std::tuple< Types... > const& tp)
{
size_t num = to_chars(buf, std::get<Curr>(tp));
buf = buf.len >= num ? buf.sub(num) : substr{};
num += tuple_helper< Curr+1, Types... >::do_cat(buf, tp);
return num;
}
static size_t do_uncat(csubstr buf, std::tuple< Types... > & tp)
{
size_t num = from_str_trim(buf, &std::get<Curr>(tp));
if(num == csubstr::npos) return csubstr::npos;
buf = buf.len >= num ? buf.sub(num) : substr{};
num += tuple_helper< Curr+1, Types... >::do_uncat(buf, tp);
return num;
}
template< class Sep >
static size_t do_catsep_more(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
{
size_t ret = to_chars(buf, sep), num = ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = to_chars(buf, std::get<Curr>(tp));
num += ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = tuple_helper< Curr+1, Types... >::do_catsep_more(buf, sep, tp);
num += ret;
return num;
}
template< class Sep >
static size_t do_uncatsep_more(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
{
size_t ret = from_str_trim(buf, &sep), num = ret;
if(ret == csubstr::npos) return csubstr::npos;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = from_str_trim(buf, &std::get<Curr>(tp));
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = tuple_helper< Curr+1, Types... >::do_uncatsep_more(buf, sep, tp);
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
return num;
}
static size_t do_format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
{
auto pos = fmt.find("{}");
if(pos != csubstr::npos)
{
size_t num = to_chars(buf, fmt.sub(0, pos));
size_t out = num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = to_chars(buf, std::get<Curr>(tp));
out += num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = tuple_helper< Curr+1, Types... >::do_format(buf, fmt.sub(pos + 2), tp);
out += num;
return out;
}
else
{
return format(buf, fmt);
}
}
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
{
auto pos = fmt.find("{}");
if(pos != csubstr::npos)
{
size_t num = pos;
size_t out = num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = from_str_trim(buf, &std::get<Curr>(tp));
out += num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = tuple_helper< Curr+1, Types... >::do_unformat(buf, fmt.sub(pos + 2), tp);
out += num;
return out;
}
else
{
return tuple_helper< sizeof...(Types), Types... >::do_unformat(buf, fmt, tp);
}
}
};
/** @todo VS compilation fails for this class */
template< class... Types >
struct tuple_helper< sizeof...(Types), Types... >
{
static size_t do_cat(substr /*buf*/, std::tuple<Types...> const& /*tp*/) { return 0; }
static size_t do_uncat(csubstr /*buf*/, std::tuple<Types...> & /*tp*/) { return 0; }
template< class Sep > static size_t do_catsep_more(substr /*buf*/, Sep const& /*sep*/, std::tuple<Types...> const& /*tp*/) { return 0; }
template< class Sep > static size_t do_uncatsep_more(csubstr /*buf*/, Sep & /*sep*/, std::tuple<Types...> & /*tp*/) { return 0; }
static size_t do_format(substr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
{
return to_chars(buf, fmt);
}
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
{
return 0;
}
};
} // namespace detail
template< class... Types >
inline size_t cat(substr buf, std::tuple< Types... > const& tp)
{
return detail::tuple_helper< 0, Types... >::do_cat(buf, tp);
}
template< class... Types >
inline size_t uncat(csubstr buf, std::tuple< Types... > & tp)
{
return detail::tuple_helper< 0, Types... >::do_uncat(buf, tp);
}
template< class Sep, class... Types >
inline size_t catsep(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
{
size_t num = to_chars(buf, std::cref(std::get<0>(tp)));
buf = buf.len >= num ? buf.sub(num) : substr{};
num += detail::tuple_helper< 1, Types... >::do_catsep_more(buf, sep, tp);
return num;
}
template< class Sep, class... Types >
inline size_t uncatsep(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
{
size_t ret = from_str_trim(buf, &std::get<0>(tp)), num = ret;
if(ret == csubstr::npos) return csubstr::npos;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = detail::tuple_helper< 1, Types... >::do_uncatsep_more(buf, sep, tp);
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
return num;
}
template< class... Types >
inline size_t format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
{
return detail::tuple_helper< 0, Types... >::do_format(buf, fmt, tp);
}
template< class... Types >
inline size_t unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
{
return detail::tuple_helper< 0, Types... >::do_unformat(buf, fmt, tp);
}
#endif // C4_TUPLE_TO_CHARS
} // namespace c4
#endif /* _C4_STD_TUPLE_HPP_ */
-88
View File
@@ -1,88 +0,0 @@
#ifndef _C4_STD_VECTOR_HPP_
#define _C4_STD_VECTOR_HPP_
/** @file vector.hpp provides conversion and comparison facilities
* from/between std::vector<char> to c4::substr and c4::csubstr.
* @todo add to_span() and friends
*/
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <vector>
namespace c4 {
//-----------------------------------------------------------------------------
/** get a substr (writeable string view) of an existing std::vector<char> */
template<class Alloc>
c4::substr to_substr(std::vector<char, Alloc> &vec)
{
char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
return c4::substr(data, vec.size());
}
/** get a csubstr (read-only string) view of an existing std::vector<char> */
template<class Alloc>
c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec)
{
const char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
return c4::csubstr(data, vec.size());
}
//-----------------------------------------------------------------------------
// comparisons between substrings and std::vector<char>
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss != to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss == to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss >= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss > to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss <= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss < to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss != to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss == to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss <= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss < to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss >= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss > to_csubstr(s); }
//-----------------------------------------------------------------------------
/** copy a std::vector<char> to a writeable string view */
template<class Alloc>
inline size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t len = buf.len < s.size() ? buf.len : s.size();
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len > 0)
{
memcpy(buf.str, s.data(), len);
}
return s.size(); // return the number of needed chars
}
/** copy a string view to an existing std::vector<char> */
template<class Alloc>
inline bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s)
{
s->resize(buf.len);
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(buf.len > 0)
{
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}
} // namespace c4
#endif // _C4_STD_VECTOR_HPP_
-70
View File
@@ -1,70 +0,0 @@
#ifndef _C4_STD_VECTOR_FWD_HPP_
#define _C4_STD_VECTOR_FWD_HPP_
/** @file vector_fwd.hpp */
#include <cstddef>
// NOLINTBEGIN(cert-dcl58-cpp)
// forward declarations for std::vector
#if defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_MSC_VER)
#if defined(_MSC_VER)
__pragma(warning(push))
__pragma(warning(disable : 4643))
#endif
namespace std {
template<typename> class allocator;
#ifdef _GLIBCXX_DEBUG
inline namespace __debug {
template<typename T, typename Alloc> class vector;
}
#else
template<typename T, typename Alloc> class vector;
#endif
} // namespace std
#if defined(_MSC_VER)
__pragma(warning(pop))
#endif
#elif defined(_LIBCPP_ABI_NAMESPACE)
namespace std {
inline namespace _LIBCPP_ABI_NAMESPACE {
template<typename> class allocator;
template<typename T, typename Alloc> class vector;
} // namespace _LIBCPP_ABI_NAMESPACE
} // namespace std
#else
#error "unknown standard library"
#endif
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr_fwd.hpp"
#endif
namespace c4 {
template<class Alloc> c4::substr to_substr(std::vector<char, Alloc> &vec);
template<class Alloc> c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec);
template<class Alloc> bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s);
template<class Alloc> bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s);
} // namespace c4
// NOLINTEND(cert-dcl58-cpp)
#endif // _C4_STD_VECTOR_FWD_HPP_
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
#ifndef _C4_SUBSTR_FWD_HPP_
#define _C4_SUBSTR_FWD_HPP_
#include "c4/export.hpp"
namespace c4 {
#ifndef DOXYGEN
template<class C> struct basic_substring;
using csubstr = C4CORE_EXPORT basic_substring<const char>;
using substr = C4CORE_EXPORT basic_substring<char>;
#endif // !DOXYGEN
} // namespace c4
#endif /* _C4_SUBSTR_FWD_HPP_ */
-68
View File
@@ -1,68 +0,0 @@
#ifndef _C4_SZCONV_HPP_
#define _C4_SZCONV_HPP_
/** @file szconv.hpp utilities to deal safely with narrowing conversions */
#include "c4/config.hpp"
#include "c4/error.hpp"
#include <limits>
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
/** @todo this would be so much easier with calls to numeric_limits::max()... */
template<class SizeOut, class SizeIn>
struct is_narrower_size : std::conditional
<
(std::is_signed<SizeOut>::value == std::is_signed<SizeIn>::value)
?
(sizeof(SizeOut) < sizeof(SizeIn))
:
(
(sizeof(SizeOut) < sizeof(SizeIn))
||
(
(sizeof(SizeOut) == sizeof(SizeIn))
&&
(std::is_signed<SizeOut>::value && std::is_unsigned<SizeIn>::value)
)
),
std::true_type,
std::false_type
>::type
{
static_assert(std::is_integral<SizeIn >::value, "must be integral type");
static_assert(std::is_integral<SizeOut>::value, "must be integral type");
};
/** when SizeOut is wider than SizeIn, assignment can occur without reservations */
template<class SizeOut, class SizeIn>
C4_ALWAYS_INLINE
typename std::enable_if< ! is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
szconv(SizeIn sz) noexcept
{
return static_cast<SizeOut>(sz);
}
/** when SizeOut is narrower than SizeIn, narrowing will occur, so we check
* for overflow. Note that this check is done only if C4_XASSERT is enabled.
* @see C4_XASSERT */
template<class SizeOut, class SizeIn>
C4_ALWAYS_INLINE
typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
szconv(SizeIn sz)
{
C4_XASSERT(sz >= 0);
C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz);
SizeOut szo = static_cast<SizeOut>(sz);
return szo;
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
#endif /* _C4_SZCONV_HPP_ */
-507
View File
@@ -1,507 +0,0 @@
#ifndef _C4_TYPES_HPP_
#define _C4_TYPES_HPP_
#include <stdint.h>
#include <stddef.h>
#include <type_traits>
#if __cplusplus >= 201103L
#include <utility> // for integer_sequence and friends
#endif
#include "c4/preprocessor.hpp"
#include "c4/language.hpp"
/** @file types.hpp basic types, and utility macros and traits for types.
* @ingroup basic_headers */
/** @defgroup types Type utilities */
// NOLINTBEGIN(bugprone-macro-parentheses)
namespace c4 {
/** @defgroup intrinsic_types Intrinsic types
* @ingroup types
* @{ */
using cbyte = const char; /**< a constant byte */
using byte = char; /**< a mutable byte */
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using f32 = float;
using f64 = double;
using ssize_t = typename std::make_signed<size_t>::type;
/** @} */
//--------------------------------------------------
/** @defgroup utility_types Utility types
* @ingroup types
* @{ */
// some tag types
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic push
#if __GNUC__ >= 6
#pragma GCC diagnostic ignored "-Wunused-const-variable"
#endif
#endif
/** a tag type for initializing the containers with variadic arguments a la
* initializer_list, minus the initializer_list overload problems.
*/
struct aggregate_t {};
/** @see aggregate_t */
constexpr const aggregate_t aggregate{};
/** a tag type for specifying the initial capacity of allocatable contiguous storage */
struct with_capacity_t {};
/** @see with_capacity_t */
constexpr const with_capacity_t with_capacity{};
/** a tag type for disambiguating template parameter packs in variadic template overloads */
struct varargs_t {};
/** @see with_capacity_t */
constexpr const varargs_t varargs{};
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
//--------------------------------------------------
/** whether a value should be used in place of a const-reference in argument passing. */
template<class T>
struct cref_uses_val
{
enum { value = (
std::is_scalar<T>::value
||
(
#if C4_CPP >= 20
(std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value)
#else
std::is_pod<T>::value
#endif
&&
sizeof(T) <= sizeof(size_t))) };
};
/** utility macro to override the default behaviour for c4::fastcref<T>
@see fastcref */
#define C4_CREF_USES_VAL(T) \
template<> \
struct cref_uses_val<T> \
{ \
enum { value = true }; \
};
/** Whether to use pass-by-value or pass-by-const-reference in a function argument
* or return type. */
template<class T>
using fastcref = typename std::conditional<c4::cref_uses_val<T>::value, T, T const&>::type;
//--------------------------------------------------
/** Just what its name says. Useful sometimes as a default empty policy class. */
struct EmptyStruct // NOLINT
{
template<class... T> EmptyStruct(T && ...){} // NOLINT
};
/** Just what its name says. Useful sometimes as a default policy class to
* be inherited from. */
struct EmptyStructVirtual // NOLINT
{
virtual ~EmptyStructVirtual() = default;
template<class... T> EmptyStructVirtual(T && ...){} // NOLINT
};
/** */
template<class T>
struct inheritfrom : public T {};
//--------------------------------------------------
// Utilities to make a class obey size restrictions (eg, min size or size multiple of).
// DirectX usually makes this restriction with uniform buffers.
// This is also useful for padding to prevent false-sharing.
/** how many bytes must be added to size such that the result is at least minsize? */
C4_ALWAYS_INLINE constexpr size_t min_remainder(size_t size, size_t minsize) noexcept
{
return size < minsize ? minsize-size : 0;
}
/** how many bytes must be added to size such that the result is a multiple of multipleof? */
C4_ALWAYS_INLINE constexpr size_t mult_remainder(size_t size, size_t multipleof) noexcept
{
return (((size % multipleof) != 0) ? (multipleof-(size % multipleof)) : 0);
}
/* force the following class to be tightly packed. */
#pragma pack(push, 1)
/** pad a class with more bytes at the end.
* @see http://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly */
template<class T, size_t BytesToPadAtEnd>
struct Padded : public T
{
using T::T;
using T::operator=;
Padded(T const& val) : T(val) {}
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
char ___c4padspace___[BytesToPadAtEnd];
};
#pragma pack(pop)
/** When the padding argument is 0, we cannot declare the char[] array. */
template<class T>
struct Padded<T, 0> : public T
{
using T::T;
using T::operator=;
Padded(T const& val) : T(val) {}
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
};
/** make T have a size which is at least Min bytes */
template<class T, size_t Min>
using MinSized = Padded<T, min_remainder(sizeof(T), Min)>;
/** make T have a size which is a multiple of Mult bytes */
template<class T, size_t Mult>
using MultSized = Padded<T, mult_remainder(sizeof(T), Mult)>;
/** make T have a size which is simultaneously:
* -bigger or equal than Min
* -a multiple of Mult */
template<class T, size_t Min, size_t Mult>
using MinMultSized = MultSized<MinSized<T, Min>, Mult>;
/** make T be suitable for use as a uniform buffer. (at least with DirectX). */
template<class T>
using UbufSized = MinMultSized<T, 64, 16>;
//-----------------------------------------------------------------------------
#define C4_NO_COPY_CTOR(ty) ty(ty const&) = delete
#define C4_NO_MOVE_CTOR(ty) ty(ty &&) = delete
#define C4_NO_COPY_ASSIGN(ty) ty& operator=(ty const&) = delete
#define C4_NO_MOVE_ASSIGN(ty) ty& operator=(ty &&) = delete
#define C4_DEFAULT_COPY_CTOR(ty) ty(ty const&) noexcept = default
#define C4_DEFAULT_MOVE_CTOR(ty) ty(ty &&) noexcept = default
#define C4_DEFAULT_COPY_ASSIGN(ty) ty& operator=(ty const&) noexcept = default
#define C4_DEFAULT_MOVE_ASSIGN(ty) ty& operator=(ty &&) noexcept = default
#define C4_NO_COPY_OR_MOVE_CTOR(ty) \
C4_NO_COPY_CTOR(ty); \
C4_NO_MOVE_CTOR(ty)
#define C4_NO_COPY_OR_MOVE_ASSIGN(ty) \
C4_NO_COPY_ASSIGN(ty); \
C4_NO_MOVE_ASSIGN(ty)
#define C4_NO_COPY_OR_MOVE(ty) \
C4_NO_COPY_OR_MOVE_CTOR(ty); \
C4_NO_COPY_OR_MOVE_ASSIGN(ty)
#define C4_DEFAULT_COPY_AND_MOVE_CTOR(ty) \
C4_DEFAULT_COPY_CTOR(ty); \
C4_DEFAULT_MOVE_CTOR(ty)
#define C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty) \
C4_DEFAULT_COPY_ASSIGN(ty); \
C4_DEFAULT_MOVE_ASSIGN(ty)
#define C4_DEFAULT_COPY_AND_MOVE(ty) \
C4_DEFAULT_COPY_AND_MOVE_CTOR(ty); \
C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty)
/** @see https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable */
#define C4_MUST_BE_TRIVIAL_COPY(ty) \
static_assert(std::is_trivially_copyable<ty>::value, #ty " must be trivially copyable")
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup traits_types Type traits utilities
* @ingroup types
* @{ */
// http://stackoverflow.com/questions/10821380/is-t-an-instance-of-a-template-in-c
template<template<typename...> class X, typename T> struct is_instance_of_tpl : std::false_type {};
template<template<typename...> class X, typename... Y> struct is_instance_of_tpl<X, X<Y...>> : std::true_type {};
//-----------------------------------------------------------------------------
/** SFINAE. use this macro to enable a template function overload
based on a compile-time condition.
@code
// define an overload for a non-pod type
template<class T, C4_REQUIRE_T(std::is_pod<T>::value)>
void foo() { std::cout << "pod type\n"; }
// define an overload for a non-pod type
template<class T, C4_REQUIRE_T(!std::is_pod<T>::value)>
void foo() { std::cout << "nonpod type\n"; }
struct non_pod
{
non_pod() : name("asdfkjhasdkjh") {}
const char *name;
};
int main()
{
foo<float>(); // prints "pod type"
foo<non_pod>(); // prints "nonpod type"
}
@endcode */
#define C4_REQUIRE_T(cond) typename std::enable_if<cond, bool>::type* = nullptr
/** enable_if for a return type
* @see C4_REQUIRE_T */
#define C4_REQUIRE_R(cond, type_) typename std::enable_if<cond, type_>::type
//-----------------------------------------------------------------------------
/** define a traits class reporting whether a type provides a member typedef */
#define C4_DEFINE_HAS_TYPEDEF(member_typedef) \
template<typename T> \
struct has_##stype \
{ \
private: \
\
typedef char yes; \
typedef struct { char array[2]; } no; \
\
template<typename C> \
static yes _test(typename C::member_typedef*); \
\
template<typename C> \
static no _test(...); \
\
public: \
\
enum { value = (sizeof(_test<T>(0)) == sizeof(yes)) }; \
\
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup type_declarations Type declaration utilities
* @ingroup types
* @{ */
#define _c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I) \
\
using size_type = I; \
using ssize_type = typename std::make_signed<I>::type; \
using difference_type = typename std::make_signed<I>::type; \
\
using value_type = T; \
using pointer = T*; \
using const_pointer = T const*; \
using reference = T&; \
using const_reference = T const&
#define _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I) \
\
using size_type = I; \
using ssize_type = typename std::make_signed<I>::type; \
using difference_type = typename std::make_signed<I>::type; \
\
template<I n> using value_type = typename std::tuple_element< n, std::tuple<interior_types...>>::type; \
template<I n> using pointer = value_type<n>*; \
template<I n> using const_pointer = value_type<n> const*; \
template<I n> using reference = value_type<n>&; \
template<I n> using const_reference = value_type<n> const&
#define _c4_DEFINE_ARRAY_TYPES(T, I) \
\
_c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I); \
\
using iterator = T*; \
using const_iterator = T const*; \
using reverse_iterator = std::reverse_iterator<T*>; \
using const_reverse_iterator = std::reverse_iterator<T const*>
#define _c4_DEFINE_TUPLE_ARRAY_TYPES(interior_types, I) \
\
_c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I); \
\
template<I n> using iterator = value_type<n>*; \
template<I n> using const_iterator = value_type<n> const*; \
template<I n> using reverse_iterator = std::reverse_iterator< value_type<n>*>; \
template<I n> using const_reverse_iterator = std::reverse_iterator< value_type<n> const*>
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup compatility_utilities Backport implementation of some Modern C++ utilities
* @ingroup types
* @{ */
//-----------------------------------------------------------------------------
// index_sequence and friends are available only for C++14 and later.
// A C++11 implementation is provided here.
// This implementation was copied over from clang.
// see http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687
#if __cplusplus > 201103L
using std::integer_sequence;
using std::index_sequence;
using std::make_integer_sequence;
using std::make_index_sequence;
using std::index_sequence_for;
#else
/** C++11 implementation of integer sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class _Tp, _Tp... _Ip>
struct integer_sequence
{
static_assert(std::is_integral<_Tp>::value,
"std::integer_sequence can only be instantiated with an integral type" );
using value_type = _Tp;
static constexpr size_t size() noexcept { return sizeof...(_Ip); }
};
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<size_t... _Ip>
using index_sequence = integer_sequence<size_t, _Ip...>;
/** @cond DONT_DOCUMENT_THIS */
namespace __detail {
template<typename _Tp, size_t ..._Extra>
struct __repeat;
template<typename _Tp, _Tp ..._Np, size_t ..._Extra>
struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...>
{
using type = integer_sequence<_Tp,
_Np...,
sizeof...(_Np) + _Np...,
2 * sizeof...(_Np) + _Np...,
3 * sizeof...(_Np) + _Np...,
4 * sizeof...(_Np) + _Np...,
5 * sizeof...(_Np) + _Np...,
6 * sizeof...(_Np) + _Np...,
7 * sizeof...(_Np) + _Np...,
_Extra...>;
};
template<size_t _Np> struct __parity;
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
template<> struct __make<0> { using type = integer_sequence<size_t>; };
template<> struct __make<1> { using type = integer_sequence<size_t, 0>; };
template<> struct __make<2> { using type = integer_sequence<size_t, 0, 1>; };
template<> struct __make<3> { using type = integer_sequence<size_t, 0, 1, 2>; };
template<> struct __make<4> { using type = integer_sequence<size_t, 0, 1, 2, 3>; };
template<> struct __make<5> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4>; };
template<> struct __make<6> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5>; };
template<> struct __make<7> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6>; };
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<typename _Tp, typename _Up>
struct __convert
{
template<typename> struct __result;
template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...>>
{
using type = integer_sequence<_Up, _Np...>;
};
};
template<typename _Tp>
struct __convert<_Tp, _Tp>
{
template<typename _Up> struct __result
{
using type = _Up;
};
};
template<typename _Tp, _Tp _Np>
using __make_integer_sequence_unchecked = typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
template<class _Tp, _Tp _Ep>
struct __make_integer_sequence
{
static_assert(std::is_integral<_Tp>::value,
"std::make_integer_sequence can only be instantiated with an integral type" );
static_assert(0 <= _Ep, "std::make_integer_sequence input shall not be negative");
typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
};
} // namespace __detail
/** @endcond */
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class _Tp, _Tp _Np>
using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type;
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<size_t _Np>
using make_index_sequence = make_integer_sequence<size_t, _Np>;
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class... _Tp>
using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
#endif
/** @} */
} // namespace c4
// NOLINTEND(bugprone-macro-parentheses)
#endif /* _C4_TYPES_HPP_ */
-73
View File
@@ -1,73 +0,0 @@
#ifndef C4_UTF_HPP_
#define C4_UTF_HPP_
#include "c4/language.hpp"
#include "c4/substr_fwd.hpp"
#include <stddef.h>
#include <stdint.h>
/** @file utf.hpp utilities for UTF and Byte Order Mark */
namespace c4 {
/** @defgroup doc_utf UTF utilities
* @{ */
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark.
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT substr skip_bom(substr s);
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT csubstr skip_bom(csubstr s);
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT substr get_bom(substr s);
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT csubstr get_bom(csubstr s);
/** return the position of the first character not belonging to the
* Byte Order Mark, or 0 if there is no Byte Order Mark.
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT size_t first_non_bom(csubstr s);
/** decode the given @p code_point, writing into the output string in
* @p out.
*
* @param out the output string. must have at least 4 bytes (this is
* asserted), and must not have a null string.
*
* @param code_point: must have length in ]0,8], and must not begin
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
*
* @return the part of @p out that was written, which will always be
* at most 4 bytes.
*/
C4CORE_EXPORT substr decode_code_point(substr out, csubstr code_point);
/** decode the given @p code point, writing into the output string @p
* buf, of size @p buflen
*
* @param buf the output string. must have at least 4 bytes (this is
* asserted), and must not be null
*
* @param buflen the length of the output string. must be at least 4
*
* @param code: the code point must have length in ]0,8], and must not begin
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
*
* @return the number of written characters, which will always be
* at most 4 bytes.
*/
C4CORE_EXPORT size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, uint32_t code);
/** @} */
} // namespace c4
#endif // C4_UTF_HPP_
-10
View File
@@ -1,10 +0,0 @@
#ifndef _C4_WINDOWS_HPP_
#define _C4_WINDOWS_HPP_
#if defined(_WIN64) || defined(_WIN32)
#include "c4/windows_push.hpp"
#include <windows.h>
#include "c4/windows_pop.hpp"
#endif
#endif /* _C4_WINDOWS_HPP_ */
-41
View File
@@ -1,41 +0,0 @@
#ifndef _C4_WINDOWS_POP_HPP_
#define _C4_WINDOWS_POP_HPP_
#if defined(_WIN64) || defined(_WIN32)
#ifdef _c4_AMD64_
# undef _c4_AMD64_
# undef _AMD64_
#endif
#ifdef _c4_X86_
# undef _c4_X86_
# undef _X86_
#endif
#ifdef _c4_ARM_
# undef _c4_ARM_
# undef _ARM_
#endif
#ifdef _c4_NOMINMAX
# undef _c4_NOMINMAX
# undef NOMINMAX
#endif
#ifdef NOGDI
# undef _c4_NOGDI
# undef NOGDI
#endif
#ifdef VC_EXTRALEAN
# undef _c4_VC_EXTRALEAN
# undef VC_EXTRALEAN
#endif
#ifdef WIN32_LEAN_AND_MEAN
# undef _c4_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif /* defined(_WIN64) || defined(_WIN32) */
#endif /* _C4_WINDOWS_POP_HPP_ */
-102
View File
@@ -1,102 +0,0 @@
#ifndef _C4_WINDOWS_PUSH_HPP_
#define _C4_WINDOWS_PUSH_HPP_
/** @file windows_push.hpp sets up macros to include windows header files
* without pulling in all of <windows.h>
*
* @see #include windows_pop.hpp to undefine these macros
*
* @see https://aras-p.info/blog/2018/01/12/Minimizing-windows.h/ */
#if defined(_WIN64) || defined(_WIN32)
#if defined(_M_AMD64)
# ifndef _AMD64_
# define _c4_AMD64_
# define _AMD64_
# endif
#elif defined(_M_IX86)
# ifndef _X86_
# define _c4_X86_
# define _X86_
# endif
#elif defined(_M_ARM64)
# ifndef _ARM64_
# define _c4_ARM64_
# define _ARM64_
# endif
#elif defined(_M_ARM)
# ifndef _ARM_
# define _c4_ARM_
# define _ARM_
# endif
#endif
#ifndef NOMINMAX
# define _c4_NOMINMAX
# define NOMINMAX
#endif
#ifndef NOGDI
# define _c4_NOGDI
# define NOGDI
#endif
#ifndef VC_EXTRALEAN
# define _c4_VC_EXTRALEAN
# define VC_EXTRALEAN
#endif
#ifndef WIN32_LEAN_AND_MEAN
# define _c4_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
/* If defined, the following flags inhibit definition
* of the indicated items.
*
* NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
* NOVIRTUALKEYCODES - VK_*
* NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
* NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
* NOSYSMETRICS - SM_*
* NOMENUS - MF_*
* NOICONS - IDI_*
* NOKEYSTATES - MK_*
* NOSYSCOMMANDS - SC_*
* NORASTEROPS - Binary and Tertiary raster ops
* NOSHOWWINDOW - SW_*
* OEMRESOURCE - OEM Resource values
* NOATOM - Atom Manager routines
* NOCLIPBOARD - Clipboard routines
* NOCOLOR - Screen colors
* NOCTLMGR - Control and Dialog routines
* NODRAWTEXT - DrawText() and DT_*
* NOGDI - All GDI defines and routines
* NOKERNEL - All KERNEL defines and routines
* NOUSER - All USER defines and routines
* NONLS - All NLS defines and routines
* NOMB - MB_* and MessageBox()
* NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
* NOMETAFILE - typedef METAFILEPICT
* NOMINMAX - Macros min(a,b) and max(a,b)
* NOMSG - typedef MSG and associated routines
* NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
* NOSCROLL - SB_* and scrolling routines
* NOSERVICE - All Service Controller routines, SERVICE_ equates, etc.
* NOSOUND - Sound driver routines
* NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
* NOWH - SetWindowsHook and WH_*
* NOWINOFFSETS - GWL_*, GCL_*, associated routines
* NOCOMM - COMM driver routines
* NOKANJI - Kanji support stuff.
* NOHELP - Help engine interface.
* NOPROFILER - Profiler interface.
* NODEFERWINDOWPOS - DeferWindowPos routines
* NOMCX - Modem Configuration Extensions
*/
#endif /* defined(_WIN64) || defined(_WIN32) */
#endif /* _C4_WINDOWS_PUSH_HPP_ */
-660
View File
@@ -1,660 +0,0 @@
#ifndef _C4_YML_COMMON_HPP_
#define _C4_YML_COMMON_HPP_
/** @file common.hpp Common utilities and infrastructure used by ryml. */
#include <cstddef>
#include <c4/substr.hpp>
#include <c4/charconv.hpp>
#include <c4/dump.hpp>
#include <c4/yml/export.hpp>
#if defined(C4_MSVC) || defined(C4_MINGW) || defined(_WIN32) || defined(C4_WIN)
#include <malloc.h>
#else
#include <alloca.h>
#endif
//-----------------------------------------------------------------------------
#ifndef RYML_ERRMSG_SIZE
/// size for the error message buffer
#define RYML_ERRMSG_SIZE (1024)
#endif
#ifndef RYML_LOGBUF_SIZE
/// size for the buffer used to format individual values to string
/// while preparing an error message. This is only used for formatting
/// individual values in the message; final messages will be larger
/// than this value (see @ref RYML_ERRMSG_SIZE). This is also used for
/// the detailed debug log messages when RYML_DBG is defined.
#define RYML_LOGBUF_SIZE (256)
#endif
#ifndef RYML_LOGBUF_SIZE_MAX
/// size for the fallback larger log buffer. When @ref
/// RYML_LOGBUF_SIZE is not large enough to convert a value to string,
/// then temporary stack memory is allocated up to
/// RYML_LOGBUF_SIZE_MAX. This limit is in place to prevent a stack
/// overflow. If the printed value requires more than
/// RYML_LOGBUF_SIZE_MAX, the value is silently skipped.
#define RYML_LOGBUF_SIZE_MAX (1024)
#endif
#ifndef RYML_LOCATIONS_SMALL_THRESHOLD
/// threshold at which a location search will revert from linear to
/// binary search.
#define RYML_LOCATIONS_SMALL_THRESHOLD (30)
#endif
//-----------------------------------------------------------------------------
// Specify groups to have a predefined topic order in doxygen:
/** @defgroup doc_quickstart Quickstart
*
* Example code for every feature.
*/
/** @defgroup doc_parse Parse utilities
* @see sample::sample_parse_in_place
* @see sample::sample_parse_in_arena
* @see sample::sample_parse_file
* @see sample::sample_parse_reuse_tree
* @see sample::sample_parse_reuse_parser
* @see sample::sample_parse_reuse_tree_and_parser
* @see sample::sample_location_tracking
*/
/** @defgroup doc_emit Emit utilities
*
* Utilities to emit YAML and JSON, either to a memory buffer or to a
* file or ostream-like class.
*
* @see sample::sample_emit_to_container
* @see sample::sample_emit_to_stream
* @see sample::sample_emit_to_file
* @see sample::sample_emit_nested_node
* @see sample::sample_emit_style
*/
/** @defgroup doc_node_type Node types
*/
/** @defgroup doc_tree Tree utilities
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*
* @see sample::sample_static_trees
* @see sample::sample_location_tracking
*
* @see sample::sample_docs
* @see sample::sample_anchors_and_aliases
* @see sample::sample_tags
*/
/** @defgroup doc_node_classes Node classes
*
* High-level node classes.
*
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*/
/** @defgroup doc_callbacks Callbacks for errors and allocation
*
* Functions called by ryml to allocate/free memory and to report
* errors.
*
* @see sample::sample_error_handler
* @see sample::sample_global_allocator
* @see sample::sample_per_tree_allocator
*/
/** @defgroup doc_serialization Serialization/deserialization
*
* Contains information on how to serialize and deserialize
* fundamental types, user scalar types, user container types and
* interop with std scalar/container types.
*
*/
/** @defgroup doc_ref_utils Anchor/Reference utilities
*
* @see sample::sample_anchors_and_aliases
* */
/** @defgroup doc_tag_utils Tag utilities
* @see sample::sample_tags
*/
/** @defgroup doc_preprocessors Preprocessors
*
* Functions for preprocessing YAML prior to parsing.
*/
//-----------------------------------------------------------------------------
// document macros for doxygen
#ifdef __DOXYGEN__ // defined in Doxyfile::PREDEFINED
/** define this macro with a boolean value to enable/disable
* assertions to check preconditions and assumptions throughout the
* codebase; this causes a slowdown of the code, and larger code
* size. By default, this macro is defined unless NDEBUG is defined
* (see C4_USE_ASSERT); as a result, by default this macro is truthy
* only in debug builds. */
# define RYML_USE_ASSERT
/** (Undefined by default) Define this macro to disable ryml's default
* implementation of the callback functions; see @ref c4::yml::Callbacks */
# define RYML_NO_DEFAULT_CALLBACKS
/** (Undefined by default) When this macro is defined (and
* @ref RYML_NO_DEFAULT_CALLBACKS is not defined), the default error
* handler will throw C++ exceptions of type `std::runtime_error`. */
# define RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
/** Conditionally expands to `noexcept` when @ref RYML_USE_ASSERT is 0 and
* is empty otherwise. The user is unable to override this macro. */
# define RYML_NOEXCEPT
#endif
//-----------------------------------------------------------------------------
/** @cond dev*/
#ifndef RYML_USE_ASSERT
# define RYML_USE_ASSERT C4_USE_ASSERT
#endif
#if RYML_USE_ASSERT
# define RYML_ASSERT(cond) RYML_CHECK(cond)
# define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg)
# define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond))
# define _RYML_CB_ASSERT_(cb, cond, loc) _RYML_CB_CHECK((cb), (cond), (loc))
# define RYML_NOEXCEPT
#else
# define RYML_ASSERT(cond)
# define RYML_ASSERT_MSG(cond, msg)
# define _RYML_CB_ASSERT(cb, cond)
# define _RYML_CB_ASSERT_(cb, cond, loc)
# define RYML_NOEXCEPT noexcept
#endif
#define RYML_DEPRECATED(msg) C4_DEPRECATED(msg)
#define RYML_CHECK(cond) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK(); \
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define RYML_CHECK_MSG(cond, msg) \
do \
{ \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK(); \
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
# define RYML_DEBUG_BREAK() \
do { \
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
{ \
C4_DEBUG_BREAK(); \
} \
} while(0)
#else
# define RYML_DEBUG_BREAK()
#endif
/** @endcond */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
#ifndef RYML_ID_TYPE
/** The type of a node id in the YAML tree. In the future, the default
* will likely change to int32_t, which was observed to be faster.
* @see id_type */
#define RYML_ID_TYPE size_t
#endif
/** The type of a node id in the YAML tree; to override the default
* type, define the macro @ref RYML_ID_TYPE to a suitable integer
* type. */
using id_type = RYML_ID_TYPE;
static_assert(std::is_integral<id_type>::value, "id_type must be an integer type");
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
enum : id_type {
/** an index to none */
NONE = id_type(-1),
};
C4_SUPPRESS_WARNING_GCC_CLANG_POP
enum : size_t {
/** a null string position */
npos = size_t(-1)
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! holds a position into a source buffer
struct RYML_EXPORT LineCol
{
//! number of bytes from the beginning of the source buffer
size_t offset;
//! line
size_t line;
//! column
size_t col;
LineCol() = default;
//! construct from line and column
LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {}
//! construct from offset, line and column
LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
};
static_assert(std::is_trivially_copyable<LineCol>::value, "LineCol not trivially copyable");
static_assert(std::is_trivially_default_constructible<LineCol>::value, "LineCol not trivially default constructible");
static_assert(std::is_standard_layout<LineCol>::value, "Location not trivial");
//! a source file position
struct RYML_EXPORT Location
{
//! number of bytes from the beginning of the source buffer
size_t offset;
//! line
size_t line;
//! column
size_t col;
//! file name
csubstr name;
operator bool () const { return !name.empty() || line != 0 || offset != 0 || col != 0; }
operator LineCol const& () const { return reinterpret_cast<LineCol const&>(*this); } // NOLINT
Location() = default;
Location( size_t l, size_t c) : offset( ), line(l), col(c), name( ) {}
Location( size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name( ) {}
Location( csubstr n, size_t l, size_t c) : offset( ), line(l), col(c), name(n) {}
Location( csubstr n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(n) {}
Location(const char *n, size_t l, size_t c) : offset( ), line(l), col(c), name(to_csubstr(n)) {}
Location(const char *n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(to_csubstr(n)) {}
};
static_assert(std::is_standard_layout<Location>::value, "Location not trivial");
//-----------------------------------------------------------------------------
/** @addtogroup doc_callbacks
*
* @{ */
struct Callbacks;
/** set the global callbacks for the library; after a call to this
* function, these callbacks will be used by newly created objects
* (unless they are copying older objects with different
* callbacks). If @ref RYML_NO_DEFAULT_CALLBACKS is defined, it is
* mandatory to call this function prior to using any other library
* facility.
*
* @warning This function is NOT thread-safe.
*
* @warning the error callback must never return: see @ref pfn_error
* for more details */
RYML_EXPORT void set_callbacks(Callbacks const& c);
/** get the global callbacks
* @warning This function is not thread-safe. */
RYML_EXPORT Callbacks const& get_callbacks();
/** set the global callbacks back to their defaults ()
* @warning This function is not thread-safe. */
RYML_EXPORT void reset_callbacks();
/** the type of the function used to report errors
*
* @warning When given by the user, this function MUST interrupt
* execution, typically by either throwing an exception, or using
* `std::longjmp()` ([see
* documentation](https://en.cppreference.com/w/cpp/utility/program/setjmp))
* or by calling `std::abort()`. If the function returned, the parser
* would enter into an infinite loop, or the program may crash. */
using pfn_error = void (*) (const char* msg, size_t msg_len, Location location, void *user_data);
/** the type of the function used to allocate memory; ryml will only
* allocate memory through this callback. */
using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data);
/** the type of the function used to free memory; ryml will only free
* memory through this callback. */
using pfn_free = void (*)(void* mem, size_t size, void *user_data);
/** a c-style callbacks class. Can be used globally by the library
* and/or locally by @ref Tree and @ref Parser objects. */
struct RYML_EXPORT Callbacks
{
void * m_user_data;
pfn_allocate m_allocate;
pfn_free m_free;
pfn_error m_error;
/** Construct an object with the default callbacks. If
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, the object will have null
* members.*/
Callbacks() noexcept;
/** Construct an object with the given callbacks.
*
* @param user_data Data to be forwarded in every call to a callback.
*
* @param alloc A pointer to an allocate function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* alloc implementation.
*
* @param free A pointer to a free function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default free
* implementation.
*
* @param error A pointer to an error function, which must never
* return (see @ref pfn_error). Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* error implementation.
*/
Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error);
bool operator!= (Callbacks const& that) const { return !operator==(that); }
bool operator== (Callbacks const& that) const
{
return (m_user_data == that.m_user_data &&
m_allocate == that.m_allocate &&
m_free == that.m_free &&
m_error == that.m_error);
}
};
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
typedef enum {
NOBOM,
UTF8,
UTF16LE,
UTF16BE,
UTF32LE,
UTF32BE,
} Encoding_e;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
// BEWARE! MSVC requires that [[noreturn]] appears before RYML_EXPORT
[[noreturn]] RYML_EXPORT void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc);
[[noreturn]] RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc);
[[noreturn]] inline void error(const char *msg, size_t msg_len)
{
error(msg, msg_len, Location{});
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N], Location loc)
{
error(msg, N-1, loc);
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N])
{
error(msg, N-1, Location{});
}
#define _RYML_CB_ERR(cb, msg_literal) \
_RYML_CB_ERR_(cb, msg_literal, c4::yml::Location(__FILE__, 0, __LINE__, 0))
#define _RYML_CB_CHECK(cb, cond) \
_RYML_CB_CHECK_(cb, cond, c4::yml::Location(__FILE__, 0, __LINE__, 0))
#define _RYML_CB_ERR_(cb, msg_literal, loc) \
do \
{ \
const char msg[] = msg_literal; \
RYML_DEBUG_BREAK(); \
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
C4_UNREACHABLE_AFTER_ERR(); \
} while(0)
#define _RYML_CB_CHECK_(cb, cond, loc) \
do \
{ \
if(C4_UNLIKELY(!(cond))) \
{ \
const char msg[] = "check failed: " #cond; \
RYML_DEBUG_BREAK(); \
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), T, (num), nullptr)
#define _RYML_CB_FREE(cb, buf, T, num) \
do { \
(cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \
(buf) = nullptr; \
} while(0)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
typedef enum {
BLOCK_LITERAL, //!< keep newlines (|)
BLOCK_FOLD //!< replace newline with single space (>)
} BlockStyle_e;
typedef enum {
CHOMP_CLIP, //!< single newline at end (default)
CHOMP_STRIP, //!< no newline at end (-)
CHOMP_KEEP //!< all newlines from end (+)
} BlockChomp_e;
/** Abstracts the fact that a scalar filter result may not fit in the
* intended memory. */
struct FilterResult
{
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
C4_ALWAYS_INLINE size_t required_len() const noexcept { return str.len; }
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
csubstr str;
};
/** Abstracts the fact that a scalar filter result may not fit in the
* intended memory. */
struct FilterResultExtending
{
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
C4_ALWAYS_INLINE size_t required_len() const noexcept { return reqlen; }
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
csubstr str;
size_t reqlen;
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace detail {
// is there a better way to do this?
template<int8_t signedval, uint8_t unsignedval>
struct _charconstant_t
: public std::conditional<std::is_signed<char>::value,
std::integral_constant<int8_t, static_cast<int8_t>(unsignedval)>,
std::integral_constant<uint8_t, unsignedval>>::type
{};
#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value
} // namespace detail
namespace detail {
struct _SubstrWriter
{
substr buf;
size_t pos;
_SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
void append(csubstr s)
{
C4_ASSERT(!s.overlaps(buf));
C4_ASSERT(s.str || !s.len);
if(s.len && pos + s.len <= buf.len)
{
C4_ASSERT(s.str);
memcpy(buf.str + pos, s.str, s.len);
}
pos += s.len;
}
void append(char c)
{
C4_ASSERT(buf.str);
if(pos < buf.len)
buf.str[pos] = c;
++pos;
}
void append_n(char c, size_t numtimes)
{
C4_ASSERT(buf.str);
if(numtimes && pos + numtimes < buf.len)
memset(buf.str + pos, c, numtimes);
pos += numtimes;
}
size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; }
size_t excess() const { return pos > buf.len ? pos - buf.len : 0; }
//! get the part written so far
csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
//! get the part that is still free to write to (the remainder)
substr rem() const { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
size_t advance(size_t more) { pos += more; return pos; }
};
} // namespace detail
namespace detail {
// dumpfn is a function abstracting prints to terminal (or to string).
template<class DumpFn, class ...Args>
C4_NO_INLINE void _dump(DumpFn &&dumpfn, csubstr fmt, Args&& ...args)
{
DumpResults results;
// try writing everything:
{
// buffer for converting individual arguments. it is defined
// in a child scope to free it in case the buffer is too small
// for any of the arguments.
char writebuf[RYML_LOGBUF_SIZE];
results = format_dump_resume(std::forward<DumpFn>(dumpfn), writebuf, fmt, std::forward<Args>(args)...);
}
// if any of the arguments failed to fit the buffer, allocate a
// larger buffer (up to a limit) and resume writing.
//
// results.bufsize is set to the size of the largest element
// serialized. Eg int(1) will require 1 byte.
if(C4_UNLIKELY(results.bufsize > RYML_LOGBUF_SIZE))
{
const size_t bufsize = results.bufsize <= RYML_LOGBUF_SIZE_MAX ? results.bufsize : RYML_LOGBUF_SIZE_MAX;
#ifdef C4_MSVC
substr largerbuf = {static_cast<char*>(_alloca(bufsize)), bufsize};
#else
substr largerbuf = {static_cast<char*>(alloca(bufsize)), bufsize};
#endif
results = format_dump_resume(std::forward<DumpFn>(dumpfn), results, largerbuf, fmt, std::forward<Args>(args)...);
}
}
template<class ...Args>
C4_NORETURN C4_NO_INLINE void _report_err(Callbacks const& C4_RESTRICT callbacks, csubstr fmt, Args const& C4_RESTRICT ...args)
{
char errmsg[RYML_ERRMSG_SIZE] = {0};
detail::_SubstrWriter writer(errmsg);
auto dumpfn = [&writer](csubstr s){ writer.append(s); };
_dump(dumpfn, fmt, args...);
writer.append('\n');
const size_t len = writer.pos < RYML_ERRMSG_SIZE ? writer.pos : RYML_ERRMSG_SIZE;
callbacks.m_error(errmsg, len, {}, callbacks.m_user_data);
C4_UNREACHABLE_AFTER_ERR();
}
} // namespace detail
inline csubstr _c4prc(const char &C4_RESTRICT c) // pass by reference!
{
switch(c)
{
case '\n': return csubstr("\\n");
case '\t': return csubstr("\\t");
case '\0': return csubstr("\\0");
case '\r': return csubstr("\\r");
case '\f': return csubstr("\\f");
case '\b': return csubstr("\\b");
case '\v': return csubstr("\\v");
case '\a': return csubstr("\\a");
default: return csubstr(&c, 1);
}
}
/// @endcond
C4_SUPPRESS_WARNING_GCC_POP
} // namespace yml
} // namespace c4
#endif /* _C4_YML_COMMON_HPP_ */
-200
View File
@@ -1,200 +0,0 @@
#ifndef C4_YML_DETAIL_CHECKS_HPP_
#define C4_YML_DETAIL_CHECKS_HPP_
#include "c4/yml/tree.hpp"
#ifdef __clang__
# pragma clang diagnostic push
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wtype-limits" // error: comparison of unsigned expression >= 0 is always true
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
#endif
namespace c4 {
namespace yml {
void check_invariants(Tree const& t, id_type node=NONE);
void check_free_list(Tree const& t);
void check_arena(Tree const& t);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_invariants(Tree const& t, id_type node)
{
if(node == NONE)
{
if(t.empty()) return;
node = t.root_id();
}
NodeData const& n = *t._p(node);
#if defined(RYML_DBG) && 0
if(n.m_first_child != NONE || n.m_last_child != NONE)
{
printf("check(%zu): fc=%zu lc=%zu\n", node, n.m_first_child, n.m_last_child);
}
else
{
printf("check(%zu)\n", node);
}
#endif
C4_CHECK(n.m_parent != node);
if(n.m_parent == NONE)
{
C4_CHECK(t.is_root(node));
}
else //if(n.m_parent != NONE)
{
C4_CHECK(t.has_child(n.m_parent, node));
auto const& p = *t._p(n.m_parent);
if(n.m_prev_sibling == NONE)
{
C4_CHECK(p.m_first_child == node);
C4_CHECK(t.first_sibling(node) == node);
}
else
{
C4_CHECK(p.m_first_child != node);
C4_CHECK(t.first_sibling(node) != node);
}
if(n.m_next_sibling == NONE)
{
C4_CHECK(p.m_last_child == node);
C4_CHECK(t.last_sibling(node) == node);
}
else
{
C4_CHECK(p.m_last_child != node);
C4_CHECK(t.last_sibling(node) != node);
}
}
C4_CHECK(n.m_first_child != node);
C4_CHECK(n.m_last_child != node);
if(n.m_first_child != NONE || n.m_last_child != NONE)
{
C4_CHECK(n.m_first_child != NONE);
C4_CHECK(n.m_last_child != NONE);
}
C4_CHECK(n.m_prev_sibling != node);
C4_CHECK(n.m_next_sibling != node);
if(n.m_prev_sibling != NONE)
{
C4_CHECK(t._p(n.m_prev_sibling)->m_next_sibling == node);
C4_CHECK(t._p(n.m_prev_sibling)->m_prev_sibling != node);
}
if(n.m_next_sibling != NONE)
{
C4_CHECK(t._p(n.m_next_sibling)->m_prev_sibling == node);
C4_CHECK(t._p(n.m_next_sibling)->m_next_sibling != node);
}
id_type count = 0;
for(id_type i = n.m_first_child; i != NONE; i = t.next_sibling(i))
{
#if defined(RYML_DBG) && 0
printf("check(%zu): descend to child[%zu]=%zu\n", node, count, i);
#endif
auto const& ch = *t._p(i);
C4_CHECK(ch.m_parent == node);
C4_CHECK(ch.m_next_sibling != i);
++count;
}
C4_CHECK(count == t.num_children(node));
if(n.m_prev_sibling == NONE && n.m_next_sibling == NONE)
{
if(n.m_parent != NONE)
{
C4_CHECK(t.num_children(n.m_parent) == 1);
C4_CHECK(t.num_siblings(node) == 1);
}
}
if(node == t.root_id())
{
C4_CHECK(t.size() == t.m_size);
C4_CHECK(t.capacity() == t.m_cap);
C4_CHECK(t.m_cap == t.m_size + t.slack());
check_free_list(t);
check_arena(t);
}
for(id_type i = t.first_child(node); i != NONE; i = t.next_sibling(i))
{
check_invariants(t, i);
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_free_list(Tree const& t)
{
if(t.m_free_head == NONE)
{
C4_CHECK(t.m_free_tail == t.m_free_head);
return;
}
C4_CHECK(t.m_free_head >= 0 && t.m_free_head < t.m_cap);
C4_CHECK(t.m_free_tail >= 0 && t.m_free_tail < t.m_cap);
auto const& head = *t._p(t.m_free_head);
//auto const& tail = *t._p(t.m_free_tail);
//C4_CHECK(head.m_prev_sibling == NONE);
//C4_CHECK(tail.m_next_sibling == NONE);
id_type count = 0;
for(id_type i = t.m_free_head, prev = NONE; i != NONE; i = t._p(i)->m_next_sibling)
{
auto const& elm = *t._p(i);
if(&elm != &head)
{
C4_CHECK(elm.m_prev_sibling == prev);
}
prev = i;
++count;
}
C4_CHECK(count == t.slack());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_arena(Tree const& t)
{
C4_CHECK(t.m_arena.len == 0 || (t.m_arena_pos >= 0 && t.m_arena_pos <= t.m_arena.len));
C4_CHECK(t.arena_size() == t.m_arena_pos);
C4_CHECK(t.arena_slack() + t.m_arena_pos == t.m_arena.len);
}
} /* namespace yml */
} /* namespace c4 */
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif /* C4_YML_DETAIL_CHECKS_HPP_ */
-129
View File
@@ -1,129 +0,0 @@
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#define _C4_YML_DETAIL_DBGPRINT_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "../common.hpp"
#endif
#ifdef RYML_DBG
#include <cstdio>
#endif
//-----------------------------------------------------------------------------
// debug prints
#ifndef RYML_DBG
# define _c4dbgt(fmt, ...)
# define _c4dbgpf(fmt, ...)
# define _c4dbgpf_(fmt, ...)
# define _c4dbgp(msg)
# define _c4dbgp_(msg)
# define _c4dbgq(msg)
# define _c4presc(...)
# define _c4prscalar(msg, scalar, keep_newlines)
#else
# define _c4dbgt(fmt, ...) do { if(_dbg_enabled()) { \
this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__); } } while(0)
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgpf_(fmt, ...) _dbg_printf("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
# define _c4dbgp_(msg) _dbg_printf("{}:{}: " msg , __FILE__, __LINE__ )
# define _c4dbgq(msg) _dbg_printf(msg "\n")
# define _c4presc(...) do { if(_dbg_enabled()) __c4presc(__VA_ARGS__); } while(0)
# define _c4prscalar(msg, scalar, keep_newlines) \
do { \
_c4dbgpf_("{}: [{}]~~~", msg, scalar.len); \
if(_dbg_enabled()) { \
__c4presc((scalar).str, (scalar).len, (keep_newlines)); \
} \
_c4dbgq("~~~"); \
} while(0)
#endif // RYML_DBG
//-----------------------------------------------------------------------------
#ifdef RYML_DBG
#include <c4/dump.hpp>
namespace c4 {
inline bool& _dbg_enabled() { static bool enabled = true; return enabled; }
inline void _dbg_set_enabled(bool yes) { _dbg_enabled() = yes; }
inline void _dbg_dumper(csubstr s)
{
if(s.str)
fwrite(s.str, 1, s.len, stdout);
}
inline substr _dbg_buf() noexcept
{
static char writebuf[2048];
return substr{writebuf, sizeof(writebuf)}; // g++-5 has trouble with return writebuf;
}
template<class ...Args>
C4_NO_INLINE void _dbg_printf(c4::csubstr fmt, Args const& ...args)
{
if(_dbg_enabled())
{
substr buf = _dbg_buf();
const size_t needed_size = c4::format_dump(&_dbg_dumper, buf, fmt, args...);
C4_CHECK(needed_size <= buf.len);
}
}
inline C4_NO_INLINE void __c4presc(const char *s, size_t len, bool keep_newlines=false)
{
RYML_ASSERT(s || !len);
size_t prev = 0;
for(size_t i = 0; i < len; ++i)
{
switch(s[i])
{
case '\n' : _dbg_printf("{}{}{}", csubstr(s+prev, i-prev), csubstr("\\n"), csubstr(keep_newlines ? "\n":"")); prev = i+1; break;
case '\t' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\t")); prev = i+1; break;
case '\0' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\0")); prev = i+1; break;
case '\r' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\r")); prev = i+1; break;
case '\f' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\f")); prev = i+1; break;
case '\b' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\b")); prev = i+1; break;
case '\v' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\v")); prev = i+1; break;
case '\a' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\a")); prev = i+1; break;
case '\x1b': _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\x1b")); prev = i+1; break;
case -0x3e/*0xc2u*/:
if(i+1 < len)
{
if(s[i+1] == -0x60/*0xa0u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\_")); prev = i+1;
}
else if(s[i+1] == -0x7b/*0x85u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\N")); prev = i+1;
}
}
break;
case -0x1e/*0xe2u*/:
if(i+2 < len && s[i+1] == -0x80/*0x80u*/)
{
if(s[i+2] == -0x58/*0xa8u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\L")); prev = i+1;
}
else if(s[i+2] == -0x57/*0xa9u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\P")); prev = i+1;
}
}
break;
}
}
if(len > prev)
_dbg_printf("{}", csubstr(s+prev, len-prev));
}
inline void __c4presc(csubstr s, bool keep_newlines=false)
{
__c4presc(s.str, s.len, keep_newlines);
}
} // namespace c4
#endif // RYML_DBG
#endif /* _C4_YML_DETAIL_DBGPRINT_HPP_ */
-184
View File
@@ -1,184 +0,0 @@
#ifndef C4_YML_DETAIL_PRINT_HPP_
#define C4_YML_DETAIL_PRINT_HPP_
#include "c4/yml/tree.hpp"
#include "c4/yml/node.hpp"
#ifdef RYML_DBG
#define _c4dbg_tree(...) print_tree(__VA_ARGS__)
#define _c4dbg_node(...) print_tree(__VA_ARGS__)
#else
#define _c4dbg_tree(...)
#define _c4dbg_node(...)
#endif
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
inline const char* _container_style_code(Tree const& p, id_type node)
{
if(p.is_container(node))
{
if(p._p(node)->m_type & (FLOW_SL|FLOW_ML))
{
return "[FLOW]";
}
if(p._p(node)->m_type & (BLOCK))
{
return "[BLCK]";
}
}
return "";
}
inline char _scalar_code(NodeType masked)
{
if(masked & (KEY_LITERAL|VAL_LITERAL))
return '|';
if(masked & (KEY_FOLDED|VAL_FOLDED))
return '>';
if(masked & (KEY_SQUO|VAL_SQUO))
return '\'';
if(masked & (KEY_DQUO|VAL_DQUO))
return '"';
if(masked & (KEY_PLAIN|VAL_PLAIN))
return '~';
return '@';
}
inline char _scalar_code_key(NodeType t)
{
return _scalar_code(t & KEY_STYLE);
}
inline char _scalar_code_val(NodeType t)
{
return _scalar_code(t & VAL_STYLE);
}
inline char _scalar_code_key(Tree const& p, id_type node)
{
return _scalar_code_key(p._p(node)->m_type);
}
inline char _scalar_code_val(Tree const& p, id_type node)
{
return _scalar_code_key(p._p(node)->m_type);
}
inline id_type print_node(Tree const& p, id_type node, int level, id_type count, bool print_children)
{
printf("[%zu]%*s[%zu] %p", (size_t)count, (2*level), "", (size_t)node, (void const*)p.get(node));
if(p.is_root(node))
{
printf(" [ROOT]");
}
char typebuf[128];
csubstr typestr = p.type(node).type_str(typebuf);
RYML_CHECK(typestr.str);
printf(" %.*s", (int)typestr.len, typestr.str);
if(p.has_key(node))
{
if(p.has_key_anchor(node))
{
csubstr ka = p.key_anchor(node);
printf(" &%.*s", (int)ka.len, ka.str);
}
if(p.has_key_tag(node))
{
csubstr kt = p.key_tag(node);
printf(" <%.*s>", (int)kt.len, kt.str);
}
const char code = _scalar_code_key(p, node);
csubstr k = p.key(node);
printf(" %c%.*s%c :", code, (int)k.len, k.str, code);
}
if(p.has_val_anchor(node))
{
csubstr a = p.val_anchor(node);
printf(" &%.*s'", (int)a.len, a.str);
}
if(p.has_val_tag(node))
{
csubstr vt = p.val_tag(node);
printf(" <%.*s>", (int)vt.len, vt.str);
}
if(p.has_val(node))
{
const char code = _scalar_code_val(p, node);
csubstr v = p.val(node);
printf(" %c%.*s%c", code, (int)v.len, v.str, code);
}
printf(" (%zu sibs)", (size_t)p.num_siblings(node));
++count;
if(!p.is_container(node))
{
printf("\n");
}
else
{
printf(" (%zu children)\n", (size_t)p.num_children(node));
if(print_children)
{
for(id_type i = p.first_child(node); i != NONE; i = p.next_sibling(i))
{
count = print_node(p, i, level+1, count, print_children);
}
}
}
return count;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void print_node(ConstNodeRef const& p, int level=0)
{
print_node(*p.tree(), p.id(), level, 0, true);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline id_type print_tree(const char *message, Tree const& p, id_type node=NONE)
{
printf("--------------------------------------\n");
if(message != nullptr)
printf("%s:\n", message);
id_type ret = 0;
if(!p.empty())
{
if(node == NONE)
node = p.root_id();
ret = print_node(p, node, 0, 0, true);
}
printf("#nodes=%zu vs #printed=%zu\n", (size_t)p.size(), (size_t)ret);
printf("--------------------------------------\n");
return ret;
}
inline id_type print_tree(Tree const& p, id_type node=NONE)
{
return print_tree(nullptr, p, node);
}
inline void print_tree(ConstNodeRef const& p, int level)
{
print_node(p, level);
for(ConstNodeRef ch : p.children())
{
print_tree(ch, level+1);
}
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} /* namespace yml */
} /* namespace c4 */
#endif /* C4_YML_DETAIL_PRINT_HPP_ */
-291
View File
@@ -1,291 +0,0 @@
#ifndef _C4_YML_DETAIL_STACK_HPP_
#define _C4_YML_DETAIL_STACK_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "../common.hpp"
#endif
#ifdef RYML_DBG
# include <type_traits>
#endif
#include <string.h>
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
namespace detail {
/** A lightweight contiguous stack with Small Storage
* Optimization. This is required because std::vector can throw
* exceptions, and we don't want to enforce any particular error
* mechanism. */
template<class T, id_type N=16>
class stack
{
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");
public:
enum : id_type { sso_size = N };
public:
T m_buf[size_t(N)];
T *C4_RESTRICT m_stack;
id_type m_size;
id_type m_capacity;
Callbacks m_callbacks;
public:
constexpr static bool is_contiguous() { return true; }
stack(Callbacks const& cb)
: m_buf()
, m_stack(m_buf)
, m_size(0)
, m_capacity(N)
, m_callbacks(cb) {}
stack() : stack(get_callbacks()) {}
~stack()
{
_free();
}
stack(stack const& that) RYML_NOEXCEPT : stack(that.m_callbacks)
{
resize(that.m_size);
_cp(&that);
}
stack(stack &&that) noexcept : stack(that.m_callbacks)
{
_mv(&that);
}
stack& operator= (stack const& that) RYML_NOEXCEPT
{
if(&that != this)
{
_cb(that.m_callbacks);
resize(that.m_size);
_cp(&that);
}
return *this;
}
stack& operator= (stack &&that) noexcept
{
_cb(that.m_callbacks);
_mv(&that);
return *this;
}
public:
id_type size() const { return m_size; }
id_type empty() const { return m_size == 0; }
id_type capacity() const { return m_capacity; }
void clear()
{
m_size = 0;
}
void resize(id_type sz)
{
reserve(sz);
m_size = sz;
}
void reserve(id_type sz);
void push(T const& C4_RESTRICT n)
{
_RYML_CB_ASSERT(m_callbacks, (const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
if(m_size == m_capacity)
{
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
reserve(cap);
}
m_stack[m_size] = n;
++m_size;
}
void push_top()
{
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
if(m_size == m_capacity)
{
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
reserve(cap);
}
m_stack[m_size] = m_stack[m_size - 1];
++m_size;
}
T const& C4_RESTRICT pop()
{
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
--m_size;
return m_stack[m_size];
}
C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
C4_ALWAYS_INLINE T & C4_RESTRICT top() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT top(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT top(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT bottom(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT operator[](id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
public:
using iterator = T *;
using const_iterator = T const *;
iterator begin() { return m_stack; }
iterator end () { return m_stack + m_size; }
const_iterator begin() const { return (const_iterator)m_stack; }
const_iterator end () const { return (const_iterator)m_stack + m_size; }
public:
void _free();
void _cp(stack const* C4_RESTRICT that);
void _mv(stack * that);
void _cb(Callbacks const& cb);
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::reserve(id_type sz)
{
if(sz <= m_size)
return;
if(sz <= N)
{
m_stack = m_buf;
m_capacity = N;
return;
}
T *buf = (T*) m_callbacks.m_allocate((size_t)sz * sizeof(T), m_stack, m_callbacks.m_user_data);
_RYML_CB_ASSERT(m_callbacks, ((uintptr_t)buf % alignof(T)) == 0u);
memcpy(buf, m_stack, (size_t)m_size * sizeof(T));
if(m_stack != m_buf)
{
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
}
m_stack = buf;
m_capacity = sz;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_free()
{
_RYML_CB_ASSERT(m_callbacks, m_stack != nullptr); // this structure cannot be memset() to zero
if(m_stack != m_buf)
{
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
m_stack = m_buf;
m_size = N;
m_capacity = N;
}
else
{
_RYML_CB_ASSERT(m_callbacks, m_capacity == N);
}
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_cp(stack const* C4_RESTRICT that)
{
if(that->m_stack != that->m_buf)
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
}
else
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
}
memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));
m_size = that->m_size;
m_capacity = that->m_size < N ? N : that->m_size;
m_callbacks = that->m_callbacks;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_mv(stack * that)
{
if(that->m_stack != that->m_buf)
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
m_stack = that->m_stack;
}
else
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));
m_stack = m_buf;
}
m_size = that->m_size;
m_capacity = that->m_capacity;
m_callbacks = that->m_callbacks;
// make sure no deallocation happens on destruction
_RYML_CB_ASSERT(m_callbacks, that->m_stack != m_buf);
that->m_stack = that->m_buf;
that->m_capacity = N;
that->m_size = 0;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_cb(Callbacks const& cb)
{
if(cb != m_callbacks)
{
_free();
m_callbacks = cb;
}
}
} // namespace detail
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace yml
} // namespace c4
#endif /* _C4_YML_DETAIL_STACK_HPP_ */
File diff suppressed because it is too large Load Diff
-909
View File
@@ -1,909 +0,0 @@
#ifndef _C4_YML_EMIT_HPP_
#define _C4_YML_EMIT_HPP_
/** @file emit.hpp Utilities to emit YAML and JSON. */
#ifndef _C4_YML_WRITER_HPP_
#include "./writer.hpp"
#endif
#ifndef _C4_YML_TREE_HPP_
#include "./tree.hpp"
#endif
#ifndef _C4_YML_NODE_HPP_
#include "./node.hpp"
#endif
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
/** @addtogroup doc_emit
*
* @{
*/
// fwd declarations
template<class Writer> class Emitter;
template<class OStream>
using EmitterOStream = Emitter<WriterOStream<OStream>>;
using EmitterFile = Emitter<WriterFile>;
using EmitterBuf = Emitter<WriterBuf>;
namespace detail {
inline bool is_set_(ConstNodeRef n) { return n.tree() && (n.id() != NONE); }
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Specifies the type of content to emit */
typedef enum {
EMIT_YAML = 0, ///< emit YAML
EMIT_JSON = 1 ///< emit JSON
} EmitType_e;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A lightweight object containing options to be used when emitting. */
struct EmitOptions
{
typedef enum : uint32_t {
DEFAULT_FLAGS = 0u,
JSON_ERR_ON_TAG = 1u << 0u,
JSON_ERR_ON_ANCHOR = 1u << 1u,
_JSON_ERR_MASK = JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
} EmitOptionFlags_e;
public:
/** @name option flags
*
* @{ */
C4_ALWAYS_INLINE EmitOptionFlags_e json_error_flags() const noexcept { return m_option_flags; }
EmitOptions& json_error_flags(EmitOptionFlags_e d) noexcept { m_option_flags = (EmitOptionFlags_e)(d & _JSON_ERR_MASK); return *this; }
/** @} */
public:
/** @name max depth for the emitted tree
*
* This makes the emitter fail when emitting trees exceeding the
* max_depth.
*
* @{ */
C4_ALWAYS_INLINE id_type max_depth() const noexcept { return m_max_depth; }
EmitOptions& max_depth(id_type d) noexcept { m_max_depth = d; return *this; }
static constexpr const id_type max_depth_default = 64;
/** @} */
public:
bool operator== (const EmitOptions& that) const noexcept
{
return m_max_depth == that.m_max_depth &&
m_option_flags == that.m_option_flags;
}
private:
/** @cond dev */
id_type m_max_depth{max_depth_default};
EmitOptionFlags_e m_option_flags{DEFAULT_FLAGS};
/** @endcond */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A stateful emitter, for use with a writer such as @ref WriterBuf,
* @ref WriterFile, or @ref WriterOStream */
template<class Writer>
class Emitter : public Writer
{
public:
/** Construct the emitter and its internal Writer state, using default emit options.
* @param args arguments to be forwarded to the constructor of the writer.
* */
template<class ...Args>
Emitter(Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(), m_flow(false) {}
/** Construct the emitter and its internal Writer state.
*
* @param opts EmitOptions
* @param args arguments to be forwarded to the constructor of the writer.
* */
template<class ...Args>
Emitter(EmitOptions const& opts, Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(opts), m_flow(false) {}
/** emit!
*
* When writing to a buffer, returns a substr of the emitted YAML.
* If the given buffer has insufficient space, the returned substr
* will be null and its size will be the needed space. Whatever
* the size of the buffer, it is guaranteed that no writes are
* done past its end.
*
* When writing to a file, the returned substr will be null, but its
* length will be set to the number of bytes written.
*
* @param type specify what to emit
* @param t the tree to emit
* @param id the id of the node to emit
* @param error_on_excess when true, an error is raised when the
* output buffer is too small for the emitted YAML/JSON
* */
substr emit_as(EmitType_e type, Tree const& t, id_type id, bool error_on_excess);
/** emit starting at the root node */
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true)
{
if(t.empty())
return {};
return this->emit_as(type, t, t.root_id(), error_on_excess);
}
/** emit starting at the given node */
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
}
public:
/** get the emit options for this object */
EmitOptions const& options() const noexcept { return m_opts; }
/** set the max depth for emitted trees (to prevent a stack overflow) */
void max_depth(id_type max_depth) noexcept { m_opts.max_depth(max_depth); }
/** get the max depth for emitted trees (to prevent a stack overflow) */
id_type max_depth() const noexcept { return m_opts.max_depth(); }
private:
Tree const* C4_RESTRICT m_tree;
EmitOptions m_opts;
bool m_flow;
private:
void _emit_yaml(id_type id);
void _do_visit_flow_sl(id_type id, id_type depth, id_type ilevel=0);
void _do_visit_flow_ml(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
void _do_visit_block(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
void _do_visit_block_container(id_type id, id_type depth, id_type next_level, bool do_indent);
void _do_visit_json(id_type id, id_type depth);
private:
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, id_type level);
void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
void _write_doc(id_type id);
void _write_scalar_json_dquo(csubstr s);
void _write_scalar_literal(csubstr s, id_type level, bool as_key);
void _write_scalar_folded(csubstr s, id_type level, bool as_key);
void _write_scalar_squo(csubstr s, id_type level);
void _write_scalar_dquo(csubstr s, id_type level);
void _write_scalar_plain(csubstr s, id_type level);
size_t _write_escaped_newlines(csubstr s, size_t i);
size_t _write_indented_block(csubstr s, size_t i, id_type level);
void _write_tag(csubstr tag)
{
if(!tag.begins_with('!'))
this->Writer::_do_write('!');
this->Writer::_do_write(tag);
}
enum : type_bits {
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
_keysc_json = (KEY) | ~(VAL),
_valsc_json = ~(KEY) | (VAL),
};
C4_ALWAYS_INLINE void _writek(id_type id, id_type level) { _write(m_tree->keysc(id), (m_tree->_p(id)->m_type.type & ~_valsc), level); }
C4_ALWAYS_INLINE void _writev(id_type id, id_type level) { _write(m_tree->valsc(id), (m_tree->_p(id)->m_type.type & ~_keysc), level); }
C4_ALWAYS_INLINE void _writek_json(id_type id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
C4_ALWAYS_INLINE void _writev_json(id_type id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
void _indent(id_type level, bool enabled)
{
if(enabled)
this->Writer::_do_write(' ', 2u * (size_t)level);
}
void _indent(id_type level)
{
if(!m_flow)
this->Writer::_do_write(' ', 2u * (size_t)level);
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_file Emit to file
*
* @{
*/
// emit from tree and node id -----------------------
/** (1) emit YAML to the given file, starting at the given node. A null
* file defaults to stdout. Return the number of bytes written. */
inline size_t emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(Tree const& t, id_type id, FILE *f)
{
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file, starting at the given node. A null
* file defaults to stdout. Return the number of bytes written. */
inline size_t emit_json(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(Tree const& t, id_type id, FILE *f)
{
EmitterFile em(f);
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
}
// emit from root -------------------------
/** (1) emit YAML to the given file, starting at the root node. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_yaml(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
{
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_json(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
{
EmitterFile em(f);
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
}
// emit from ConstNodeRef ------------------------
/** (1) emit YAML to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(f);
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_json(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(f);
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_ostream Emit to an STL-like ostream
*
* @{
*/
/** emit YAML to an STL-like ostream */
template<class OStream>
inline OStream& operator<< (OStream& s, Tree const& t)
{
EmitterOStream<OStream> em(s);
em.emit_as(EMIT_YAML, t);
return s;
}
/** emit YAML to an STL-like ostream
* @overload */
template<class OStream>
inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
{
if(!detail::is_set_(n))
return s;
EmitterOStream<OStream> em(s);
em.emit_as(EMIT_YAML, n);
return s;
}
/** mark a tree or node to be emitted as yaml when using @ref
* operator<<, with options. For example:
*
* ```cpp
* Tree t = parse_in_arena("{foo: bar}");
* std::cout << t; // emits YAML
* std::cout << as_yaml(t); // emits YAML, same as above
* std::cout << as_yaml(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
* ```
*
* @see @ref operator<< */
struct as_json
{
Tree const* tree;
size_t node;
EmitOptions options;
as_json(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
as_json(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
as_json(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
};
/** mark a tree or node to be emitted as yaml when using @ref
* operator<< . For example:
*
* ```cpp
* Tree t = parse_in_arena("{foo: bar}");
* std::cout << t; // emits YAML
* std::cout << as_json(t); // emits JSON
* std::cout << as_json(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
* ```
*
* @see @ref operator<< */
struct as_yaml
{
Tree const* tree;
size_t node;
EmitOptions options;
as_yaml(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
as_yaml(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
as_yaml(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
};
/** emit json to an STL-like stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_json const& j)
{
if(!j.tree || j.node == NONE)
return s;
EmitterOStream<OStream> em(j.options, s);
em.emit_as(EMIT_JSON, *j.tree, j.node, true);
return s;
}
/** emit yaml to an STL-like stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_yaml const& y)
{
if(!y.tree || y.node == NONE)
return s;
EmitterOStream<OStream> em(y.options, s);
em.emit_as(EMIT_YAML, *y.tree, y.node, true);
return s;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_buffer Emit to memory buffer
*
* @{
*/
// emit from tree and node id -----------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param t the tree to emit.
* @param id the node where to start emitting.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param t the tree to emit.
* @param id the node where to start emitting.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
}
// emit from root -------------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param t the tree; will be emitted from the root node.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, t, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param t the tree; will be emitted from the root node.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, t, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, t, error_on_excess);
}
// emit from ConstNodeRef ------------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param r the starting node.
* @param buf the output buffer.
* @param opts emit options.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, r, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, r, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param r the starting node.
* @param buf the output buffer.
* @param opts emit options.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, r, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, r, error_on_excess);
}
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_container Emit to resizeable container
*
* @{
*/
// emit from tree and node id ---------------------------
/** (1) emit+resize: emit YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML. If @p append is
* set to true, the emitted YAML is appended at the end of the container.
*
* @return a substr trimmed to the emitted YAML (excluding the initial contents, when appending) */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
size_t startpos = append ? cont->size() : 0u;
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
substr buf = to_substr(*cont).sub(startpos);
substr ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
cont->resize(startpos + ret.len);
buf = to_substr(*cont).sub(startpos);
ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/true);
}
else
{
cont->resize(startpos + ret.len);
}
return ret;
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
{
return emitrs_yaml(t, id, EmitOptions{}, cont, append);
}
/** (1) emit+resize: emit JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON. If @p append is
* set to true, the emitted YAML is appended at the end of the container.
*
* @return a substr trimmed to the emitted JSON (excluding the initial contents, when appending) */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
const size_t startpos = append ? cont->size() : 0u;
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
substr buf = to_substr(*cont).sub(startpos);
EmitterBuf em(opts, buf);
substr ret = emit_json(t, id, opts, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
cont->resize(startpos + ret.len);
buf = to_substr(*cont).sub(startpos);
ret = emit_json(t, id, opts, buf, /*error_on_excess*/true);
}
else
{
cont->resize(startpos + ret.len);
}
return ret;
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
{
return emitrs_json(t, id, EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts={})
{
CharOwningContainer c;
emitrs_yaml(t, id, opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, id_type id, EmitOptions const& opts={})
{
CharOwningContainer c;
emitrs_json(t, id, opts, &c);
return c;
}
// emit from root -------------------------
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML.
* @return a substr trimmed to the new emitted contents. */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_yaml(t, t.root_id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_yaml(t, t.root_id(), EmitOptions{}, cont, append);
}
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON.
* @return a substr trimmed to the new emitted contents. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_json(t, t.root_id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_json(t, t.root_id(), EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t, EmitOptions const& opts={})
{
CharOwningContainer c;
if(t.empty())
return c;
emitrs_yaml(t, t.root_id(), opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, EmitOptions const& opts={})
{
CharOwningContainer c;
if(t.empty())
return c;
emitrs_json(t, t.root_id(), opts, &c);
return c;
}
// emit from ConstNodeRef ------------------------
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted YAML.
* @return a substr trimmed to the new emitted contents */
template<class CharOwningContainer>
substr emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_yaml(*n.tree(), n.id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_yaml(*n.tree(), n.id(), EmitOptions{}, cont, append);
}
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted JSON.
* @return a substr trimmed to the new emitted contents */
template<class CharOwningContainer>
substr emitrs_json(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_json(*n.tree(), n.id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_json(*n.tree(), n.id(), EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts={})
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
CharOwningContainer c;
emitrs_yaml(*n.tree(), n.id(), opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(ConstNodeRef const& n, EmitOptions const& opts={})
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
CharOwningContainer c;
emitrs_json(*n.tree(), n.id(), opts, &c);
return c;
}
/** @} */
//-----------------------------------------------------------------------------
/** @cond dev */
#define RYML_DEPRECATE_EMIT \
RYML_DEPRECATED("use emit_yaml() instead. " \
"See https://github.com/biojppm/rapidyaml/issues/120")
#define RYML_DEPRECATE_EMITRS \
RYML_DEPRECATED("use emitrs_yaml() instead. " \
"See https://github.com/biojppm/rapidyaml/issues/120")
// workaround for Qt emit which is a macro;
// see https://github.com/biojppm/rapidyaml/issues/120.
// emit is defined in qobjectdefs.h (as an empty define).
#ifdef emit
#define RYML_TMP_EMIT_
#undef emit
#endif
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, id_type id, FILE *f)
{
return emit_yaml(t, id, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
{
return emit_yaml(t, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
{
return emit_yaml(r, f);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, id, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
return emit_yaml(r, buf, error_on_excess);
}
#ifdef RYML_TMP_EMIT_
#define emit
#undef RYML_TMP_EMIT_
#endif
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, id_type id, CharOwningContainer * cont)
{
return emitrs_yaml(t, id, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, id_type id)
{
return emitrs_yaml<CharOwningContainer>(t, id);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
{
return emitrs_yaml(t, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
{
return emitrs_yaml<CharOwningContainer>(t);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
{
return emitrs_yaml(n, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
{
return emitrs_yaml<CharOwningContainer>(n);
}
/** @endcond */
} // namespace yml
} // namespace c4
C4_SUPPRESS_WARNING_GCC_CLANG_POP
#undef RYML_DEPRECATE_EMIT
#undef RYML_DEPRECATE_EMITRS
#include "c4/yml/emit.def.hpp" // NOLINT
#endif /* _C4_YML_EMIT_HPP_ */
@@ -1,194 +0,0 @@
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
#define _C4_YML_EVENT_HANDLER_STACK_HPP_
#ifndef _C4_YML_DETAIL_STACK_HPP_
#include "c4/yml/detail/stack.hpp"
#endif
#ifndef _C4_YML_NODE_TYPE_HPP_
#include "c4/yml/node_type.hpp"
#endif
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#include "c4/yml/detail/dbgprint.hpp"
#endif
#ifndef _C4_YML_PARSER_STATE_HPP_
#include "c4/yml/parser_state.hpp"
#endif
#ifdef RYML_DBG
#ifndef _C4_YML_DETAIL_PRINT_HPP_
#include "c4/yml/detail/print.hpp"
#endif
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_event_handlers
* @{ */
namespace detail {
using pfn_relocate_arena = void (*)(void*, csubstr prev_arena, substr next_arena);
} // detail
/** Use this class a base of implementations of event handler to
* simplify the stack logic. */
template<class HandlerImpl, class HandlerState>
struct EventHandlerStack
{
static_assert(std::is_base_of<ParserState, HandlerState>::value,
"ParserState must be a base of HandlerState");
using state = HandlerState;
using pfn_relocate_arena = detail::pfn_relocate_arena;
public:
detail::stack<state> m_stack;
state *C4_RESTRICT m_curr; ///< current stack level: top of the stack. cached here for easier access.
state *C4_RESTRICT m_parent; ///< parent of the current stack level.
pfn_relocate_arena m_relocate_arena; ///< callback when the arena gets relocated
void * m_relocate_arena_data;
protected:
EventHandlerStack() : m_stack(), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
EventHandlerStack(Callbacks const& cb) : m_stack(cb), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
protected:
void _stack_start_parse(const char *filename, pfn_relocate_arena relocate_arena, void *relocate_arena_data)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_curr != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena_data != nullptr);
m_curr->start_parse(filename, m_curr->node_id);
m_relocate_arena = relocate_arena;
m_relocate_arena_data = relocate_arena_data;
}
void _stack_finish_parse()
{
}
protected:
void _stack_reset_root()
{
m_stack.clear();
m_stack.push({});
m_parent = nullptr;
m_curr = &m_stack.top();
}
void _stack_reset_non_root()
{
m_stack.clear();
m_stack.push({}); // parent
m_stack.push({}); // node
m_parent = &m_stack.top(1);
m_curr = &m_stack.top();
}
void _stack_push()
{
m_stack.push_top();
m_parent = &m_stack.top(1); // don't use m_curr. watch out for relocations inside the prev push
m_curr = &m_stack.top();
m_curr->reset_after_push();
}
void _stack_pop()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.size() > 1);
m_parent->reset_before_pop(*m_curr);
m_stack.pop();
m_parent = m_stack.size() > 1 ? &m_stack.top(1) : nullptr;
m_curr = &m_stack.top();
#ifdef RYML_DBG
if(m_parent)
_c4dbgpf("popped! top is now node={} (parent={})", m_curr->node_id, m_parent->node_id);
else
_c4dbgpf("popped! top is now node={} @ ROOT", m_curr->node_id);
#endif
}
protected:
// undefined at the end
#define _has_any_(bits) (static_cast<HandlerImpl const* C4_RESTRICT>(this)->template _has_any__<bits>())
bool _stack_should_push_on_begin_doc() const
{
const bool is_root = (m_stack.size() == 1u);
return is_root && (_has_any_(DOC|VAL|MAP|SEQ) || m_curr->has_children);
}
bool _stack_should_pop_on_end_doc() const
{
const bool is_root = (m_stack.size() == 1u);
return !is_root && _has_any_(DOC);
}
protected:
void _stack_relocate_to_new_arena(csubstr prev, substr curr)
{
for(state &st : m_stack)
{
if(st.line_contents.rem.is_sub(prev))
st.line_contents.rem = _stack_relocate_to_new_arena(st.line_contents.rem, prev, curr);
if(st.line_contents.full.is_sub(prev))
st.line_contents.full = _stack_relocate_to_new_arena(st.line_contents.full, prev, curr);
if(st.line_contents.stripped.is_sub(prev))
st.line_contents.stripped = _stack_relocate_to_new_arena(st.line_contents.stripped, prev, curr);
}
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena_data != nullptr);
m_relocate_arena(m_relocate_arena_data, prev, curr);
}
substr _stack_relocate_to_new_arena(csubstr s, csubstr prev, substr curr)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, prev.is_super(s));
auto pos = s.str - prev.str;
substr out = {curr.str + pos, s.len};
_RYML_CB_ASSERT(m_stack.m_callbacks, curr.is_super(out));
return out;
}
public:
/** Check whether the current parse tokens are trailing on the
* previous doc, and raise an error if they are. This function is
* called by the parse engine (not the event handler) before a doc
* is started. */
void check_trailing_doc_token() const
{
const bool is_root = (m_stack.size() == 1u);
const bool isndoc = (m_curr->flags & NDOC) != 0;
const bool suspicious = _has_any_(MAP|SEQ|VAL);
_c4dbgpf("target={} isroot={} suspicious={} ndoc={}", m_curr->node_id, is_root, suspicious, isndoc);
if((is_root || _has_any_(DOC)) && suspicious && !isndoc)
_RYML_CB_ERR_(m_stack.m_callbacks, "parse error", m_curr->pos);
}
protected:
#undef _has_any_
};
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#endif /* _C4_YML_EVENT_HANDLER_STACK_HPP_ */
-768
View File
@@ -1,768 +0,0 @@
#ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
#define _C4_YML_EVENT_HANDLER_TREE_HPP_
#ifndef _C4_YML_TREE_HPP_
#include "c4/yml/tree.hpp"
#endif
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
#include "c4/yml/event_handler_stack.hpp"
#endif
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable code
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_event_handlers
* @{ */
/** @cond dev */
struct EventHandlerTreeState : public ParserState
{
NodeData *tr_data;
};
/** @endcond */
/** The event handler to create a ryml @ref Tree. See the
* documentation for @ref doc_event_handlers, which has important
* notes about the event model used by rapidyaml. */
struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
{
/** @name types
* @{ */
using state = EventHandlerTreeState;
/** @} */
public:
/** @cond dev */
Tree *C4_RESTRICT m_tree;
id_type m_id;
size_t m_num_directives;
bool m_yaml_directive;
#ifdef RYML_DBG
#define _enable_(bits) _enable__<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
#define _disable_(bits) _disable__<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
#else
#define _enable_(bits) _enable__<bits>()
#define _disable_(bits) _disable__<bits>()
#endif
#define _has_any_(bits) _has_any__<bits>()
/** @endcond */
public:
/** @name construction and resetting
* @{ */
EventHandlerTree() : EventHandlerStack(), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
EventHandlerTree(Callbacks const& cb) : EventHandlerStack(cb), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
EventHandlerTree(Tree *tree, id_type id) : EventHandlerStack(tree->callbacks()), m_tree(tree), m_id(id), m_num_directives(), m_yaml_directive()
{
reset(tree, id);
}
void reset(Tree *tree, id_type id)
{
if(C4_UNLIKELY(!tree))
_RYML_CB_ERR(m_stack.m_callbacks, "null tree");
if(C4_UNLIKELY(id >= tree->capacity()))
_RYML_CB_ERR(tree->callbacks(), "invalid node");
if(C4_UNLIKELY(!tree->is_root(id)))
if(C4_UNLIKELY(tree->is_map(tree->parent(id))))
if(C4_UNLIKELY(!tree->has_key(id)))
_RYML_CB_ERR(tree->callbacks(), "destination node belongs to a map and has no key");
m_tree = tree;
m_id = id;
if(m_tree->is_root(id))
{
_stack_reset_root();
_reset_parser_state(m_curr, id, m_tree->root_id());
}
else
{
_stack_reset_non_root();
_reset_parser_state(m_parent, id, m_tree->parent(id));
_reset_parser_state(m_curr, id, id);
}
m_num_directives = 0;
m_yaml_directive = false;
}
/** @} */
public:
/** @name parse events
* @{ */
void start_parse(const char* filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
}
void finish_parse()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
if(m_num_directives && !m_tree->is_stream(m_tree->root_id()))
_RYML_CB_ERR_(m_stack.m_callbacks, "directives cannot be used without a document", {});
this->_stack_finish_parse();
/* This pointer is temporary. Remember that:
*
* - this handler object may be held by the user
* - it may be used with a temporary tree inside the parse function
* - when the parse function returns the temporary tree, its address
* will change
*
* As a result, the user could try to read the tree from m_tree, and
* end up reading the stale temporary object.
*
* So it is better to clear it here; then the user will get an obvious
* segfault if reading from m_tree. */
m_tree = nullptr;
}
void cancel_parse()
{
m_tree = nullptr;
}
/** @} */
public:
/** @name YAML stream events */
/** @{ */
C4_ALWAYS_INLINE void begin_stream() const noexcept { /*nothing to do*/ }
C4_ALWAYS_INLINE void end_stream() const noexcept { /*nothing to do*/ }
/** @} */
public:
/** @name YAML document events */
/** @{ */
/** implicit doc start (without ---) */
void begin_doc()
{
_c4dbgp("begin_doc");
if(_stack_should_push_on_begin_doc())
{
_c4dbgp("push!");
_set_root_as_stream();
_push();
_enable_(DOC);
}
}
/** implicit doc end (without ...) */
void end_doc()
{
_c4dbgp("end_doc");
if(_stack_should_pop_on_end_doc())
{
_remove_speculative();
_c4dbgp("pop!");
_pop();
}
}
/** explicit doc start, with --- */
void begin_doc_expl()
{
_c4dbgp("begin_doc_expl");
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id);
if(!m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
{
_c4dbgp("ensure stream");
_set_root_as_stream();
id_type first = m_tree->first_child(m_tree->root_id());
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u);
if(m_tree->has_children(first) || m_tree->is_val(first))
{
_c4dbgp("push!");
_push();
}
else
{
_c4dbgp("tweak");
_push();
_remove_speculative();
m_curr->node_id = m_tree->last_child(m_tree->root_id());
m_curr->tr_data = m_tree->_p(m_curr->node_id);
}
}
else
{
_c4dbgp("push!");
_push();
}
_enable_(DOC);
}
/** explicit doc end, with ... */
void end_doc_expl()
{
_c4dbgp("end_doc_expl");
_remove_speculative();
if(_stack_should_pop_on_end_doc())
{
_c4dbgp("pop!");
_pop();
}
m_yaml_directive = false;
}
/** @} */
public:
/** @name YAML map events */
/** @{ */
void begin_map_key_flow()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_map_key_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_map_val_flow()
{
_c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(MAP|FLOW_SL);
_save_loc();
_push();
}
void begin_map_val_block()
{
_c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(MAP|BLOCK);
_save_loc();
_push();
}
void end_map()
{
_pop();
_c4dbgpf("node[{}]: end_map_val", m_curr->node_id);
}
/** @} */
public:
/** @name YAML seq events */
/** @{ */
void begin_seq_key_flow()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_seq_key_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_seq_val_flow()
{
_c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(SEQ|FLOW_SL);
_save_loc();
_push();
}
void begin_seq_val_block()
{
_c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(SEQ|BLOCK);
_save_loc();
_push();
}
void end_seq()
{
_pop();
_c4dbgpf("node[{}]: end_seq_val", m_curr->node_id);
}
/** @} */
public:
/** @name YAML structure events */
/** @{ */
void add_sibling()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id));
NodeData const* prev = m_tree->m_buf; // watchout against relocation of the tree nodes
_set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
if(prev != m_tree->m_buf)
_refresh_after_relocation();
_c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
}
/** set the previous val as the first key of a new map, with flow style.
*
* See the documentation for @ref doc_event_handlers, which has
* important notes about this event.
*/
void actually_val_is_first_key_of_new_map_flow()
{
if(C4_UNLIKELY(m_tree->is_container(m_curr->node_id)))
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id));
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id));
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id));
const NodeData tmp = _val2key_(*m_curr->tr_data);
_disable_(_VALMASK|VAL_STYLE);
m_curr->tr_data->m_val = {};
begin_map_val_flow();
m_curr->tr_data->m_type = tmp.m_type;
m_curr->tr_data->m_key = tmp.m_key;
}
/** like its flow counterpart, but this function can only be
* called after the end of a flow-val at root or doc level.
*
* See the documentation for @ref doc_event_handlers, which has
* important notes about this event.
*/
void actually_val_is_first_key_of_new_map_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
/** @} */
public:
/** @name YAML scalar events */
/** @{ */
C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
{
_c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
m_curr->tr_data->m_key.scalar = {};
_enable_(KEY|KEY_PLAIN|KEYNIL);
}
C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
{
_c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
m_curr->tr_data->m_val.scalar = {};
_enable_(VAL|VAL_PLAIN|VALNIL);
}
C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_PLAIN);
}
C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_PLAIN);
}
C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_DQUO);
}
C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_DQUO);
}
C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_SQUO);
}
C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_SQUO);
}
C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_LITERAL);
}
C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_LITERAL);
}
C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_FOLDED);
}
C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_FOLDED);
}
C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
{
_enable_(KEY_UNFILT);
}
C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
{
_enable_(VAL_UNFILT);
}
/** @} */
public:
/** @name YAML anchor/reference events */
/** @{ */
void set_key_anchor(csubstr anchor)
{
_c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(KEYREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(KEYANCH);
m_curr->tr_data->m_key.anchor = anchor;
}
void set_val_anchor(csubstr anchor)
{
_c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(VALREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(VALANCH);
m_curr->tr_data->m_val.anchor = anchor;
}
void set_key_ref(csubstr ref)
{
_c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(KEYANCH)))
_RYML_CB_ERR_(m_tree->callbacks(), "key cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
_enable_(KEY|KEYREF);
m_curr->tr_data->m_key.anchor = ref.sub(1);
m_curr->tr_data->m_key.scalar = ref;
}
void set_val_ref(csubstr ref)
{
_c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(VALANCH)))
_RYML_CB_ERR_(m_tree->callbacks(), "val cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
_enable_(VAL|VALREF);
m_curr->tr_data->m_val.anchor = ref.sub(1);
m_curr->tr_data->m_val.scalar = ref;
}
/** @} */
public:
/** @name YAML tag events */
/** @{ */
void set_key_tag(csubstr tag) noexcept
{
_c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
_enable_(KEYTAG);
m_curr->tr_data->m_key.tag = tag;
}
void set_val_tag(csubstr tag) noexcept
{
_c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
_enable_(VALTAG);
m_curr->tr_data->m_val.tag = tag;
}
/** @} */
public:
/** @name YAML directive events */
/** @{ */
C4_NO_INLINE void add_directive(csubstr directive)
{
_c4dbgpf("% directive! {}", directive);
_RYML_CB_ASSERT(m_tree->callbacks(), directive.begins_with('%'));
if(directive.begins_with("%TAG"))
{
if(C4_UNLIKELY(!m_tree->add_tag_directive(directive)))
_RYML_CB_ERR_(m_stack.m_callbacks, "failed to add directive", m_curr->pos);
}
else if(directive.begins_with("%YAML"))
{
_c4dbgpf("%YAML directive! ignoring...: {}", directive);
if(C4_UNLIKELY(m_yaml_directive))
_RYML_CB_ERR_(m_stack.m_callbacks, "multiple yaml directives", m_curr->pos);
m_yaml_directive = true;
}
else
{
_c4dbgpf("unknown directive! ignoring... {}", directive);
}
++m_num_directives;
}
/** @} */
public:
/** @name arena functions */
/** @{ */
substr alloc_arena(size_t len)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
csubstr prev = m_tree->arena();
substr out = m_tree->alloc_arena(len);
substr curr = m_tree->arena();
if(curr.str != prev.str)
_stack_relocate_to_new_arena(prev, curr);
return out;
}
substr alloc_arena(size_t len, substr *relocated)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
csubstr prev = m_tree->arena();
if(!prev.is_super(*relocated))
return alloc_arena(len);
substr out = alloc_arena(len);
substr curr = m_tree->arena();
if(curr.str != prev.str)
*relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
return out;
}
/** @} */
public:
/** @cond dev */
void _reset_parser_state(state* st, id_type parse_root, id_type node)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_set_state_(st, node);
const NodeType type = m_tree->type(node);
#ifdef RYML_DBG
char flagbuf[80];
_c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
#endif
if(type == NOTYPE)
{
_c4dbgpf("node[{}] is notype", node);
if(m_tree->is_root(parse_root))
{
_c4dbgpf("node[{}] is root", node);
st->flags |= RUNK|RTOP;
}
else
{
_c4dbgpf("node[{}] is not root. setting USTY", node);
st->flags |= USTY;
}
}
else if(type.is_map())
{
_c4dbgpf("node[{}] is map", node);
st->flags |= RMAP|USTY;
}
else if(type.is_seq())
{
_c4dbgpf("node[{}] is map", node);
st->flags |= RSEQ|USTY;
}
else if(type.has_key())
{
_c4dbgpf("node[{}] has key. setting USTY", node);
st->flags |= USTY;
}
else
{
_RYML_CB_ERR(m_tree->callbacks(), "cannot append to node");
}
if(type.is_doc())
{
_c4dbgpf("node[{}] is doc", node);
st->flags |= RDOC;
}
#ifdef RYML_DBG
_c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
#endif
}
/** push a new parent, add a child to the new parent, and set the
* child as the current node */
void _push()
{
_stack_push();
NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
m_curr->tr_data = m_tree->_p(m_curr->node_id);
if(prev != m_tree->m_buf)
_refresh_after_relocation();
_c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
}
/** end the current scope */
void _pop()
{
_remove_speculative_with_parent();
_stack_pop();
}
public:
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept
{
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type | bits);
}
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept
{
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type & (~bits));
}
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool _has_any__() const noexcept
{
return (m_curr->tr_data->m_type.type & bits) != 0;
}
public:
C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
{
s->node_id = id;
s->tr_data = m_tree->_p(id);
}
void _refresh_after_relocation()
{
_c4dbgp("tree: refreshing stack data after tree data relocation");
for(auto &st : m_stack)
st.tr_data = m_tree->_p(st.node_id);
}
void _set_root_as_stream()
{
_c4dbgp("set root as stream");
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->root_id() == 0u);
_RYML_CB_ASSERT(m_tree->callbacks(), m_curr->node_id == 0u);
const bool hack = !m_tree->has_children(m_curr->node_id) && !m_tree->is_val(m_curr->node_id);
if(hack)
m_tree->_p(m_tree->root_id())->m_type.add(VAL);
m_tree->set_root_as_stream();
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())));
if(hack)
m_tree->_p(m_tree->first_child(m_tree->root_id()))->m_type.rem(VAL);
_set_state_(m_curr, m_tree->root_id());
}
static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
{
NodeData r = d;
r.m_key = d.m_val;
r.m_val = {};
r.m_type = d.m_type;
static_assert((_VALMASK >> 1u) == _KEYMASK, "required for this function to work");
static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
r.m_type.type = ((d.m_type.type & (_VALMASK|VAL_STYLE)) >> 1u);
r.m_type.type = (r.m_type.type & ~(_VALMASK|VAL_STYLE));
r.m_type.type = (r.m_type.type | KEY);
return r;
}
void _remove_speculative()
{
_c4dbgp("remove speculative node");
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
if(m_tree->has_parent(last_added))
if(m_tree->_p(last_added)->m_type == NOTYPE)
m_tree->remove(last_added);
}
void _remove_speculative_with_parent()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_parent(last_added));
if(m_tree->_p(last_added)->m_type == NOTYPE)
{
_c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
m_tree->remove(last_added);
}
}
C4_ALWAYS_INLINE void _save_loc()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
}
#undef _enable_
#undef _disable_
#undef _has_any_
/** @endcond */
};
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
C4_SUPPRESS_WARNING_MSVC_POP
#endif /* _C4_YML_EVENT_HANDLER_TREE_HPP_ */
-18
View File
@@ -1,18 +0,0 @@
#ifndef C4_YML_EXPORT_HPP_
#define C4_YML_EXPORT_HPP_
#ifdef _WIN32
#ifdef RYML_SHARED
#ifdef RYML_EXPORTS
#define RYML_EXPORT __declspec(dllexport)
#else
#define RYML_EXPORT __declspec(dllimport)
#endif
#else
#define RYML_EXPORT
#endif
#else
#define RYML_EXPORT
#endif
#endif /* C4_YML_EXPORT_HPP_ */
-512
View File
@@ -1,512 +0,0 @@
#ifndef _C4_YML_FILTER_PROCESSOR_HPP_
#define _C4_YML_FILTER_PROCESSOR_HPP_
#include "c4/yml/common.hpp"
#ifdef RYML_DBG
#include "c4/charconv.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#endif
namespace c4 {
namespace yml {
/** @defgroup doc_filter_processors Scalar filter processors
*
* These are internal classes used by @ref ParseEngine to parse the
* scalars; normally there is no reason for a user to be manually
* using these classes.
*
* @ingroup doc_parse */
/** @{ */
//-----------------------------------------------------------------------------
/** Filters an input string into a different output string */
struct FilterProcessorSrcDst
{
csubstr src;
substr dst;
size_t rpos; ///< read position
size_t wpos; ///< write position
C4_ALWAYS_INLINE FilterProcessorSrcDst(csubstr src_, substr dst_) noexcept
: src(src_)
, dst(dst_)
, rpos(0)
, wpos(0)
{
RYML_ASSERT(!dst.overlaps(src));
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(dst.str, wpos <= dst.len ? wpos : dst.len); }
C4_ALWAYS_INLINE FilterResult result() const noexcept
{
FilterResult ret;
ret.str.str = wpos <= dst.len ? dst.str : nullptr;
ret.str.len = wpos;
return ret;
}
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE bool skipped_chars() const noexcept { return wpos != rpos; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
C4_ALWAYS_INLINE void set_at(size_t pos, char c) noexcept // NOLINT(readability-make-member-function-const)
{
RYML_ASSERT(pos < wpos);
dst.str[pos] = c;
}
C4_ALWAYS_INLINE void set(char c) noexcept
{
if(wpos < dst.len)
dst.str[wpos] = c;
++wpos;
}
C4_ALWAYS_INLINE void set(char c, size_t num) noexcept
{
RYML_ASSERT(num > 0);
if(wpos + num <= dst.len)
memset(dst.str + wpos, c, num);
wpos += num;
}
C4_ALWAYS_INLINE void copy() noexcept
{
RYML_ASSERT(rpos < src.len);
if(wpos < dst.len)
dst.str[wpos] = src.str[rpos];
++wpos;
++rpos;
}
C4_ALWAYS_INLINE void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
if(wpos + num <= dst.len)
memcpy(dst.str + wpos, src.str + rpos, num);
wpos += num;
rpos += num;
}
C4_ALWAYS_INLINE void translate_esc(char c) noexcept
{
if(wpos < dst.len)
dst.str[wpos] = c;
++wpos;
rpos += 2;
}
C4_ALWAYS_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(rpos+nr <= src.len);
if(wpos+nw <= dst.len)
memcpy(dst.str + wpos, s, nw);
wpos += nw;
rpos += 1 + nr;
}
C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
translate_esc_bulk(s, nw, nr);
}
};
//-----------------------------------------------------------------------------
// filter in place
// debugging scaffold
/** @cond dev */
#if defined(RYML_DBG) && 0
#define _c4dbgip(...) _c4dbgpf(__VA_ARGS__)
#else
#define _c4dbgip(...)
#endif
/** @endcond */
/** Filters in place. While the result may be larger than the source,
* any extending happens only at the end of the string. Consequently,
* it's impossible for characters to be left unfiltered.
*
* @see FilterProcessorInplaceMidExtending */
struct FilterProcessorInplaceEndExtending
{
substr src; ///< the subject string
size_t wcap; ///< write capacity - the capacity of the subject string's buffer
size_t rpos; ///< read position
size_t wpos; ///< write position
C4_ALWAYS_INLINE FilterProcessorInplaceEndExtending(substr src_, size_t wcap_) noexcept
: src(src_)
, wcap(wcap_)
, rpos(0)
, wpos(0)
{
RYML_ASSERT(wcap >= src.len);
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE FilterResult result() const noexcept
{
_c4dbgip("inplace: wpos={} wcap={} small={}", wpos, wcap, wpos > rpos);
FilterResult ret;
ret.str.str = (wpos <= wcap) ? src.str : nullptr;
ret.str.len = wpos;
return ret;
}
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
void set_at(size_t pos, char c) noexcept
{
RYML_ASSERT(pos < wpos);
const size_t save = wpos;
wpos = pos;
set(c);
wpos = save;
}
void set(char c) noexcept
{
if(wpos < wcap) // respect write-capacity
src.str[wpos] = c;
++wpos;
}
void set(char c, size_t num) noexcept
{
RYML_ASSERT(num);
if(wpos + num <= wcap) // respect write-capacity
memset(src.str + wpos, c, num);
wpos += num;
}
void copy() noexcept
{
RYML_ASSERT(wpos <= rpos);
RYML_ASSERT(rpos < src.len);
if(wpos < wcap) // respect write-capacity
src.str[wpos] = src.str[rpos];
++rpos;
++wpos;
}
void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
RYML_ASSERT(wpos <= rpos);
if(wpos + num <= wcap) // respect write-capacity
{
if(wpos + num <= rpos) // there is no overlap
memcpy(src.str + wpos, src.str + rpos, num);
else // there is overlap
memmove(src.str + wpos, src.str + rpos, num);
}
rpos += num;
wpos += num;
}
void translate_esc(char c) noexcept
{
RYML_ASSERT(rpos + 2 <= src.len);
RYML_ASSERT(wpos <= rpos);
if(wpos < wcap) // respect write-capacity
src.str[wpos] = c;
rpos += 2; // add 1u to account for the escape character
++wpos;
}
void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(nw <= nr + 1u);
RYML_ASSERT(rpos+nr <= src.len);
RYML_ASSERT(wpos <= rpos);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
RYML_ASSERT(wpos_next <= rpos_next);
if(wpos_next <= wcap)
memcpy(src.str + wpos, s, nw);
rpos = rpos_next;
wpos = wpos_next;
}
C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
translate_esc_bulk(s, nw, nr);
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Filters in place. The result may be larger than the source, and
* extending may happen anywhere. As a result some characters may be
* left unfiltered when there is no slack in the buffer and the
* write-position would overlap the read-position. Consequently, it's
* possible for characters to be left unfiltered. In YAML, this
* happens only with double-quoted strings, and only with a small
* number of escape sequences such as `\L` which is substituted by three
* bytes. These escape sequences cause a call to translate_esc_extending()
* which is the only entry point to this unfiltered situation.
*
* @see FilterProcessorInplaceMidExtending */
struct FilterProcessorInplaceMidExtending
{
substr src; ///< the subject string
size_t wcap; ///< write capacity - the capacity of the subject string's buffer
size_t rpos; ///< read position
size_t wpos; ///< write position
size_t maxcap; ///< the max capacity needed for filtering the string. This may be larger than the final string size.
bool unfiltered_chars; ///< number of characters that were not added to wpos from lack of capacity
C4_ALWAYS_INLINE FilterProcessorInplaceMidExtending(substr src_, size_t wcap_) noexcept
: src(src_)
, wcap(wcap_)
, rpos(0)
, wpos(0)
, maxcap(src.len)
, unfiltered_chars(false)
{
RYML_ASSERT(wcap >= src.len);
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE FilterResultExtending result() const noexcept
{
_c4dbgip("inplace: wpos={} wcap={} unfiltered={} maxcap={}", this->wpos, this->wcap, this->unfiltered_chars, this->maxcap);
FilterResultExtending ret;
ret.str.str = (wpos <= wcap && !unfiltered_chars) ? src.str : nullptr;
ret.str.len = wpos;
ret.reqlen = maxcap;
return ret;
}
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
void set_at(size_t pos, char c) noexcept
{
RYML_ASSERT(pos < wpos);
const size_t save = wpos;
wpos = pos;
set(c);
wpos = save;
}
void set(char c) noexcept
{
if(wpos < wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
src.str[wpos] = c;
}
else
{
_c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void set(char c, size_t num) noexcept
{
RYML_ASSERT(num);
if(wpos + num <= wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
memset(src.str + wpos, c, num);
}
else
{
_c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+num > maxcap ? wpos+num : maxcap));
unfiltered_chars = true;
}
wpos += num;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void copy() noexcept
{
RYML_ASSERT(rpos < src.len);
if(wpos < wcap) // respect write-capacity
{
if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
src.str[wpos] = src.str[rpos];
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
++rpos;
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
if(wpos + num <= wcap) // respect write-capacity
{
if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
{
if(wpos + num <= rpos) // there is no overlap
memcpy(src.str + wpos, src.str + rpos, num);
else // there is overlap
memmove(src.str + wpos, src.str + rpos, num);
}
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
unfiltered_chars = true;
}
rpos += num;
wpos += num;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void translate_esc(char c) noexcept
{
RYML_ASSERT(rpos + 2 <= src.len);
if(wpos < wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
src.str[wpos] = c;
}
else
{
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
rpos += 2;
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
C4_NO_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(nr+1u >= nw);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
if(wpos_next <= wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars) // write only if wpos is behind rpos
memcpy(src.str + wpos, s, nw);
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
unfiltered_chars = true;
}
rpos = rpos_next;
wpos = wpos_next;
maxcap = wpos > maxcap ? wpos : maxcap;
}
C4_NO_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(rpos+nr <= src.len);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
if(wpos_next <= rpos_next) // read and write do not overlap. just do a vanilla copy.
{
if((wpos_next <= wcap) && !unfiltered_chars)
memcpy(src.str + wpos, s, nw);
rpos = rpos_next;
wpos = wpos_next;
maxcap = wpos > maxcap ? wpos : maxcap;
}
else // there is overlap. move the (to-be-read) string to the right.
{
const size_t excess = wpos_next - rpos_next;
RYML_ASSERT(wpos_next > rpos_next);
if(src.len + excess <= wcap) // ensure we do not go past the end
{
RYML_ASSERT(rpos+nr+excess <= src.len);
if(wpos_next <= wcap)
{
if(!unfiltered_chars)
{
memmove(src.str + wpos_next, src.str + rpos_next, src.len - rpos_next);
memcpy(src.str + wpos, s, nw);
}
rpos = wpos_next; // wpos, not rpos
}
else
{
rpos = rpos_next;
//const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true);
unfiltered_chars = true;
}
wpos = wpos_next;
// extend the string up to capacity
src.len += excess;
maxcap = wpos > maxcap ? wpos : maxcap;
}
else
{
//const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
RYML_ASSERT(rpos_next <= src.len);
const size_t required_size = wpos_next + (src.len - rpos_next);
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, required_size > maxcap ? required_size : maxcap);
RYML_ASSERT(required_size > wcap);
unfiltered_chars = true;
maxcap = required_size > maxcap ? required_size : maxcap;
wpos = wpos_next;
rpos = rpos_next;
}
}
}
};
#undef _c4dbgip
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_FILTER_PROCESSOR_HPP_ */
-24
View File
@@ -1,24 +0,0 @@
#ifndef _C4_YML_FWD_HPP_
#define _C4_YML_FWD_HPP_
/** @file fwd.hpp forward declarations */
namespace c4 {
namespace yml {
struct NodeScalar;
struct NodeInit;
struct NodeData;
struct NodeType;
class NodeRef;
class ConstNodeRef;
class Tree;
struct ReferenceResolver;
template<class EventHandler> class ParseEngine;
struct EventHandlerTree;
using Parser = ParseEngine<EventHandlerTree>;
} // namespace c4
} // namespace yml
#endif /* _C4_YML_FWD_HPP_ */
File diff suppressed because it is too large Load Diff
-282
View File
@@ -1,282 +0,0 @@
#ifndef C4_YML_NODE_TYPE_HPP_
#define C4_YML_NODE_TYPE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
C4_SUPPRESS_WARNING_MSVC_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
#if __GNUC__ >= 6
C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
#endif
namespace c4 {
namespace yml {
/** @addtogroup doc_node_type
*
* @{
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** the integral type necessary to cover all the bits for NodeType_e */
using type_bits = uint32_t;
/** a bit mask for marking node types and styles */
typedef enum : type_bits {
#define __(v) (type_bits(1) << v) // a convenience define, undefined below // NOLINT
NOTYPE = 0, ///< no node type or style is set
KEY = __(0), ///< is member of a map
VAL = __(1), ///< a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or SEQ
MAP = __(2), ///< a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
SEQ = __(3), ///< a seq: a parent of VAL/SEQ/MAP nodes
DOC = __(4), ///< a document
STREAM = __(5)|SEQ, ///< a stream: a seq of docs
KEYREF = __(6), ///< a *reference: the key references an &anchor
VALREF = __(7), ///< a *reference: the val references an &anchor
KEYANCH = __(8), ///< the key has an &anchor
VALANCH = __(9), ///< the val has an &anchor
KEYTAG = __(10), ///< the key has a tag
VALTAG = __(11), ///< the val has a tag
KEYNIL = __(12), ///< the key is null (eg `{ : b}` results in a null key)
VALNIL = __(13), ///< the val is null (eg `{a : }` results in a null val)
_TYMASK = __(14)-1, ///< all the bits up to here
//
// unfiltered flags:
//
KEY_UNFILT = __(14), ///< the key scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
VAL_UNFILT = __(15), ///< the val scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
//
// style flags:
//
FLOW_SL = __(16), ///< mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,key2: val2}')
FLOW_ML = __(17), ///< (NOT IMPLEMENTED, work in progress) mark container with multi-line flow style (seqs as '[\n val1,\n val2\n], maps as '{\n key: val,\n key2: val2\n}')
BLOCK = __(18), ///< mark container with block style (seqs as '- val\n', maps as 'key: val')
KEY_LITERAL = __(19), ///< mark key scalar as multiline, block literal |
VAL_LITERAL = __(20), ///< mark val scalar as multiline, block literal |
KEY_FOLDED = __(21), ///< mark key scalar as multiline, block folded >
VAL_FOLDED = __(22), ///< mark val scalar as multiline, block folded >
KEY_SQUO = __(23), ///< mark key scalar as single quoted '
VAL_SQUO = __(24), ///< mark val scalar as single quoted '
KEY_DQUO = __(25), ///< mark key scalar as double quoted "
VAL_DQUO = __(26), ///< mark val scalar as double quoted "
KEY_PLAIN = __(27), ///< mark key scalar as plain scalar (unquoted, even when multiline)
VAL_PLAIN = __(28), ///< mark val scalar as plain scalar (unquoted, even when multiline)
//
// type combination masks:
//
KEYVAL = KEY|VAL,
KEYSEQ = KEY|SEQ,
KEYMAP = KEY|MAP,
DOCMAP = DOC|MAP,
DOCSEQ = DOC|SEQ,
DOCVAL = DOC|VAL,
//
// style combination masks:
//
SCALAR_LITERAL = KEY_LITERAL|VAL_LITERAL,
SCALAR_FOLDED = KEY_FOLDED|VAL_FOLDED,
SCALAR_SQUO = KEY_SQUO|VAL_SQUO,
SCALAR_DQUO = KEY_DQUO|VAL_DQUO,
SCALAR_PLAIN = KEY_PLAIN|VAL_PLAIN,
KEYQUO = KEY_SQUO|KEY_DQUO|KEY_FOLDED|KEY_LITERAL, ///< key style is one of ', ", > or |
VALQUO = VAL_SQUO|VAL_DQUO|VAL_FOLDED|VAL_LITERAL, ///< val style is one of ', ", > or |
KEY_STYLE = KEY_LITERAL|KEY_FOLDED|KEY_SQUO|KEY_DQUO|KEY_PLAIN, ///< mask of all the scalar styles for key (not container styles!)
VAL_STYLE = VAL_LITERAL|VAL_FOLDED|VAL_SQUO|VAL_DQUO|VAL_PLAIN, ///< mask of all the scalar styles for val (not container styles!)
SCALAR_STYLE = KEY_STYLE|VAL_STYLE,
CONTAINER_STYLE_FLOW = FLOW_SL|FLOW_ML,
CONTAINER_STYLE_BLOCK = BLOCK,
CONTAINER_STYLE = FLOW_SL|FLOW_ML|BLOCK,
STYLE = SCALAR_STYLE | CONTAINER_STYLE,
//
// mixed masks
_KEYMASK = KEY | KEYQUO | KEYANCH | KEYREF | KEYTAG,
_VALMASK = VAL | VALQUO | VALANCH | VALREF | VALTAG,
#undef __
} NodeType_e;
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator| (NodeType_e lhs, NodeType_e rhs) noexcept { return (NodeType_e)(((type_bits)lhs) | ((type_bits)rhs)); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator& (NodeType_e lhs, NodeType_e rhs) noexcept { return (NodeType_e)(((type_bits)lhs) & ((type_bits)rhs)); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator>> (NodeType_e bits, uint32_t n) noexcept { return (NodeType_e)(((type_bits)bits) >> n); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator<< (NodeType_e bits, uint32_t n) noexcept { return (NodeType_e)(((type_bits)bits) << n); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator~ (NodeType_e bits) noexcept { return (NodeType_e)(~(type_bits)bits); }
C4_ALWAYS_INLINE NodeType_e& operator&= (NodeType_e &subject, NodeType_e bits) noexcept { subject = (NodeType_e)((type_bits)subject & (type_bits)bits); return subject; }
C4_ALWAYS_INLINE NodeType_e& operator|= (NodeType_e &subject, NodeType_e bits) noexcept { subject = (NodeType_e)((type_bits)subject | (type_bits)bits); return subject; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** wraps a NodeType_e element with some syntactic sugar and predicates */
struct RYML_EXPORT NodeType
{
public:
NodeType_e type;
public:
C4_ALWAYS_INLINE NodeType() noexcept : type(NOTYPE) {}
C4_ALWAYS_INLINE NodeType(NodeType_e t) noexcept : type(t) {}
C4_ALWAYS_INLINE NodeType(type_bits t) noexcept : type((NodeType_e)t) {}
C4_ALWAYS_INLINE bool has_any(NodeType_e t) const noexcept { return (type & t) != 0u; }
C4_ALWAYS_INLINE bool has_all(NodeType_e t) const noexcept { return (type & t) == t; }
C4_ALWAYS_INLINE bool has_none(NodeType_e t) const noexcept { return (type & t) == 0; }
C4_ALWAYS_INLINE void set(NodeType_e t) noexcept { type = t; }
C4_ALWAYS_INLINE void add(NodeType_e t) noexcept { type = (type|t); }
C4_ALWAYS_INLINE void rem(NodeType_e t) noexcept { type = (type & ~t); }
C4_ALWAYS_INLINE void addrem(NodeType_e bits_to_add, NodeType_e bits_to_remove) noexcept { type |= bits_to_add; type &= ~bits_to_remove; }
C4_ALWAYS_INLINE void clear() noexcept { type = NOTYPE; }
public:
C4_ALWAYS_INLINE operator NodeType_e & C4_RESTRICT () noexcept { return type; }
C4_ALWAYS_INLINE operator NodeType_e const& C4_RESTRICT () const noexcept { return type; }
public:
/** @name node type queries
* @{ */
/** return a preset string based on the node type */
C4_ALWAYS_INLINE const char *type_str() const noexcept { return type_str(type); }
/** return a preset string based on the node type */
static const char* type_str(NodeType_e t) noexcept;
/** fill a string with the node type flags. If the string is small, returns {null, len} */
C4_ALWAYS_INLINE csubstr type_str(substr buf) const noexcept { return type_str(buf, type); }
/** fill a string with the node type flags. If the string is small, returns {null, len} */
static csubstr type_str(substr buf, NodeType_e t) noexcept;
public:
/** @name node type queries
* @{ */
C4_ALWAYS_INLINE bool is_notype() const noexcept { return type == NOTYPE; }
C4_ALWAYS_INLINE bool is_stream() const noexcept { return ((type & STREAM) == STREAM) != 0; }
C4_ALWAYS_INLINE bool is_doc() const noexcept { return (type & DOC) != 0; }
C4_ALWAYS_INLINE bool is_container() const noexcept { return (type & (MAP|SEQ|STREAM)) != 0; }
C4_ALWAYS_INLINE bool is_map() const noexcept { return (type & MAP) != 0; }
C4_ALWAYS_INLINE bool is_seq() const noexcept { return (type & SEQ) != 0; }
C4_ALWAYS_INLINE bool has_key() const noexcept { return (type & KEY) != 0; }
C4_ALWAYS_INLINE bool has_val() const noexcept { return (type & VAL) != 0; }
C4_ALWAYS_INLINE bool is_val() const noexcept { return (type & KEYVAL) == VAL; }
C4_ALWAYS_INLINE bool is_keyval() const noexcept { return (type & KEYVAL) == KEYVAL; }
C4_ALWAYS_INLINE bool key_is_null() const noexcept { return (type & KEYNIL) != 0; }
C4_ALWAYS_INLINE bool val_is_null() const noexcept { return (type & VALNIL) != 0; }
C4_ALWAYS_INLINE bool has_key_tag() const noexcept { return (type & KEYTAG) != 0; }
C4_ALWAYS_INLINE bool has_val_tag() const noexcept { return (type & VALTAG) != 0; }
C4_ALWAYS_INLINE bool has_key_anchor() const noexcept { return (type & KEYANCH) != 0; }
C4_ALWAYS_INLINE bool has_val_anchor() const noexcept { return (type & VALANCH) != 0; }
C4_ALWAYS_INLINE bool has_anchor() const noexcept { return (type & (KEYANCH|VALANCH)) != 0; }
C4_ALWAYS_INLINE bool is_key_ref() const noexcept { return (type & KEYREF) != 0; }
C4_ALWAYS_INLINE bool is_val_ref() const noexcept { return (type & VALREF) != 0; }
C4_ALWAYS_INLINE bool is_ref() const noexcept { return (type & (KEYREF|VALREF)) != 0; }
C4_ALWAYS_INLINE bool is_key_unfiltered() const noexcept { return (type & (KEY_UNFILT)) != 0; }
C4_ALWAYS_INLINE bool is_val_unfiltered() const noexcept { return (type & (VAL_UNFILT)) != 0; }
RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor() const noexcept { return has_key_anchor(); }
RYML_DEPRECATED("use has_val_anchor()") bool is_val_anchor() const noexcept { return has_val_anchor(); }
RYML_DEPRECATED("use has_anchor()") bool is_anchor() const noexcept { return has_anchor(); }
RYML_DEPRECATED("use has_anchor() || is_ref()") bool is_anchor_or_ref() const noexcept { return has_anchor() || is_ref(); }
/** @} */
public:
/** @name style functions
* @{ */
C4_ALWAYS_INLINE bool is_container_styled() const noexcept { return (type & (CONTAINER_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_block() const noexcept { return (type & (BLOCK)) != 0; }
C4_ALWAYS_INLINE bool is_flow_sl() const noexcept { return (type & (FLOW_SL)) != 0; }
C4_ALWAYS_INLINE bool is_flow_ml() const noexcept { return (type & (FLOW_ML)) != 0; }
C4_ALWAYS_INLINE bool is_flow() const noexcept { return (type & (FLOW_ML|FLOW_SL)) != 0; }
C4_ALWAYS_INLINE bool is_key_styled() const noexcept { return (type & (KEY_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_val_styled() const noexcept { return (type & (VAL_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_key_literal() const noexcept { return (type & (KEY_LITERAL)) != 0; }
C4_ALWAYS_INLINE bool is_val_literal() const noexcept { return (type & (VAL_LITERAL)) != 0; }
C4_ALWAYS_INLINE bool is_key_folded() const noexcept { return (type & (KEY_FOLDED)) != 0; }
C4_ALWAYS_INLINE bool is_val_folded() const noexcept { return (type & (VAL_FOLDED)) != 0; }
C4_ALWAYS_INLINE bool is_key_squo() const noexcept { return (type & (KEY_SQUO)) != 0; }
C4_ALWAYS_INLINE bool is_val_squo() const noexcept { return (type & (VAL_SQUO)) != 0; }
C4_ALWAYS_INLINE bool is_key_dquo() const noexcept { return (type & (KEY_DQUO)) != 0; }
C4_ALWAYS_INLINE bool is_val_dquo() const noexcept { return (type & (VAL_DQUO)) != 0; }
C4_ALWAYS_INLINE bool is_key_plain() const noexcept { return (type & (KEY_PLAIN)) != 0; }
C4_ALWAYS_INLINE bool is_val_plain() const noexcept { return (type & (VAL_PLAIN)) != 0; }
C4_ALWAYS_INLINE bool is_key_quoted() const noexcept { return (type & KEYQUO) != 0; }
C4_ALWAYS_INLINE bool is_val_quoted() const noexcept { return (type & VALQUO) != 0; }
C4_ALWAYS_INLINE bool is_quoted() const noexcept { return (type & (KEYQUO|VALQUO)) != 0; }
C4_ALWAYS_INLINE NodeType key_style() const noexcept { return (type & (KEY_STYLE)); }
C4_ALWAYS_INLINE NodeType val_style() const noexcept { return (type & (VAL_STYLE)); }
C4_ALWAYS_INLINE void set_container_style(NodeType_e style) noexcept { type = ((style & CONTAINER_STYLE) | (type & ~CONTAINER_STYLE)); }
C4_ALWAYS_INLINE void set_key_style(NodeType_e style) noexcept { type = ((style & KEY_STYLE) | (type & ~KEY_STYLE)); }
C4_ALWAYS_INLINE void set_val_style(NodeType_e style) noexcept { type = ((style & VAL_STYLE) | (type & ~VAL_STYLE)); }
C4_ALWAYS_INLINE void clear_style() noexcept { type &= ~STYLE; }
/** @} */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @name scalar style helpers
* @{ */
/** choose a YAML emitting style based on the scalar's contents */
RYML_EXPORT NodeType_e scalar_style_choose(csubstr scalar) noexcept;
/** choose a json style based on the scalar's contents */
RYML_EXPORT NodeType_e scalar_style_json_choose(csubstr scalar) noexcept;
/** query whether a scalar can be encoded using single quotes.
* It may not be possible, notably when there is leading
* whitespace after a newline. */
RYML_EXPORT bool scalar_style_query_squo(csubstr s) noexcept;
/** query whether a scalar can be encoded using plain style (no
* quotes, not a literal/folded block scalar). */
RYML_EXPORT bool scalar_style_query_plain(csubstr s) noexcept;
/** YAML-sense query of nullity. returns true if the scalar points
* to `nullptr` or is otherwise equal to one of the strings
* `"~"`,`"null"`,`"Null"`,`"NULL"` */
RYML_EXPORT inline C4_NO_INLINE bool scalar_is_null(csubstr s) noexcept
{
return s.str == nullptr ||
s == "~" ||
s == "null" ||
s == "Null" ||
s == "NULL";
}
/** @} */
/** @} */
} // namespace yml
} // namespace c4
C4_SUPPRESS_WARNING_MSVC_POP
C4_SUPPRESS_WARNING_GCC_CLANG_POP
#endif /* C4_YML_NODE_TYPE_HPP_ */
-324
View File
@@ -1,324 +0,0 @@
#ifndef _C4_YML_PARSE_HPP_
#define _C4_YML_PARSE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
namespace c4 {
namespace yml {
class Tree;
class NodeRef;
template<class EventHandler> class ParseEngine;
struct EventHandlerTree;
RYML_EXPORT id_type estimate_tree_capacity(csubstr src); // NOLINT
/** @addtogroup doc_parse
* @{ */
/** This is the main ryml parser, where the parser events are handled
* to create a ryml tree.
*
* @warning This class cannot parse YAML where there are container
* keys. This is not a limitation of the @ref ParseEngine, but of the
* @ref EventHandlerTree, which is present because the @ref Tree does
* not accept containers as keys. However, the @ref ParseEngine *can*
* parse container keys; consult its documentation for more details.
*
* @see ParserOptions
* @see ParseEngine
* @see EventHandlerTree
* */
using Parser = RYML_EXPORT ParseEngine<EventHandlerTree>;
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_place__with_existing_parser Parse in place with existing parser
*
* @brief parse a mutable YAML source buffer (re)using an existing
* parser. Scalars requiring filtering are mutated in place (except in
* the rare cases where the filtered scalar is longer than the
* original scalar, or where filtering was disabled before the
* call). These overloads accept an existing parser object, and
* provide the opportunity to use special parser options.
*
* @see ParserOptions
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id); /**< (1) parse YAML into an existing tree node.
*
* The filename will be used in any error messages
* arising during the parse. The callbacks in the
* tree are kept, and used to allocate
* the tree members, if any allocation is required. */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, Tree *t, id_type node_id); /**< (2) like (1) but no filename will be reported */
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t ); /**< (3) parse YAML into the root node of an existing tree.
*
* The filename will be used in any error messages
* arising during the parse. The callbacks in the
* tree are kept, and used to allocate
* the tree members, if any allocation is required. */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, Tree *t ); /**< (4) like (3) but no filename will be reported */
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, NodeRef node ); /**< (5) like (1) but the node is given as a NodeRef */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, NodeRef node ); /**< (6) like (5) but no filename will be reported */
RYML_EXPORT Tree parse_in_place(Parser *parser, csubstr filename, substr yaml ); /**< (7) create a new tree, and parse YAML into its root node.
*
* The filename will be used in any error messages
* arising during the parse. The tree is created with
* the callbacks currently in the parser.
*/
RYML_EXPORT Tree parse_in_place(Parser *parser, substr yaml ); /**< (8) like (7) but no filename will be reported */
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_place(Parser *parser, csubstr filename, substr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_place(Parser *parser, substr json ); ///< (8) like (7) but no filename will be reported
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_place___with_temporary_parser Parse in place with temporary parser
*
* @brief parse a mutable YAML source buffer. Scalars requiring
* filtering are mutated in place (except in the rare cases where the
* filtered scalar is longer than the original scalar).
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to enable the user to easily parse
* YAML without the need to explicitly instantiate a parser and event
* handler. Note that some properties (notably node locations in the
* original source code) are only available through the parser
* class. If you need access to any of these properties, use
* the appropriate overload from @ref doc_parse_in_place__with_existing_parser
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_place( substr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_place( substr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_place( substr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_place(csubstr filename, substr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_place( substr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_place( substr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_place( substr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_place( substr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_place(csubstr filename, substr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_place( substr json ); ///< (8) like (7) but no filename will be reported
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_arena__with_existing_parser Parse in arena with existing parser
*
* @brief parse a read-only (immutable) YAML source buffer. This is
* achieved by first copying the contents of the buffer to the tree's
* arena, and then calling @ref parse_in_arena() . All the resulting
* scalars will be filtered in the arena. These overloads accept an
* existing parser object, and provide the opportunity to use special
* parser options.
*
* @see ParserOptions
*
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily parse YAML without the need
* to instantiate a separate parser. Note that some properties
* (notably node locations in the original source code) are only
* available through the parser class. If you need access to any of
* these properties, use the appropriate overload from @ref
* doc_parse_in_arena__with_existing_parser
*
* @warning overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
* will cause a linker error. This is to prevent an accidental copy of
* the source buffer to the tree's arena, because substr (which is
* mutable) is implicitly convertible to csubstr (which is
* immutable). If you really intend to parse a mutable buffer in the
* tree's arena, convert it first to immutable by assigning the substr
* to a csubstr prior to calling parse_in_arena(). This is not needed
* for parse_in_place() because csubstr is not implicitly convertible
* to substr. To be clear:
* ```c++
* substr mutable_buffer = ...;
* parser.parse_in_arena(mutable_buffer); // linker error
*
* csubstr immutable_buffer = ...;
* parser.parse_in_arena(immutable_buffer); // ok
* ```
*
* @{
*/
#define RYML_DONT_PARSE_SUBSTR_IN_ARENA "" \
"Do not pass a (mutable) substr to parse_in_arena(); " \
"if you have a substr, it should be parsed in place. " \
"Consider using parse_in_place() instead, or convert " \
"the buffer to csubstr prior to calling. This function " \
" is deliberately left undefined, so that calling it " \
"will cause a linker error."
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_arena(Parser *parser, csubstr filename, csubstr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_arena(Parser *parser, csubstr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_arena(Parser *parser, csubstr filename, csubstr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_arena(Parser *parser, csubstr json ); ///< (8) like (7) but no filename will be reported
/* READ THE DEPRECATION NOTE!
*
* All of the functions below are intentionally left undefined, to
* prevent them being used.
*
*/
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(Parser *parser, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(Parser *parser, csubstr filename, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(Parser *parser, substr json );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(Parser *parser, csubstr filename, substr json );
/** @endcond */
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_arena__with_temporary_parser Parse in arena with temporary parser
*
* @brief parse a read-only (immutable) YAML source buffer. This is
* achieved by first copying the contents of the buffer to the tree's
* arena, and then calling @ref parse_in_arena() .
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily one-off parse YAML without
* the need to instantiate a separate parser. Note that some
* properties (notably node locations in the original source code) are
* only available through the parser class. If you need access to any
* of these properties, use the appropriate overload from @ref
* doc_parse_in_arena__with_existing_parser
*
* @warning overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
* will cause a linker error. This is to prevent an accidental copy of
* the source buffer to the tree's arena, because substr (which is
* mutable) is implicitly convertible to csubstr (which is
* immutable). If you really intend to parse a mutable buffer in the
* tree's arena, convert it first to immutable by assigning the substr
* to a csubstr prior to calling parse_in_arena(). This is not needed
* for parse_in_place() because csubstr is not implicitly convertible
* to substr. To be clear:
* ```c++
* substr mutable_buffer = ...;
* parser.parse_in_arena(mutable_buffer); // linker error
*
* csubstr immutable_buffer = ...;
* parser.parse_in_arena(immutable_buffer); // ok
* ```
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_arena( csubstr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_arena( csubstr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_arena( csubstr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_arena(csubstr filename, csubstr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_arena( csubstr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_arena( csubstr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_arena( csubstr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_arena( csubstr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_arena(csubstr filename, csubstr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_arena( csubstr json ); ///< (8) like (7) but no filename will be reported
/* READ THE DEPRECATION NOTE!
*
* All of the functions below are intentionally left undefined, to
* prevent them being used.
*/
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena( substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena( substr json );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(csubstr filename, substr json );
/** @endcond */
/** @} */
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_PARSE_HPP_ */
File diff suppressed because it is too large Load Diff
-799
View File
@@ -1,799 +0,0 @@
#ifndef _C4_YML_PARSE_ENGINE_HPP_
#define _C4_YML_PARSE_ENGINE_HPP_
#ifndef _C4_YML_PARSER_STATE_HPP_
#include "c4/yml/parser_state.hpp"
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_parse
* @{ */
/** @defgroup doc_event_handlers Event Handlers
*
* @brief rapidyaml implements its parsing logic with a two-level
* model, where a @ref ParseEngine object reads through the YAML
* source, and dispatches events to an EventHandler bound to the @ref
* ParseEngine. Because @ref ParseEngine is templated on the event
* handler, the binding uses static polymorphism, without any virtual
* functions. The actual handler object can be changed at run time,
* (but of course needs to be the type of the template parameter).
* This is thus a very efficient architecture, and further enables the
* user to provide his own custom handler if he wishes to bypass the
* rapidyaml @ref Tree.
*
* There are two handlers implemented in this project:
*
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref extra::EventHandlerInts parses YAML into an integer array
representation of the tree and scalars.
*
* - @ref extra::EventHandlerTestSuite is the handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project.
*
*
* ### Event model
*
* The event model used by the parse engine and event handlers follows
* very closely the event model in the [YAML test
* suite](https://github.com/yaml/yaml-test-suite).
*
* Consider for example this YAML,
* ```yaml
* {foo: bar,foo2: bar2}
* ```
* which would produce these events in the test-suite parlance:
* ```
* +STR
* +DOC
* +MAP {}
* =VAL :foo
* =VAL :bar
* =VAL :foo2
* =VAL :bar2
* -MAP
* -DOC
* -STR
* ```
*
* For reference, the @ref ParseEngine object will produce this
* sequence of calls to its bound EventHandler:
* ```cpp
* handler.begin_stream();
* handler.begin_doc();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("foo");
* handler.set_val_scalar_plain("bar");
* handler.add_sibling();
* handler.set_key_scalar_plain("foo2");
* handler.set_val_scalar_plain("bar2");
* handler.end_map();
* handler.end_doc();
* handler.end_stream();
* ```
*
* For many other examples of all areas of YAML and how ryml's parse
* model corresponds to the YAML standard model, refer to the [unit
* tests for the parse
* engine](https://github.com/biojppm/rapidyaml/tree/master/test/test_parse_engine.cpp).
*
*
* ### Special events
*
* Most of the parsing events adopted by rapidyaml in its event model
* are fairly obvious, but there are two less-obvious events requiring
* some explanation.
*
* These events exist to make it easier to parse some special YAML
* cases. They are called by the parser when a just-handled
* value/container is actually the first key of a new map:
*
* - `actually_val_is_first_key_of_new_map_flow()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTestSuite")
* - `actually_val_is_first_key_of_new_map_block()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTestSuite")
*
* For example, consider an implicit map inside a seq: `[a: b, c:
* d]` which is parsed as `[{a: b}, {c: d}]`. The standard event
* sequence for this YAML would be the following:
* ```cpp
* handler.begin_seq_val_flow();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("a");
* handler.set_val_scalar_plain("b");
* handler.end_map();
* handler.add_sibling();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("c");
* handler.set_val_scalar_plain("d");
* handler.end_map();
* handler.end_seq();
* ```
* The problem with this event sequence is that it forces the
* parser to delay setting the val scalar (in this case "a" and
* "c") until it knows whether the scalar is a key or a val. This
* would require the parser to store the scalar until this
* time. For instance, in the example above, the parser should
* delay setting "a" and "c", because they are in fact keys and
* not vals. Until then, the parser would have to store "a" and
* "c" in its internal state. The downside is that this complexity
* cost would apply even if there is no implicit map -- every val
* in a seq would have to be delayed until one of the
* disambiguating subsequent tokens `,-]:` is found.
* By calling this function, the parser can avoid this complexity,
* by preemptively setting the scalar as a val. Then a call to
* this function will create the map and rearrange the scalar as
* key. Now the cost applies only once: when a seqimap starts. So
* the following (easier and cheaper) event sequence below has the
* same effect as the event sequence above:
* ```cpp
* handler.begin_seq_val_flow();
* handler.set_val_scalar_plain("notmap");
* handler.set_val_scalar_plain("a"); // preemptively set "a" as val!
* handler.actually_as_new_map_key(); // create a map, move the "a" val as the key of the first child of the new map
* handler.set_val_scalar_plain("b"); // now "a" is a key and "b" the val
* handler.end_map();
* handler.set_val_scalar_plain("c"); // "c" also as val!
* handler.actually_as_block_flow(); // likewise
* handler.set_val_scalar_plain("d"); // now "c" is a key and "b" the val
* handler.end_map();
* handler.end_seq();
* ```
* This also applies to container keys (although ryml's tree
* cannot accomodate these): the parser can preemptively set a
* container as a val, and call this event to turn that container
* into a key. For example, consider this yaml:
* ```yaml
* [aa, bb]: [cc, dd]
* # ^ ^ ^
* # | | |
* # (2) (1) (3) <- event sequence
* ```
* The standard event sequence for this YAML would be the
* following:
* ```cpp
* handler.begin_map_val_block(); // (1)
* handler.begin_seq_key_flow(); // (2)
* handler.set_val_scalar_plain("aa");
* handler.add_sibling();
* handler.set_val_scalar_plain("bb");
* handler.end_seq();
* handler.begin_seq_val_flow(); // (3)
* handler.set_val_scalar_plain("cc");
* handler.add_sibling();
* handler.set_val_scalar_plain("dd");
* handler.end_seq();
* handler.end_map();
* ```
* The problem with the sequence above is that, reading from
* left-to-right, the parser can only detect the proper calls at
* (1) and (2) once it reaches (1) in the YAML source. So, the
* parser would have to buffer the entire event sequence starting
* from the beginning until it reaches (1). Using this function,
* the parser can do instead:
* ```cpp
* handler.begin_seq_val_flow(); // (2) -- preemptively as val!
* handler.set_val_scalar_plain("aa");
* handler.add_sibling();
* handler.set_val_scalar_plain("bb");
* handler.end_seq();
* handler.actually_as_new_map_key(); // (1) -- adjust when finding that the prev val was actually a key.
* handler.begin_seq_val_flow(); // (3) -- go on as before
* handler.set_val_scalar_plain("cc");
* handler.add_sibling();
* handler.set_val_scalar_plain("dd");
* handler.end_seq();
* handler.end_map();
* ```
*/
class Tree;
class NodeRef;
class ConstNodeRef;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Options to give to the parser to control its behavior. */
struct RYML_EXPORT ParserOptions
{
private:
typedef enum : uint32_t {
SCALAR_FILTERING = (1u << 0u),
LOCATIONS = (1u << 1u),
DEFAULTS = SCALAR_FILTERING,
} Flags_e;
uint32_t flags = DEFAULTS;
public:
ParserOptions() = default;
public:
/** @name source location tracking */
/** @{ */
/** enable/disable source location tracking */
ParserOptions& locations(bool enabled) noexcept
{
if(enabled)
flags |= LOCATIONS;
else
flags &= ~LOCATIONS;
return *this;
}
/** query source location tracking status */
C4_ALWAYS_INLINE bool locations() const noexcept { return (flags & LOCATIONS); }
/** @} */
public:
/** @name scalar filtering status (experimental; disable at your discretion) */
/** @{ */
/** enable/disable scalar filtering while parsing */
ParserOptions& scalar_filtering(bool enabled) noexcept
{
if(enabled)
flags |= SCALAR_FILTERING;
else
flags &= ~SCALAR_FILTERING;
return *this;
}
/** query scalar filtering status */
C4_ALWAYS_INLINE bool scalar_filtering() const noexcept { return (flags & SCALAR_FILTERING); }
/** @} */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** This is the main driver of parsing logic: it scans the YAML or
* JSON source for tokens, and emits the appropriate sequence of
* parsing events to its event handler. The parse engine itself has no
* special limitations, and *can* accomodate containers as keys; it is the
* event handler may introduce additional constraints.
*
* There are two implemented handlers (see @ref doc_event_handlers,
* which has important notes about the event model):
*
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref extra::EventHandlerTestSuite is a handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project. This is not part of the library and is
* not installed.
*
* - @ref extra::EventHandlerInts is the handler responsible for
* emitting integer-coded events. It is intended for implementing
* fully-conformant parsing in other programming languages
* (integration is currently under work for
* [YamlScript](https://github.com/yaml/yamlscript) and
* [go-yaml](https://github.com/yaml/go-yaml/)). It is not part of
* the library and is not installed.
*
*/
template<class EventHandler>
class ParseEngine
{
public:
using handler_type = EventHandler;
public:
/** @name construction and assignment */
/** @{ */
ParseEngine(EventHandler *evt_handler, ParserOptions opts={});
~ParseEngine();
ParseEngine(ParseEngine &&) noexcept;
ParseEngine(ParseEngine const&);
ParseEngine& operator=(ParseEngine &&) noexcept;
ParseEngine& operator=(ParseEngine const&);
/** @} */
public:
/** @name modifiers */
/** @{ */
/** Reserve a certain capacity for the parsing stack.
* This should be larger than the expected depth of the parsed
* YAML tree.
*
* The parsing stack is the only (potential) heap memory used
* directly by the parser.
*
* If the requested capacity is below the default
* stack size of 16, the memory is used directly in the parser
* object; otherwise it will be allocated from the heap.
*
* @note this reserves memory only for the parser itself; all the
* allocations for the parsed tree will go through the tree's
* allocator (when different).
*
* @note for maximum efficiency, the tree and the arena can (and
* should) also be reserved. */
void reserve_stack(id_type capacity)
{
m_evt_handler->m_stack.reserve(capacity);
}
/** Reserve a certain capacity for the array used to track node
* locations in the source buffer. */
void reserve_locations(size_t num_source_lines)
{
_resize_locations(num_source_lines);
}
RYML_DEPRECATED("filter arena no longer needed")
void reserve_filter_arena(size_t) {}
/** @} */
public:
/** @name getters */
/** @{ */
/** Get the options used to build this parser object. */
ParserOptions const& options() const { return m_options; }
/** Get the current callbacks in the parser. */
Callbacks const& callbacks() const { RYML_ASSERT(m_evt_handler); return m_evt_handler->m_stack.m_callbacks; }
/** Get the name of the latest file parsed by this object. */
csubstr filename() const { return m_file; }
/** Get the latest YAML buffer parsed by this object. */
csubstr source() const { return m_buf; }
/** Get the encoding of the latest YAML buffer parsed by this object.
* If no encoding was specified, UTF8 is assumed as per the YAML standard. */
Encoding_e encoding() const { return m_encoding != NOBOM ? m_encoding : UTF8; }
id_type stack_capacity() const { RYML_ASSERT(m_evt_handler); return m_evt_handler->m_stack.capacity(); }
size_t locations_capacity() const { return m_newline_offsets_capacity; }
RYML_DEPRECATED("filter arena no longer needed")
size_t filter_arena_capacity() const { return 0u; }
/** @} */
public:
/** @name parse methods */
/** @{ */
/** parse YAML in place, emitting events to the current handler */
void parse_in_place_ev(csubstr filename, substr src);
/** parse JSON in place, emitting events to the current handler */
void parse_json_in_place_ev(csubstr filename, substr src);
/** @} */
public:
// deprecated parse methods
/** @cond dev */
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_place(csubstr filename, substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_place( substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena(csubstr filename, csubstr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena( csubstr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena(csubstr filename, substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena( substr yaml );
/** @endcond */
public:
/** @name locations */
/** @{ */
/** Get the string starting at a particular location, to the end
* of the parsed source buffer. */
csubstr location_contents(Location const& loc) const;
/** Given a pointer to a buffer position, get the location.
* @param[in] val must be pointing to somewhere in the source
* buffer that was last parsed by this object. */
Location val_location(const char *val) const;
/** @} */
public:
/** @cond dev */
template<class U>
RYML_DEPRECATED("moved to Tree::location(Parser const&). deliberately undefined here.")
auto location(Tree const&, id_type node) const -> typename std::enable_if<U::is_wtree, Location>::type;
template<class U>
RYML_DEPRECATED("moved to ConstNodeRef::location(Parser const&), deliberately undefined here.")
auto location(ConstNodeRef const&) const -> typename std::enable_if<U::is_wtree, Location>::type;
/** @endcond */
public:
/** @name scalar filtering */
/** @{*/
/** filter a plain scalar */
FilterResult filter_scalar_plain(csubstr scalar, substr dst, size_t indentation);
/** filter a plain scalar in place */
FilterResult filter_scalar_plain_in_place(substr scalar, size_t cap, size_t indentation);
/** filter a single-quoted scalar */
FilterResult filter_scalar_squoted(csubstr scalar, substr dst);
/** filter a single-quoted scalar in place */
FilterResult filter_scalar_squoted_in_place(substr scalar, size_t cap);
/** filter a double-quoted scalar */
FilterResult filter_scalar_dquoted(csubstr scalar, substr dst);
/** filter a double-quoted scalar in place */
FilterResultExtending filter_scalar_dquoted_in_place(substr scalar, size_t cap);
/** filter a block-literal scalar */
FilterResult filter_scalar_block_literal(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp);
/** filter a block-literal scalar in place */
FilterResult filter_scalar_block_literal_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp);
/** filter a block-folded scalar */
FilterResult filter_scalar_block_folded(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp);
/** filter a block-folded scalar in place */
FilterResult filter_scalar_block_folded_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp);
/** @} */
private:
struct ScannedScalar
{
substr scalar;
bool needs_filter;
};
struct ScannedBlock
{
substr scalar;
size_t indentation;
BlockChomp_e chomp;
};
bool _is_doc_begin(csubstr s);
bool _is_doc_end(csubstr s);
bool _scan_scalar_plain_blck(ScannedScalar *C4_RESTRICT sc, size_t indentation);
bool _scan_scalar_plain_seq_flow(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_seq_blck(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_map_flow(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_map_blck(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_map_json(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_seq_json(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_unk(ScannedScalar *C4_RESTRICT sc);
bool _is_valid_start_scalar_plain_flow(csubstr s);
ScannedScalar _scan_scalar_squot();
ScannedScalar _scan_scalar_dquot();
void _scan_block(ScannedBlock *C4_RESTRICT sb, size_t indref);
csubstr _scan_anchor();
csubstr _scan_ref_seq();
csubstr _scan_ref_map();
csubstr _scan_tag();
public: // exposed for testing
/** @cond dev */
csubstr _filter_scalar_plain(substr s, size_t indentation);
csubstr _filter_scalar_squot(substr s);
csubstr _filter_scalar_dquot(substr s);
csubstr _filter_scalar_literal(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _filter_scalar_folded(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _move_scalar_left_and_add_newline(substr s);
csubstr _maybe_filter_key_scalar_plain(ScannedScalar const& sc, size_t indendation);
csubstr _maybe_filter_val_scalar_plain(ScannedScalar const& sc, size_t indendation);
csubstr _maybe_filter_key_scalar_squot(ScannedScalar const& sc);
csubstr _maybe_filter_val_scalar_squot(ScannedScalar const& sc);
csubstr _maybe_filter_key_scalar_dquot(ScannedScalar const& sc);
csubstr _maybe_filter_val_scalar_dquot(ScannedScalar const& sc);
csubstr _maybe_filter_key_scalar_literal(ScannedBlock const& sb);
csubstr _maybe_filter_val_scalar_literal(ScannedBlock const& sb);
csubstr _maybe_filter_key_scalar_folded(ScannedBlock const& sb);
csubstr _maybe_filter_val_scalar_folded(ScannedBlock const& sb);
/** @endcond */
private:
void _handle_map_block();
void _handle_seq_block();
void _handle_map_flow();
void _handle_seq_flow();
void _handle_seq_imap();
void _handle_map_json();
void _handle_seq_json();
void _handle_unk();
void _handle_unk_json();
void _handle_usty();
void _handle_flow_skip_whitespace();
void _end_map_blck();
void _end_seq_blck();
void _end2_map();
void _end2_seq();
void _begin2_doc();
void _begin2_doc_expl();
void _end2_doc();
void _end2_doc_expl();
void _maybe_begin_doc();
void _maybe_end_doc();
void _start_doc_suddenly();
void _end_doc_suddenly();
void _end_doc_suddenly__pop();
void _end_stream();
void _set_indentation(size_t indentation);
void _save_indentation();
void _handle_indentation_pop_from_block_seq();
void _handle_indentation_pop_from_block_map();
void _handle_indentation_pop(ParserState const* dst);
void _maybe_skip_comment();
void _skip_comment();
void _maybe_skip_whitespace_tokens();
void _maybe_skipchars(char c);
#ifdef RYML_NO_COVERAGE__TO_BE_DELETED
void _maybe_skipchars_up_to(char c, size_t max_to_skip);
#endif
template<size_t N>
void _skipchars(const char (&chars)[N]);
bool _maybe_scan_following_colon() noexcept;
bool _maybe_scan_following_comma() noexcept;
public:
/** @cond dev */
template<class FilterProcessor> auto _filter_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_squoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_dquoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_block_literal(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_block_folded(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result());
/** @endcond */
public:
/** @cond dev */
template<class FilterProcessor> void _filter_nl_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation);
template<class FilterProcessor> void _filter_nl_squoted(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_nl_dquoted(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> bool _filter_ws_handle_to_first_non_space(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_ws_copy_trailing(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_ws_skip_trailing(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_dquoted_backslash(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_chomp(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp, size_t indentation);
template<class FilterProcessor> size_t _handle_all_whitespace(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp);
template<class FilterProcessor> size_t _extend_to_chomp(FilterProcessor &C4_RESTRICT proc, size_t contents_len);
template<class FilterProcessor> void _filter_block_indentation(FilterProcessor &C4_RESTRICT proc, size_t indentation);
template<class FilterProcessor> void _filter_block_folded_newlines(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len);
template<class FilterProcessor> size_t _filter_block_folded_newlines_compress(FilterProcessor &C4_RESTRICT proc, size_t num_newl, size_t wpos_at_first_newl);
template<class FilterProcessor> void _filter_block_folded_newlines_leading(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len);
template<class FilterProcessor> void _filter_block_folded_indented_block(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len, size_t curr_indentation) noexcept;
/** @endcond */
private:
void _line_progressed(size_t ahead);
void _line_ended();
void _line_ended_undo();
bool _finished_file() const;
bool _finished_line() const;
void _scan_line();
substr _peek_next_line(size_t pos=npos) const;
bool _at_line_begin() const
{
return m_evt_handler->m_curr->line_contents.rem.begin() == m_evt_handler->m_curr->line_contents.full.begin();
}
void _relocate_arena(csubstr prev_arena, substr next_arena);
static void _s_relocate_arena(void*, csubstr prev_arena, substr next_arena);
private:
C4_ALWAYS_INLINE bool has_all(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) == f; }
C4_ALWAYS_INLINE bool has_any(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) != 0; }
C4_ALWAYS_INLINE bool has_none(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) == 0; }
static C4_ALWAYS_INLINE bool has_all(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) == f; }
static C4_ALWAYS_INLINE bool has_any(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) != 0; }
static C4_ALWAYS_INLINE bool has_none(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) == 0; }
#ifndef RYML_DBG
C4_ALWAYS_INLINE static void add_flags(ParserFlag_t on, ParserState *C4_RESTRICT s) noexcept { s->flags |= on; }
C4_ALWAYS_INLINE static void addrem_flags(ParserFlag_t on, ParserFlag_t off, ParserState *C4_RESTRICT s) noexcept { s->flags &= ~off; s->flags |= on; }
C4_ALWAYS_INLINE static void rem_flags(ParserFlag_t off, ParserState *C4_RESTRICT s) noexcept { s->flags &= ~off; }
C4_ALWAYS_INLINE void add_flags(ParserFlag_t on) noexcept { m_evt_handler->m_curr->flags |= on; }
C4_ALWAYS_INLINE void addrem_flags(ParserFlag_t on, ParserFlag_t off) noexcept { m_evt_handler->m_curr->flags &= ~off; m_evt_handler->m_curr->flags |= on; }
C4_ALWAYS_INLINE void rem_flags(ParserFlag_t off) noexcept { m_evt_handler->m_curr->flags &= ~off; }
#else
static void add_flags(ParserFlag_t on, ParserState *C4_RESTRICT s);
static void addrem_flags(ParserFlag_t on, ParserFlag_t off, ParserState *C4_RESTRICT s);
static void rem_flags(ParserFlag_t off, ParserState *C4_RESTRICT s);
C4_ALWAYS_INLINE void add_flags(ParserFlag_t on) noexcept { add_flags(on, m_evt_handler->m_curr); }
C4_ALWAYS_INLINE void addrem_flags(ParserFlag_t on, ParserFlag_t off) noexcept { addrem_flags(on, off, m_evt_handler->m_curr); }
C4_ALWAYS_INLINE void rem_flags(ParserFlag_t off) noexcept { rem_flags(off, m_evt_handler->m_curr); }
#endif
private:
void _prepare_locations();
void _resize_locations(size_t sz);
bool _locations_dirty() const;
private:
void _reset();
void _free();
void _clr();
#ifdef RYML_DBG
template<class ...Args> void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const;
#endif
template<class ...Args> void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
template<class ...Args> void _errloc(csubstr fmt, Location const& loc, Args const& C4_RESTRICT ...args) const;
template<class DumpFn> void _fmt_msg(DumpFn &&dumpfn) const;
private:
/** store pending tag or anchor/ref annotations */
struct Annotation
{
struct Entry
{
csubstr str;
size_t indentation;
size_t line;
};
Entry annotations[2];
size_t num_entries;
};
void _handle_colon();
void _add_annotation(Annotation *C4_RESTRICT dst, csubstr str, size_t indentation, size_t line);
void _clear_annotations(Annotation *C4_RESTRICT dst);
bool _has_pending_annotations() const { return m_pending_tags.num_entries || m_pending_anchors.num_entries; }
#ifdef RYML_NO_COVERAGE__TO_BE_DELETED
bool _handle_indentation_from_annotations();
#endif
bool _annotations_require_key_container() const;
void _handle_annotations_before_blck_key_scalar();
void _handle_annotations_before_blck_val_scalar();
void _handle_annotations_before_start_mapblck(size_t current_line);
void _handle_annotations_before_start_mapblck_as_key();
void _handle_annotations_and_indentation_after_start_mapblck(size_t key_indentation, size_t key_line);
size_t _select_indentation_from_annotations(size_t val_indentation, size_t val_line);
void _handle_directive(csubstr rem);
bool _handle_bom();
void _handle_bom(Encoding_e enc);
void _check_tag(csubstr tag);
private:
ParserOptions m_options;
csubstr m_file;
substr m_buf;
public:
/** @cond dev */
EventHandler *C4_RESTRICT m_evt_handler; // NOLINT
/** @endcond */
private:
Annotation m_pending_anchors;
Annotation m_pending_tags;
bool m_was_inside_qmrk;
bool m_doc_empty = true;
size_t m_prev_colon = npos;
Encoding_e m_encoding = UTF8;
private:
size_t *m_newline_offsets;
size_t m_newline_offsets_size;
size_t m_newline_offsets_capacity;
csubstr m_newline_offsets_buf;
};
/** Quickly inspect the source to estimate the number of nodes the
* resulting tree is likely have. If a tree is empty before
* parsing, considerable time will be spent growing it, so calling
* this to reserve the tree size prior to parsing is likely to
* result in a time gain. We encourage using this method before
* parsing, but as always measure its impact in performance to
* obtain a good trade-off.
*
* @note since this method is meant for optimizing performance, it
* is approximate. The result may be actually smaller than the
* resulting number of nodes, notably if the YAML uses implicit
* maps as flow seq members as in `[these: are, individual:
* maps]`. */
RYML_EXPORT id_type estimate_tree_capacity(csubstr src); // NOLINT(readability-redundant-declaration)
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif /* _C4_YML_PARSE_ENGINE_HPP_ */
-212
View File
@@ -1,212 +0,0 @@
#ifndef _C4_YML_PARSER_STATE_HPP_
#define _C4_YML_PARSER_STATE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** data type for @ref ParserState_e */
using ParserFlag_t = int;
/** Enumeration of the state flags for the parser */
typedef enum : ParserFlag_t {
RTOP = 0x01 << 0, ///< reading at top level
RUNK = 0x01 << 1, ///< reading unknown state (when starting): must determine whether scalar, map or seq
RMAP = 0x01 << 2, ///< reading a map
RSEQ = 0x01 << 3, ///< reading a seq
FLOW = 0x01 << 4, ///< reading is inside explicit flow chars: [] or {}
BLCK = 0x01 << 5, ///< reading in block mode
QMRK = 0x01 << 6, ///< reading an explicit key (`? key`)
RKEY = 0x01 << 7, ///< reading a scalar as key
RVAL = 0x01 << 9, ///< reading a scalar as val
RKCL = 0x01 << 8, ///< reading the key colon (ie the : after the key in the map)
RNXT = 0x01 << 10, ///< read next val or keyval
SSCL = 0x01 << 11, ///< there's a stored scalar
QSCL = 0x01 << 12, ///< stored scalar was quoted
RSET = 0x01 << 13, ///< the (implicit) map being read is a !!set. @see https://yaml.org/type/set.html
RDOC = 0x01 << 14, ///< reading a document
NDOC = 0x01 << 15, ///< no document mode. a document has ended and another has not started yet.
USTY = 0x01 << 16, ///< reading in unknown style mode - must determine FLOW or BLCK
//! reading an implicit map nested in an explicit seq.
//! eg, {key: [key2: value2, key3: value3]}
//! is parsed as {key: [{key2: value2}, {key3: value3}]}
RSEQIMAP = 0x01 << 17,
} ParserState_e;
#ifdef RYML_DBG
/** @cond dev */
namespace detail {
csubstr _parser_flags_to_str(substr buf, ParserFlag_t flags);
} // namespace
/** @endcond */
#endif
/** Helper to control the line contents while parsing a buffer */
struct LineContents
{
substr rem; ///< the stripped line remainder; initially starts at the first non-space character
size_t indentation; ///< the number of spaces on the beginning of the line
substr full; ///< the full line, including newlines on the right
substr stripped; ///< the stripped line, excluding newlines on the right
LineContents() = default;
void reset_with_next_line(substr buf, size_t offset)
{
RYML_ASSERT(offset <= buf.len);
size_t e = offset;
// get the current line stripped of newline chars
while(e < buf.len && (buf.str[e] != '\n' && buf.str[e] != '\r'))
++e;
RYML_ASSERT(e >= offset);
const substr stripped_ = buf.range(offset, e);
#if defined(__GNUC__) && __GNUC__ == 11
C4_DONT_OPTIMIZE(stripped_);
#endif
// advance pos to include the first line ending
if(e < buf.len && buf.str[e] == '\r')
++e;
if(e < buf.len && buf.str[e] == '\n')
++e;
const substr full_ = buf.range(offset, e);
reset(full_, stripped_);
}
void reset(substr full_, substr stripped_)
{
rem = stripped_;
indentation = stripped_.first_not_of(' '); // find the first column where the character is not a space
full = full_;
stripped = stripped_;
}
C4_ALWAYS_INLINE size_t current_col() const RYML_NOEXCEPT
{
// WARNING: gcc x86 release builds were wrong (eg returning 0
// when the result should be 4 ) when this function was like
// this:
//
//return current_col(rem);
//
// (see below for the full definition of the called overload
// of current_col())
//
// ... so we explicitly inline the code in here:
RYML_ASSERT(rem.str >= full.str);
size_t col = static_cast<size_t>(rem.str - full.str);
return col;
//
// this was happening only on builds specifically with (gcc
// AND x86 AND release); no other builds were having the
// problem: not in debug, not in x64, not in other
// architectures, not in clang, not in visual studio. WTF!?
//
// Enabling debug prints with RYML_DBG made the problem go
// away, so these could not be used to debug the
// problem. Adding prints inside the called current_col() also
// made the problem go away! WTF!???
//
// a prize will be offered to anybody able to explain why this
// was happening.
}
C4_ALWAYS_INLINE size_t current_col(csubstr s) const RYML_NOEXCEPT
{
RYML_ASSERT(s.str >= full.str);
RYML_ASSERT(full.is_super(s));
size_t col = static_cast<size_t>(s.str - full.str);
return col;
}
};
static_assert(std::is_standard_layout<LineContents>::value, "LineContents not standard");
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
struct ParserState
{
LineContents line_contents;
Location pos;
ParserFlag_t flags;
size_t indref; ///< the reference indentation in the current block scope
id_type level;
id_type node_id; ///< don't hold a pointer to the node as it will be relocated during tree resizes
size_t scalar_col; // the column where the scalar (or its quotes) begin
bool more_indented;
bool has_children;
ParserState() = default;
void start_parse(const char *file, id_type node_id_)
{
level = 0;
pos.name = to_csubstr(file);
pos.offset = 0;
pos.line = 1;
pos.col = 1;
node_id = node_id_;
more_indented = false;
scalar_col = 0;
indref = 0;
has_children = false;
}
void reset_after_push()
{
node_id = NONE;
indref = npos;
more_indented = false;
++level;
has_children = false;
}
C4_ALWAYS_INLINE void reset_before_pop(ParserState const& to_pop)
{
pos = to_pop.pos;
line_contents = to_pop.line_contents;
}
public:
C4_ALWAYS_INLINE bool at_line_beginning() const noexcept
{
return line_contents.rem.str == line_contents.full.str;
}
C4_ALWAYS_INLINE bool indentation_eq() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation == indref;
}
C4_ALWAYS_INLINE bool indentation_ge() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation >= indref;
}
C4_ALWAYS_INLINE bool indentation_gt() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation > indref;
}
C4_ALWAYS_INLINE bool indentation_lt() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation < indref;
}
};
static_assert(std::is_standard_layout<ParserState>::value, "ParserState not standard");
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#endif /* _C4_YML_PARSER_STATE_HPP_ */
-97
View File
@@ -1,97 +0,0 @@
#ifndef _C4_YML_PREPROCESS_HPP_
#define _C4_YML_PREPROCESS_HPP_
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#include <c4/substr.hpp>
namespace c4 {
namespace yml {
/** @addtogroup doc_preprocessors
* @{
*/
/** @cond dev */
namespace detail {
using Preprocessor = size_t(csubstr, substr);
template<Preprocessor PP, class CharContainer>
substr preprocess_into_container(csubstr input, CharContainer *out)
{
// try to write once. the preprocessor will stop writing at the end of
// the container, but will process all the input to determine the
// required container size.
size_t sz = PP(input, to_substr(*out));
// if the container size is not enough, resize, and run again in the
// resized container
if(sz > out->size())
{
out->resize(sz);
sz = PP(input, to_substr(*out));
}
return to_substr(*out).first(sz);
}
} // namespace detail
/** @endcond */
//-----------------------------------------------------------------------------
/** @defgroup doc_preprocess_rxmap preprocess_rxmap
*
* @brief Convert flow-type relaxed maps (with implicit bools) into strict YAML
* flow map:
*
* @code{.yaml}
* {a, b, c, d: [e, f], g: {a, b}}
* # is converted into this:
* {a: 1, b: 1, c: 1, d: [e, f], g: {a, b}}
* @endcode
* @note this is NOT recursive - conversion happens only in the top-level map
* @param rxmap A relaxed map
* @param buf output buffer
* @param out output container
*
* @{
*/
/** Write into a given output buffer. This function is safe to call with
* empty or small buffers; it won't write beyond the end of the buffer.
*
* @return the number of characters required for output
*/
RYML_EXPORT size_t preprocess_rxmap(csubstr rxmap, substr buf);
/** Write into an existing container. It is resized to contained the output.
* @return a substr of the container
* @overload preprocess_rxmap */
template<class CharContainer>
substr preprocess_rxmap(csubstr rxmap, CharContainer *out)
{
return detail::preprocess_into_container<preprocess_rxmap>(rxmap, out);
}
/** Create a container with the result.
* @overload preprocess_rxmap */
template<class CharContainer>
CharContainer preprocess_rxmap(csubstr rxmap)
{
CharContainer out;
preprocess_rxmap(rxmap, &out);
return out;
}
/** @} */ // preprocess_rxmap
/** @} */ // group
} // namespace yml
} // namespace c4
#endif /* _C4_YML_PREPROCESS_HPP_ */
@@ -1,88 +0,0 @@
#ifndef _C4_YML_REFERENCE_RESOLVER_HPP_
#define _C4_YML_REFERENCE_RESOLVER_HPP_
#include "c4/yml/tree.hpp"
#include "c4/yml/detail/stack.hpp"
namespace c4 {
namespace yml {
/** @addtogroup doc_ref_utils
* @{
*/
/** Reusable object to resolve references/aliases in a @ref Tree. */
struct RYML_EXPORT ReferenceResolver
{
ReferenceResolver() = default;
/** Resolve references: for each reference, look for a matching
* anchor, and copy its contents to the ref node.
*
* @p tree the subject tree
*
* @p clear_anchors whether to clear existing anchors after
* resolving
*
* This method first does a full traversal of the tree to gather
* all anchors and references in a separate collection, then it
* goes through that collection to locate the names, which it does
* by obeying the YAML standard diktat that "an alias node refers
* to the most recent node in the serialization having the
* specified anchor"
*
* So, depending on the number of anchor/alias nodes, this is a
* potentially expensive operation, with a best-case linear
* complexity (from the initial traversal). This potential cost is
* one of the reasons for requiring an explicit call.
*
* The @ref Tree has an `Tree::resolve()` overload set forwarding
* here. Previously this operation was done there, using a
* discarded object; using this separate class offers opportunity
* for reuse of the object.
*
* @warning resolving references opens an attack vector when the
* data is malicious or severely malformed, as the tree can expand
* exponentially. See for example the [Billion Laughs
* Attack](https://en.wikipedia.org/wiki/Billion_laughs_attack).
*
*/
void resolve(Tree *tree, bool clear_anchors=true);
public:
/** @cond dev */
struct RefData
{
NodeType type;
id_type node;
id_type prev_anchor;
id_type target;
id_type parent_ref;
id_type parent_ref_sibling;
};
void reset_(Tree *t_);
void resolve_();
void gather_anchors_and_refs_();
void gather_anchors_and_refs__(id_type n);
id_type count_anchors_and_refs_(id_type n);
id_type lookup_(RefData const* C4_RESTRICT ra);
Tree *C4_RESTRICT m_tree;
/** We're using this stack purely as an array. */
detail::stack<RefData> m_refs;
/** @endcond */
};
/** @} */
} // namespace ryml
} // namespace c4
#endif // _C4_YML_REFERENCE_RESOLVER_HPP_
-46
View File
@@ -1,46 +0,0 @@
#ifndef _C4_YML_STD_MAP_HPP_
#define _C4_YML_STD_MAP_HPP_
/** @file map.hpp write/read std::map to/from a YAML tree. */
#include "c4/yml/node.hpp"
#include <map>
namespace c4 {
namespace yml {
// std::map requires child nodes in the data
// tree hierarchy (a MAP node in ryml parlance).
// So it should be serialized via write()/read().
template<class K, class V, class Less, class Alloc>
void write(c4::yml::NodeRef *n, std::map<K, V, Less, Alloc> const& m)
{
*n |= c4::yml::MAP;
for(auto const& C4_RESTRICT p : m)
{
auto ch = n->append_child();
ch << c4::yml::key(p.first);
ch << p.second;
}
}
/** read the node members, assigning into the existing map. If a key
* is already present in the map, then its value will be
* move-assigned. */
template<class K, class V, class Less, class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::map<K, V, Less, Alloc> * m)
{
for(auto const& C4_RESTRICT ch : n)
{
K k{};
ch >> c4::yml::key(k);
ch >> (*m)[k];
}
return true;
}
} // namespace yml
} // namespace c4
#endif // _C4_YML_STD_MAP_HPP_
-8
View File
@@ -1,8 +0,0 @@
#ifndef _C4_YML_STD_STD_HPP_
#define _C4_YML_STD_STD_HPP_
#include "c4/yml/std/string.hpp"
#include "c4/yml/std/vector.hpp"
#include "c4/yml/std/map.hpp"
#endif // _C4_YML_STD_STD_HPP_
-9
View File
@@ -1,9 +0,0 @@
#ifndef C4_YML_STD_STRING_HPP_
#define C4_YML_STD_STRING_HPP_
/** @file string.hpp substring conversions for/from std::string */
// everything we need is implemented here:
#include <c4/std/string.hpp>
#endif // C4_YML_STD_STRING_HPP_
-59
View File
@@ -1,59 +0,0 @@
#ifndef _C4_YML_STD_VECTOR_HPP_
#define _C4_YML_STD_VECTOR_HPP_
#include "c4/yml/node.hpp"
#include <c4/std/vector.hpp>
#include <vector>
namespace c4 {
namespace yml {
// vector is a sequence-like type, and it requires child nodes
// in the data tree hierarchy (a SEQ node in ryml parlance).
// So it should be serialized via write()/read().
template<class V, class Alloc>
void write(c4::yml::NodeRef *n, std::vector<V, Alloc> const& vec)
{
*n |= c4::yml::SEQ;
for(V const& v : vec)
n->append_child() << v;
}
/** read the node members, overwriting existing vector entries. */
template<class V, class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::vector<V, Alloc> *vec)
{
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
vec->resize(static_cast<size_t>(n.num_children()));
C4_SUPPRESS_WARNING_GCC_POP
size_t pos = 0;
for(ConstNodeRef const child : n)
child >> (*vec)[pos++];
return true;
}
/** read the node members, overwriting existing vector entries.
* specialization: std::vector<bool> uses std::vector<bool>::reference as
* the return value of its operator[]. */
template<class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::vector<bool, Alloc> *vec)
{
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
vec->resize(static_cast<size_t>(n.num_children()));
C4_SUPPRESS_WARNING_GCC_POP
size_t pos = 0;
bool tmp = {};
for(ConstNodeRef const child : n)
{
child >> tmp;
(*vec)[pos++] = tmp;
}
return true;
}
} // namespace yml
} // namespace c4
#endif // _C4_YML_STD_VECTOR_HPP_
-83
View File
@@ -1,83 +0,0 @@
#ifndef _C4_YML_TAG_HPP_
#define _C4_YML_TAG_HPP_
#include <c4/yml/common.hpp>
namespace c4 {
namespace yml {
class Tree;
/** @addtogroup doc_tag_utils
*
* @{
*/
#ifndef RYML_MAX_TAG_DIRECTIVES
/** the maximum number of tag directives in a Tree */
#define RYML_MAX_TAG_DIRECTIVES 4
#endif
/** the integral type necessary to cover all the bits marking node tags */
using tag_bits = uint16_t;
/** a bit mask for marking tags for types */
typedef enum : tag_bits {
TAG_NONE = 0,
// container types
TAG_MAP = 1, /**< !!map Unordered set of key: value pairs without duplicates. @see https://yaml.org/type/map.html */
TAG_OMAP = 2, /**< !!omap Ordered sequence of key: value pairs without duplicates. @see https://yaml.org/type/omap.html */
TAG_PAIRS = 3, /**< !!pairs Ordered sequence of key: value pairs allowing duplicates. @see https://yaml.org/type/pairs.html */
TAG_SET = 4, /**< !!set Unordered set of non-equal values. @see https://yaml.org/type/set.html */
TAG_SEQ = 5, /**< !!seq Sequence of arbitrary values. @see https://yaml.org/type/seq.html */
// scalar types
TAG_BINARY = 6, /**< !!binary A sequence of zero or more octets (8 bit values). @see https://yaml.org/type/binary.html */
TAG_BOOL = 7, /**< !!bool Mathematical Booleans. @see https://yaml.org/type/bool.html */
TAG_FLOAT = 8, /**< !!float Floating-point approximation to real numbers. https://yaml.org/type/float.html */
TAG_INT = 9, /**< !!float Mathematical integers. https://yaml.org/type/int.html */
TAG_MERGE = 10, /**< !!merge Specify one or more mapping to be merged with the current one. https://yaml.org/type/merge.html */
TAG_NULL = 11, /**< !!null Devoid of value. https://yaml.org/type/null.html */
TAG_STR = 12, /**< !!str A sequence of zero or more Unicode characters. https://yaml.org/type/str.html */
TAG_TIMESTAMP = 13, /**< !!timestamp A point in time https://yaml.org/type/timestamp.html */
TAG_VALUE = 14, /**< !!value Specify the default value of a mapping https://yaml.org/type/value.html */
TAG_YAML = 15, /**< !!yaml Specify the default value of a mapping https://yaml.org/type/yaml.html */
} YamlTag_e;
RYML_EXPORT YamlTag_e to_tag(csubstr tag);
RYML_EXPORT csubstr from_tag(YamlTag_e tag);
RYML_EXPORT csubstr from_tag_long(YamlTag_e tag);
RYML_EXPORT csubstr normalize_tag(csubstr tag);
RYML_EXPORT csubstr normalize_tag_long(csubstr tag);
RYML_EXPORT csubstr normalize_tag_long(csubstr tag, substr output);
RYML_EXPORT bool is_custom_tag(csubstr tag);
struct RYML_EXPORT TagDirective
{
/** Eg <pre>!e!</pre> in <pre>%TAG !e! tag:example.com,2000:app/</pre> */
csubstr handle;
/** Eg <pre>tag:example.com,2000:app/</pre> in <pre>%TAG !e! tag:example.com,2000:app/</pre> */
csubstr prefix;
/** The next node to which this tag directive applies */
id_type next_node_id;
bool create_from_str(csubstr directive_); ///< leaves next_node_id unfilled
size_t transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets=true) const;
};
struct RYML_EXPORT TagDirectiveRange
{
TagDirective const* C4_RESTRICT b;
TagDirective const* C4_RESTRICT e;
C4_ALWAYS_INLINE TagDirective const* begin() const noexcept { return b; }
C4_ALWAYS_INLINE TagDirective const* end() const noexcept { return e; }
};
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_TAG_HPP_ */
File diff suppressed because it is too large Load Diff
-25
View File
@@ -1,25 +0,0 @@
#ifndef _C4_YML_VERSION_HPP_
#define _C4_YML_VERSION_HPP_
/** @file version.hpp */
#define RYML_VERSION "0.10.0"
#define RYML_VERSION_MAJOR 0
#define RYML_VERSION_MINOR 10
#define RYML_VERSION_PATCH 0
#include <c4/substr.hpp>
#include <c4/yml/export.hpp>
namespace c4 {
namespace yml {
RYML_EXPORT csubstr version();
RYML_EXPORT int version_major();
RYML_EXPORT int version_minor();
RYML_EXPORT int version_patch();
} // namespace yml
} // namespace c4
#endif /* _C4_YML_VERSION_HPP_ */
-195
View File
@@ -1,195 +0,0 @@
#ifndef _C4_YML_WRITER_HPP_
#define _C4_YML_WRITER_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#include <c4/substr.hpp>
#include <stdio.h> // fwrite(), fputc()
#include <string.h> // memcpy()
namespace c4 {
namespace yml {
/** @addtogroup doc_emit
* @{
*/
/** @defgroup doc_writers Writer objects to use with an Emitter
* @see Emitter
* @{
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to a file. Defaults to stdout. */
struct WriterFile
{
FILE * m_file;
size_t m_pos;
WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}
substr _get(bool /*error_on_excess*/) const
{
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
(void)fwrite(a, sizeof(char), N - 1, m_file);
m_pos += N - 1;
}
void _do_write(csubstr sp)
{
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wsign-conversion")
if(sp.empty())
return;
(void)fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file);
m_pos += sp.len;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
}
void _do_write(const char c)
{
(void)fputc(c, m_file);
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
for(size_t i = 0; i < num_times; ++i)
(void)fputc(c, m_file);
m_pos += num_times;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to an STL-like ostream. */
template<class OStream>
struct WriterOStream
{
OStream* m_stream;
size_t m_pos;
WriterOStream(OStream &s) : m_stream(&s), m_pos(0) {}
substr _get(bool /*error_on_excess*/) const
{
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
m_stream->write(a, N - 1);
m_pos += N - 1;
}
void _do_write(csubstr sp)
{
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wsign-conversion")
if(sp.empty())
return;
m_stream->write(sp.str, sp.len);
m_pos += sp.len;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
}
void _do_write(const char c)
{
m_stream->put(c);
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
for(size_t i = 0; i < num_times; ++i)
m_stream->put(c);
m_pos += num_times;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a writer to a substr */
struct WriterBuf
{
substr m_buf;
size_t m_pos;
WriterBuf(substr sp) : m_buf(sp), m_pos(0) {}
substr _get(bool error_on_excess) const
{
if(m_pos <= m_buf.len)
return m_buf.first(m_pos);
else if(error_on_excess)
c4::yml::error("not enough space in the given buffer");
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
RYML_ASSERT( ! m_buf.overlaps(a));
if(m_pos + N-1 <= m_buf.len)
memcpy(&(m_buf[m_pos]), a, N-1);
m_pos += N-1;
}
void _do_write(csubstr sp)
{
if(sp.empty())
return;
RYML_ASSERT( ! sp.overlaps(m_buf));
if(m_pos + sp.len <= m_buf.len)
memcpy(&(m_buf[m_pos]), sp.str, sp.len);
m_pos += sp.len;
}
void _do_write(const char c)
{
if(m_pos + 1 <= m_buf.len)
m_buf[m_pos] = c;
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
if(m_pos + num_times <= m_buf.len)
for(size_t i = 0; i < num_times; ++i)
m_buf[m_pos + i] = c;
m_pos += num_times;
}
};
/** @ } */
/** @ } */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_WRITER_HPP_ */
-16
View File
@@ -1,16 +0,0 @@
#ifndef _C4_YML_YML_HPP_
#define _C4_YML_YML_HPP_
#include "c4/yml/version.hpp"
#include "c4/yml/tree.hpp"
#include "c4/yml/node.hpp"
#include "c4/yml/emit.hpp"
#include "c4/yml/event_handler_tree.hpp"
#include "c4/yml/parse_engine.hpp"
#include "c4/yml/filter_processor.hpp"
#include "c4/yml/parse.hpp"
#include "c4/yml/preprocess.hpp"
#include "c4/yml/reference_resolver.hpp"
#include "c4/yml/tag.hpp"
#endif // _C4_YML_YML_HPP_
-391
View File
@@ -1,391 +0,0 @@
# To make this file known to Qt Creator using:
# Tools > Options > Debugger > Locals & Expressions > Extra Debugging Helpers
# Any contents here will be picked up by GDB, LLDB, and CDB based
# debugging in Qt Creator automatically.
# Example to display a simple type
# template<typename U, typename V> struct MapNode
# {
# U key;
# V data;
# }
#
# def qdump__MapNode(d, value):
# d.putValue("This is the value column contents")
# d.putExpandable()
# if d.isExpanded():
# with Children(d):
# # Compact simple case.
# d.putSubItem("key", value["key"])
# # Same effect, with more customization possibilities.
# with SubItem(d, "data")
# d.putItem("data", value["data"])
# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
# for more complex examples.
# to try parsing:
# env PYTHONPATH=/usr/share/qtcreator/debugger/ python src/ryml-gdbtypes.py
import dumper
#from dumper import Dumper, Value, Children, SubItem
#from dumper import SubItem, Children
from dumper import *
import sys
import os
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# QtCreator makes it really hard to figure out problems in this code.
# So here are some debugging utilities.
# FIXME. this decorator is not working; find out why.
def dbglog(func):
"""a decorator that logs entry and exit of functions"""
if not _DBG:
return func
def func_wrapper(*args, **kwargs):
_dbg_enter(func.__name__)
ret = func(*args, **kwargs)
_dbg_exit(func.__name__)
return ret
return func_wrapper
_DBG = False
_dbg_log = None
_dbg_stack = 0
def _dbg(*args, **kwargs):
global _dbg_log, _dbg_stack
if not _DBG:
return
if _dbg_log is None:
filename = os.path.join(os.path.dirname(__file__), "dbg.txt")
_dbg_log = open(filename, "w")
kwargs['file'] = _dbg_log
kwargs['flush'] = True
print(" " * _dbg_stack, *args, **kwargs)
def _dbg_enter(name):
global _dbg_stack
_dbg(name, "- enter")
_dbg_stack += 1
def _dbg_exit(name):
global _dbg_stack
_dbg_stack -= 1
_dbg(name, "- exit!")
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
NPOS = 18446744073709551615
MAX_SUBSTR_LEN_DISPLAY = 80
MAX_SUBSTR_LEN_EXPAND = 1000
def get_str_value(d, value, limit=0):
# adapted from dumper.py::Dumper::putCharArrayValue()
m_str = value["str"].pointer()
m_len = value["len"].integer()
if m_len == NPOS:
_dbg("getstr... 1", m_len)
m_str = "!!!!!<npos>!!!!!"
m_len = len(m_str)
return m_str, m_len
if limit == 0:
limit = d.displayStringLimit
elided, shown = d.computeLimit(m_len, limit)
mem = bytes(d.readRawMemory(m_str, shown))
mem = mem.decode('utf8')
return mem, m_len
def __display_csubstr(d, value, limit=0):
m_str, m_len = get_str_value(d, value)
safe_len = min(m_len, MAX_SUBSTR_LEN_DISPLAY)
disp = m_str[0:safe_len]
# ensure the string escapes characters like \n\r\t etc
disp = disp.encode('unicode_escape').decode('utf8')
# WATCHOUT. quotes in the string will make qtcreator hang!!!
disp = disp.replace('"', '\\"')
disp = disp.replace('\'', '\\')
if m_len <= MAX_SUBSTR_LEN_DISPLAY:
d.putValue(f"[{m_len}] '{disp}'")
else:
d.putValue(f"[{m_len}] '{disp}'...")
return m_str, m_len
def qdump__c4__csubstr(d, value):
m_str, m_len = __display_csubstr(d, value)
d.putExpandable()
if d.isExpanded():
with Children(d):
safe_len = min(m_len, MAX_SUBSTR_LEN_EXPAND)
for i in range(safe_len):
ct = d.createType('char')
d.putSubItem(safe_len, d.createValue(value["str"].pointer() + i, ct))
d.putSubItem("len", value["len"])
d.putPtrItem("str", value["str"].pointer())
def qdump__c4__substr(d, value):
qdump__c4__csubstr(d, value)
def qdump__c4__basic_substring(d, value):
qdump__c4__csubstr(d, value)
def qdump__c4__yml__NodeScalar(d, value):
alen = value["anchor"]["len"].integer()
tlen = value["tag" ]["len"].integer()
m_str, m_len = get_str_value(d, value["scalar"])
if alen == 0 and tlen == 0:
d.putValue(f'\'{m_str}\'')
elif alen == 0 and tlen > 0:
d.putValue(f'\'{m_str}\' [Ta]')
elif alen > 0 and tlen == 0:
d.putValue(f'\'{m_str}\' [tA]')
elif alen > 0 and tlen > 0:
d.putValue(f'\'{m_str}\' [TA]')
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("[scalar]", value["scalar"])
if tlen > 0:
d.putSubItem("[tag]", value["tag"])
if alen > 0:
d.putSubItem("[anchor or ref]", value["anchor"])
def _format_enum_value(int_value, enum_map):
str_value = enum_map.get(int_value, None)
display = f'{int_value}' if str_value is None else f'{str_value} ({int_value})'
return display
def _format_bitmask_value(int_value, enum_map):
str_value = enum_map.get(int_value, None)
if str_value:
return f'{str_value} ({int_value})'
else:
out = ""
orig = int_value
# do in reverse to get compound flags first
for k, v in reversed(enum_map.items()):
if (k != 0):
if (int_value & k) == k:
if len(out) > 0:
out += '|'
out += v
int_value &= ~k
else:
if len(out) == 0 and int_value == 0:
return v
if out == "":
return f'{int_value}'
return f"{out} ({orig})"
def _c4bit(*ints):
ret = 0
for i in ints:
ret |= 1 << i
return ret
node_types = {
0: "NOTYPE",
_c4bit(0): "VAL" ,
_c4bit(1): "KEY" ,
_c4bit(2): "MAP" ,
_c4bit(3): "SEQ" ,
_c4bit(4): "DOC" ,
_c4bit(5,3): "STREAM",
_c4bit(6): "KEYREF" ,
_c4bit(7): "VALREF" ,
_c4bit(8): "KEYANCH" ,
_c4bit(9): "VALANCH" ,
_c4bit(10): "KEYTAG" ,
_c4bit(11): "VALTAG" ,
_c4bit(12): "VALQUO" ,
_c4bit(13): "KEYQUO" ,
_c4bit(1,0): "KEYVAL",
_c4bit(1,3): "KEYSEQ",
_c4bit(1,2): "KEYMAP",
_c4bit(4,2): "DOCMAP",
_c4bit(4,3): "DOCSEQ",
_c4bit(4,0): "DOCVAL",
#
_c4bit(14): "STYLE_FLOW_SL",
_c4bit(15): "STYLE_FLOW_ML",
_c4bit(16): "STYLE_BLOCK",
#
_c4bit(17): "KEY_LITERAL",
_c4bit(18): "VAL_LITERAL",
_c4bit(19): "KEY_FOLDED",
_c4bit(20): "VAL_FOLDED",
_c4bit(21): "KEY_SQUO",
_c4bit(22): "VAL_SQUO",
_c4bit(23): "KEY_DQUO",
_c4bit(24): "VAL_DQUO",
_c4bit(25): "KEY_PLAIN",
_c4bit(26): "VAL_PLAIN",
}
node_types_rev = {v: k for k, v in node_types.items()}
def _node_type_has_all(node_type_value, type_name):
exp = node_types_rev[type_name]
return (node_type_value & exp) == exp
def _node_type_has_any(node_type_value, type_name):
exp = node_types_rev[type_name]
return (node_type_value & exp) != 0
def qdump__c4__yml__NodeType_e(d, value):
v = _format_bitmask_value(value.integer(), node_types)
d.putValue(v)
def qdump__c4__yml__NodeType(d, value):
qdump__c4__yml__NodeType_e(d, value["type"])
def qdump__c4__yml__NodeData(d, value):
d.putValue("wtf")
ty = _format_bitmask_value(value.integer(), node_types)
t = value["m_type"]["type"].integer()
k = value["m_key"]["scalar"]
v = value["m_val"]["scalar"]
sk, lk = get_str_value(d, k)
sv, lv = get_str_value(d, v)
if _node_type_has_all(t, "KEYVAL"):
d.putValue(f"'{sk}': '{sv}' {ty}")
elif _node_type_has_any(t, "KEY"):
d.putValue(f"'{sk}': {ty}")
elif _node_type_has_any(t, "VAL"):
d.putValue(f"'{sv}' {ty}")
else:
d.putValue(f"{ty}")
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("m_type", value["m_type"])
# key
if _node_type_has_any(t, "KEY"):
d.putSubItem("m_key", value["m_key"])
if _node_type_has_any(t, "KEYREF"):
with SubItem(d, "m_key.ref"):
s_, _ = get_str_value(d, value["m_key"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "KEYANCH"):
with SubItem(d, "m_key.anchor"):
s_, _ = get_str_value(d, value["m_key"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "KEYTAG"):
with SubItem(d, "m_key.tag"):
s_, _ = get_str_value(d, value["m_key"]["tag"])
d.putValue(f"'{s_}'")
# val
if _node_type_has_any(t, "VAL"):
d.putSubItem("m_val", value["m_val"])
if _node_type_has_any(t, "VALREF"):
with SubItem(d, "m_val.ref"):
s_, _ = get_str_value(d, value["m_val"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "VALANCH"):
with SubItem(d, "m_val.anchor"):
s_, _ = get_str_value(d, value["m_val"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "VALTAG"):
with SubItem(d, "m_val.tag"):
s_, _ = get_str_value(d, value["m_val"]["tag"])
d.putValue(f"'{s_}'")
# hierarchy
_dump_node_index(d, "m_parent", value)
_dump_node_index(d, "m_first_child", value)
_dump_node_index(d, "m_last_child", value)
_dump_node_index(d, "m_next_sibling", value)
_dump_node_index(d, "m_prev_sibling", value)
def _dump_node_index(d, name, value):
if int(value[name].integer()) == NPOS:
pass
#with SubItem(d, name):
# d.putValue("-")
else:
d.putSubItem(name, value[name])
# c4::yml::Tree
def qdump__c4__yml__Tree(d, value):
m_size = value["m_size"].integer()
m_cap = value["m_cap"].integer()
d.putExpandable()
if d.isExpanded():
#d.putArrayData(value["m_buf"], m_size, value["m_buf"].dereference())
with Children(d):
with SubItem(d, f"[nodes]"):
d.putItemCount(m_size)
d.putArrayData(value["m_buf"].pointer(), m_size, value["m_buf"].type.dereference())
d.putPtrItem("m_buf", value["m_buf"].pointer())
d.putIntItem("m_size", value["m_size"])
d.putIntItem("m_cap (capacity)", value["m_cap"])
d.putIntItem("[slack]", m_cap - m_size)
d.putIntItem("m_free_head", value["m_free_head"])
d.putIntItem("m_free_tail", value["m_free_tail"])
d.putSubItem("m_arena", value["m_arena"])
def qdump__c4__yml__detail__stack(d, value):
T = value.type[0]
N = value.type[0]
m_size = value["m_size"].integer()
m_capacity = value["m_capacity"].integer()
d.putItemCount(m_size)
if d.isExpanded():
with Children(d):
with SubItem(d, f"[nodes]"):
d.putItemCount(m_size)
d.putArrayData(value["m_stack"].pointer(), m_size, T)
d.putIntItem("m_size", value["m_size"])
d.putIntItem("m_capacity", value["m_capacity"])
#d.putIntItem("[small capacity]", N)
d.putIntItem("[is large]", value["m_buf"].address() == value["m_stack"].pointer())
d.putPtrItem("m_stack", value["m_stack"].pointer())
d.putPtrItem("m_buf", value["m_buf"].address())
def qdump__c4__yml__detail__ReferenceResolver__refdata(d, value):
node = value["node"].integer()
ty = _format_bitmask_value(value["type"].integer(), node_types)
d.putValue(f'{node} {ty}')
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("type", value["type"])
d.putSubItem("node", value["node"])
_dump_node_index(d, "prev_anchor", value)
_dump_node_index(d, "target", value)
_dump_node_index(d, "parent_ref", value)
_dump_node_index(d, "parent_ref_sibling", value)

Some files were not shown because too many files have changed in this diff Show More