mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 09:44:17 +02:00
Compare commits
177 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fb8a48418 | |||
| ce472dde8b | |||
| f56d3b5f2f | |||
| 0804b68fc6 | |||
| 05c6a95fe5 | |||
| 8a3f4609a6 | |||
| a5867bfd44 | |||
| 2c608b4293 | |||
| 2c908f4d09 | |||
| c1bf4d5a56 | |||
| eab8b92037 | |||
| 4aa72d949f | |||
| 26a86130de | |||
| 0beb18c9e1 | |||
| ade5762a45 | |||
| 5cb7abf10c | |||
| 7561f7ef70 | |||
| ac69bb2142 | |||
| 2c7c8e19e2 | |||
| 59d00a0134 | |||
| 372fadfb99 | |||
| 406c2c0bbf | |||
| a5ba35ce92 | |||
| f6b2887ae0 | |||
| cba474000e | |||
| cb64246288 | |||
| 4006be49f8 | |||
| 085f1dcb68 | |||
| 1372d71fa7 | |||
| 2fda2d512d | |||
| 1edc304453 | |||
| a291936bf8 | |||
| 9b343bae3e | |||
| 6336cc82e8 | |||
| 3450e3c238 | |||
| 49017c4813 | |||
| 27a88dd333 | |||
| 6f4f6cf7de | |||
| 0020cac123 | |||
| 1160758a81 | |||
| 5c205d6287 | |||
| e814408026 | |||
| 46e85c4586 | |||
| f4b16a8762 | |||
| cdc8201222 | |||
| 94c10ca9f9 | |||
| 724155ba91 | |||
| 6ffa916336 | |||
| e3badc754d | |||
| df9783f41f | |||
| e9c6d51566 | |||
| a8c8223f69 | |||
| 9b3f827991 | |||
| 2d2bfd64ff | |||
| 73a825cbb1 | |||
| 3e0e72e50c | |||
| 259350c974 | |||
| e14b4475ff | |||
| b4f030cd37 | |||
| f28c488ecf | |||
| 2ac22f8dd9 | |||
| 5e0b92f1b4 | |||
| e1e35982e4 | |||
| 1356f282d0 | |||
| 7e8e0d4744 | |||
| 56b20a3a13 | |||
| 10cdacfa30 | |||
| 81a20150f2 | |||
| 5e5ea642b0 | |||
| e7733a2d43 | |||
| 3e60e46ae4 | |||
| 194037bd4e | |||
| 5037be3d8f | |||
| 8aca0fe288 | |||
| 0e667a9b0f | |||
| 12940f2e1b | |||
| faf6c04dee | |||
| 6aadbc18a9 | |||
| 2be34a6938 | |||
| daa0d2d3c4 | |||
| 1b4af9deef | |||
| db6cb43336 | |||
| 012d352fa7 | |||
| 904096cd6e | |||
| b3bb67b43a | |||
| deba43640e | |||
| d665efdc3a | |||
| 66493c8dd1 | |||
| 9ff85a620e | |||
| ae1ee7cc3d | |||
| 2392cf7014 | |||
| 08fe525a3b | |||
| 1cd30601ed | |||
| 07713e97d7 | |||
| be307f3eb9 | |||
| d9bfdc3fcd | |||
| 064a96dfd2 | |||
| 428e035032 | |||
| 2db9cd0437 | |||
| bd78c33f11 | |||
| f16774357a | |||
| 00868a1b29 | |||
| 93212882d0 | |||
| 7f1ab4043c | |||
| 65822ecf86 | |||
| 9dff4f2005 | |||
| ec8f3b0414 | |||
| dde3c73af7 | |||
| bc80ea92a3 | |||
| 497dc14d11 | |||
| c80866ab5c | |||
| d856f3f5bd | |||
| 5d811f03f4 | |||
| 600a8b468b | |||
| e0c5e861be | |||
| d049c395fc | |||
| 6aed46c603 | |||
| f0723a6ec9 | |||
| bc624524cf | |||
| d1a44cdae8 | |||
| 8a46f9e6ca | |||
| eba66a2bb3 | |||
| 7ea5234049 | |||
| 0b5c37e1c5 | |||
| 2f7be602c8 | |||
| 05289e80a0 | |||
| 1ddc283ea2 | |||
| f969b0d4c7 | |||
| 1bd475cfab | |||
| f678788b6c | |||
| 379371f0b5 | |||
| 247511fd38 | |||
| 8de55a1937 | |||
| 73010de3b5 | |||
| b29496eb8e | |||
| dc88ed97ab | |||
| 10d2e5dd40 | |||
| f357fad0ff | |||
| 1ae55e8615 | |||
| 012120c344 | |||
| e3565eb924 | |||
| cd9fe1630b | |||
| f5524bab1b | |||
| 471a7203a5 | |||
| 456c062246 | |||
| 2c0bb98cac | |||
| bf4670c855 | |||
| 6113f9bcb4 | |||
| fe919d18b2 | |||
| d0687dd631 | |||
| 1bf53e6432 | |||
| 58a4f1e5e9 | |||
| ea304becf6 | |||
| b0a7d6994b | |||
| bd522e2385 | |||
| 27e9accffa | |||
| 4f41366600 | |||
| d26701c004 | |||
| d7983d81e3 | |||
| 2e122c3255 | |||
| eef1f837a2 | |||
| e52d8f70ba | |||
| d4cf5a998c | |||
| 608922dc41 | |||
| 438937ace3 | |||
| 50605bd0e9 | |||
| c1d46b1866 | |||
| e47b32b2e6 | |||
| f0dc40ac15 | |||
| 15a502cf36 | |||
| a1152f5313 | |||
| 68150c7448 | |||
| 71fe1b809c | |||
| ec6901b93d | |||
| 3c7eb2ac88 | |||
| baecf73f4b | |||
| 9a2561d9cf |
@@ -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"'
|
||||
@@ -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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Vendored
+9
-7
@@ -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
@@ -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 ""
|
||||
|
||||
Vendored
+23
@@ -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). */
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
Vendored
+76
-67
@@ -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++) {
|
||||
|
||||
Vendored
+4
@@ -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;
|
||||
|
||||
Vendored
+19
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
Vendored
+2
@@ -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 = ' ';
|
||||
|
||||
Vendored
+15
-1
@@ -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:
|
||||
|
||||
Vendored
+8
-27
@@ -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)
|
||||
|
||||
|
||||
Vendored
+66
-59
@@ -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;
|
||||
|
||||
Vendored
+14
-1
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
-91
@@ -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
@@ -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
@@ -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
@@ -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<*>">
|
||||
<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<*>">
|
||||
<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<*>">
|
||||
<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<char,*>">
|
||||
<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<const char,*>">
|
||||
<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<char,*>">
|
||||
<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<const char,*>">
|
||||
<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<*,*,*,*>">
|
||||
<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<*,*>">
|
||||
<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<*,*>">
|
||||
<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<*,*,*>">
|
||||
<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<*>::Sym">
|
||||
<DisplayString>{value} - {name}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[value]">value</Item>
|
||||
<Item Name="[name]">name</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="c4::EnumSymbols<*>">
|
||||
<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>
|
||||
-2670
File diff suppressed because it is too large
Load Diff
-120
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_ */
|
||||
-1058
File diff suppressed because it is too large
Load Diff
-358
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
@@ -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
@@ -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_
|
||||
@@ -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_
|
||||
-2290
File diff suppressed because it is too large
Load Diff
-16
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_ */
|
||||
@@ -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
@@ -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
@@ -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_ */
|
||||
-1084
File diff suppressed because it is too large
Load Diff
-909
@@ -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_ */
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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
@@ -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_ */
|
||||
-1679
File diff suppressed because it is too large
Load Diff
-282
@@ -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
@@ -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_ */
|
||||
-8317
File diff suppressed because it is too large
Load Diff
-799
@@ -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
@@ -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_ */
|
||||
@@ -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
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
@@ -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_ */
|
||||
-1561
File diff suppressed because it is too large
Load Diff
-25
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user