mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 01:34:17 +02:00
Deps: Update rapidyaml to v0.11.1
This commit is contained in:
@@ -36,6 +36,7 @@ ZSTD=1.5.7
|
||||
KDDOCKWIDGETS=2.4.0
|
||||
PLUTOVG=1.3.2
|
||||
PLUTOSVG=0.0.7
|
||||
RAPIDYAML=0.11.1
|
||||
|
||||
SHADERC=2026.1
|
||||
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
|
||||
@@ -72,6 +73,7 @@ eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
|
||||
|
||||
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
|
||||
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
@@ -107,7 +109,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
-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/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 --strict SHASUMS
|
||||
@@ -349,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
|
||||
@@ -49,6 +50,7 @@ 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
|
||||
|
||||
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
@@ -67,7 +69,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
-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/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 --strict SHASUMS
|
||||
@@ -175,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"
|
||||
|
||||
@@ -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 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ MOLTENVK=1.4.1
|
||||
KDDOCKWIDGETS=2.4.0
|
||||
PLUTOVG=1.3.2
|
||||
PLUTOSVG=0.0.7
|
||||
RAPIDYAML=0.11.1
|
||||
|
||||
SHADERC=2026.1
|
||||
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
|
||||
@@ -105,6 +106,7 @@ b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
|
||||
|
||||
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
|
||||
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
@@ -137,7 +139,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
-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/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 --strict SHASUMS
|
||||
@@ -427,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
|
||||
|
||||
@@ -36,6 +36,7 @@ MOLTENVK=1.4.1
|
||||
KDDOCKWIDGETS=2.4.0
|
||||
PLUTOVG=1.3.2
|
||||
PLUTOSVG=0.0.7
|
||||
RAPIDYAML=0.11.1
|
||||
|
||||
SHADERC=2026.1
|
||||
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
|
||||
@@ -81,6 +82,7 @@ b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
|
||||
|
||||
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
|
||||
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
@@ -113,7 +115,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
-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/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 --strict SHASUMS
|
||||
@@ -370,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
|
||||
|
||||
@@ -72,6 +72,7 @@ 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=2026.1
|
||||
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
|
||||
@@ -101,6 +102,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
|
||||
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" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
|
||||
@@ -322,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
|
||||
|
||||
@@ -89,6 +89,7 @@ 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=2026.1
|
||||
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
|
||||
@@ -128,6 +129,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
|
||||
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" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
|
||||
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
|
||||
@@ -481,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
|
||||
|
||||
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)
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
#ifndef _RYML_HPP_
|
||||
#define _RYML_HPP_
|
||||
|
||||
#include "c4/yml/yml.hpp"
|
||||
|
||||
namespace ryml {
|
||||
using namespace c4::yml;
|
||||
using namespace c4;
|
||||
}
|
||||
|
||||
#endif /* _RYML_HPP_ */
|
||||
-304
@@ -1,304 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Very good intro:
|
||||
@see https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2017
|
||||
@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::yml::NodeScalar">
|
||||
<DisplayString Condition="(tag.len == 0) && (anchor.len == 0)">{scalar.str,[scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="(tag.len > 0) && (anchor.len == 0)">{scalar.str,[scalar.len]} [T]</DisplayString>
|
||||
<DisplayString Condition="(tag.len == 0) && (anchor.len > 0)">{scalar.str,[scalar.len]} [A]</DisplayString>
|
||||
<DisplayString Condition="(tag.len > 0) && (anchor.len > 0)">{scalar.str,[scalar.len]} [T][A]</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="scalar">scalar</Item>
|
||||
<Item Name="tag">tag</Item>
|
||||
<Item Name="anchor">anchor</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::NodeType">
|
||||
<DisplayString Condition="((type & c4::yml::KEY ) == c4::yml::KEY) && ((type & c4::yml::VAL) == c4::yml::VAL)">[KEYVAL]</DisplayString>
|
||||
<DisplayString Condition="((type & c4::yml::KEY ) == c4::yml::KEY) && ((type & c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ]</DisplayString>
|
||||
<DisplayString Condition="((type & c4::yml::KEY ) == c4::yml::KEY) && ((type & c4::yml::MAP) == c4::yml::MAP)">[KEYMAP]</DisplayString>
|
||||
<DisplayString Condition="((type & c4::yml::DOC ) == c4::yml::DOC) && ((type & c4::yml::VAL) == c4::yml::VAL)">[DOCVAL]</DisplayString>
|
||||
<DisplayString Condition="((type & c4::yml::DOC ) == c4::yml::DOC) && ((type & c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
|
||||
<DisplayString Condition="((type & c4::yml::DOC ) == c4::yml::DOC) && ((type & c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::VAL ) == c4::yml::VAL" >[VAL]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::KEY ) == c4::yml::KEY" >[KEY]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
|
||||
<DisplayString Condition="(type & c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
|
||||
<Expand>
|
||||
<Synthetic Name="[type bits]">
|
||||
<Expand>
|
||||
<Item Name="[0]" Condition="(type & c4::yml::KEY) != 0">c4::yml::KEY</Item>
|
||||
<Item Name="[1]" Condition="(type & c4::yml::VAL) != 0">c4::yml::VAL</Item>
|
||||
<Item Name="[2]" Condition="(type & c4::yml::MAP) != 0">c4::yml::MAP</Item>
|
||||
<Item Name="[3]" Condition="(type & c4::yml::SEQ) != 0">c4::yml::SEQ</Item>
|
||||
<Item Name="[4]" Condition="(type & c4::yml::DOC) != 0">c4::yml::DOC</Item>
|
||||
<Item Name="[5]" Condition="(type & c4::yml::STREAM) != 0">c4::yml::STREAM</Item>
|
||||
<Item Name="[6]" Condition="(type & c4::yml::KEYREF) != 0">c4::yml::KEYREF</Item>
|
||||
<Item Name="[7]" Condition="(type & c4::yml::VALREF) != 0">c4::yml::VALREF</Item>
|
||||
<Item Name="[8]" Condition="(type & c4::yml::KEYANCH) != 0">c4::yml::KEYANCH</Item>
|
||||
<Item Name="[9]" Condition="(type & c4::yml::VALANCH) != 0">c4::yml::VALANCH</Item>
|
||||
<Item Name="[10]" Condition="(type & c4::yml::KEYTAG) != 0">c4::yml::KEYTAG</Item>
|
||||
<Item Name="[11]" Condition="(type & c4::yml::VALTAG) != 0">c4::yml::VALTAG</Item>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[style bits]">
|
||||
<Expand>
|
||||
<Item Name="[0]" Condition="(type & c4::yml::_WIP_KEY_UNFILT) != 0">c4::yml::_WIP_KEY_UNFILT</Item>
|
||||
<Item Name="[1]" Condition="(type & c4::yml::_WIP_VAL_UNFILT) != 0">c4::yml::_WIP_VAL_UNFILT</Item>
|
||||
<Item Name="[2]" Condition="(type & c4::yml::_WIP_STYLE_FLOW_SL) != 0">c4::yml::_WIP_STYLE_FLOW</Item>
|
||||
<Item Name="[3]" Condition="(type & c4::yml::_WIP_STYLE_FLOW_ML) != 0">c4::yml::_WIP_STYLE_FLOW</Item>
|
||||
<Item Name="[4]" Condition="(type & c4::yml::_WIP_STYLE_BLOCK) != 0">c4::yml::_WIP_STYLE_BLOCK</Item>
|
||||
<Item Name="[5]" Condition="(type & c4::yml::_WIP_KEY_LITERAL) != 0">c4::yml::_WIP_KEY_LITERAL</Item>
|
||||
<Item Name="[6]" Condition="(type & c4::yml::_WIP_VAL_LITERAL) != 0">c4::yml::_WIP_VAL_LITERAL</Item>
|
||||
<Item Name="[7]" Condition="(type & c4::yml::_WIP_KEY_FOLDED) != 0">c4::yml::_WIP_KEY_FOLDED</Item>
|
||||
<Item Name="[8]" Condition="(type & c4::yml::_WIP_VAL_FOLDED) != 0">c4::yml::_WIP_VAL_FOLDED</Item>
|
||||
<Item Name="[9]" Condition="(type & c4::yml::_WIP_KEY_SQUO) != 0">c4::yml::_WIP_KEY_SQUO</Item>
|
||||
<Item Name="[10]" Condition="(type & c4::yml::_WIP_VAL_SQUO) != 0">c4::yml::_WIP_VAL_SQUO</Item>
|
||||
<Item Name="[11]" Condition="(type & c4::yml::_WIP_KEY_DQUO) != 0">c4::yml::_WIP_KEY_DQUO</Item>
|
||||
<Item Name="[12]" Condition="(type & c4::yml::_WIP_VAL_DQUO) != 0">c4::yml::_WIP_VAL_DQUO</Item>
|
||||
<Item Name="[13]" Condition="(type & c4::yml::_WIP_KEY_PLAIN) != 0">c4::yml::_WIP_KEY_PLAIN</Item>
|
||||
<Item Name="[14]" Condition="(type & c4::yml::_WIP_VAL_PLAIN) != 0">c4::yml::_WIP_VAL_PLAIN</Item>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::NodeData">
|
||||
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::VAL) == c4::yml::VAL)">[KEYVAL] {m_key.scalar.str,[m_key.scalar.len]}: {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::MAP) == c4::yml::MAP)">[KEYMAP] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="((m_type.type & c4::yml::DOC ) == c4::yml::DOC) && ((m_type.type & c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
|
||||
<DisplayString Condition="((m_type.type & c4::yml::DOC ) == c4::yml::DOC) && ((m_type.type & c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::VAL ) == c4::yml::VAL" >[VAL] {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::KEY ) == c4::yml::KEY" >[KEY] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
|
||||
<DisplayString Condition="(m_type.type & c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="type">m_type</Item>
|
||||
<Item Name="key" Condition="(m_type.type & c4::yml::KEY) != 0">m_key</Item>
|
||||
<Item Name="val" Condition="(m_type.type & c4::yml::VAL) != 0">m_val</Item>
|
||||
<Item Name="key quoted" Condition="((m_type.type & c4::yml::KEY) != 0) && ((m_type.type & c4::yml::KEYQUO) != 0)">c4::yml::KEYQUO</Item>
|
||||
<Item Name="val quoted" Condition="((m_type.type & c4::yml::VAL) != 0) && ((m_type.type & c4::yml::VALQUO) != 0)">c4::yml::VALQUO</Item>
|
||||
<Item Name="key ref" Condition="(m_type.type & c4::yml::KEYREF) != 0">m_key.anchor</Item>
|
||||
<Item Name="val ref" Condition="(m_type.type & c4::yml::VALREF) != 0">m_val.anchor</Item>
|
||||
<Item Name="key anchor" Condition="(m_type.type & c4::yml::KEYANCH) != 0">m_key.anchor</Item>
|
||||
<Item Name="val anchor" Condition="(m_type.type & c4::yml::VALANCH) != 0">m_val.anchor</Item>
|
||||
<Item Name="parent" Condition="m_parent == c4::yml::NONE">NONE</Item>
|
||||
<Item Name="parent" Condition="m_parent != c4::yml::NONE">m_parent</Item>
|
||||
<Item Name="first child" Condition="m_first_child != c4::yml::NONE">m_first_child</Item>
|
||||
<Item Name="last child" Condition="m_last_child != c4::yml::NONE">m_last_child</Item>
|
||||
<Item Name="prev sibling" Condition="m_prev_sibling != c4::yml::NONE">m_prev_sibling</Item>
|
||||
<Item Name="next sibling" Condition="m_next_sibling != c4::yml::NONE">m_next_sibling</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::Tree">
|
||||
<DisplayString>sz={m_size}, cap={m_cap}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">m_size</Item>
|
||||
<Item Name="[capacity]">m_cap</Item>
|
||||
<Synthetic Name="[buffer]">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>m_cap</Size>
|
||||
<ValuePointer>m_buf</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Item Name="free head">m_free_head</Item>
|
||||
<Item Name="arena">m_arena</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::Tree::_lookup_path_token">
|
||||
<DisplayString>{value} ({type})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="value">value</Item>
|
||||
<Item Name="type">type</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::Tree::lookup_result">
|
||||
<DisplayString>{path} -- target={target} closest={closest}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="target">target</Item>
|
||||
<Item Name="closest">closest</Item>
|
||||
<Item Name="path_pos">path_pos</Item>
|
||||
<Item Name="path">path</Item>
|
||||
<Synthetic Name="[resolved]">
|
||||
<DisplayString>{path.str,[path_pos]}</DisplayString>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[unresolved]">
|
||||
<DisplayString>{path.str+path_pos,[path.len-path_pos]}</DisplayString>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::NodeRef">
|
||||
<DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
|
||||
<DisplayString Condition="(m_seed.len != c4::yml::NONE) && (m_seed.str == nullptr)">[INDEX SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
|
||||
<DisplayString Condition="(m_seed.len != c4::yml::NONE) && (m_seed.str != nullptr)">[NAMED SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
|
||||
<DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="id">m_id</Item>
|
||||
<Item Name="element">*(m_tree->m_buf + m_id)</Item>
|
||||
<Item Name="tree">m_tree</Item>
|
||||
<Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) && (((m_tree->m_buf + m_id)->m_type.type & (c4::yml::MAP|c4::yml::SEQ)) != 0)">
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="tree" InitialValue="m_tree"/>
|
||||
<Variable Name="buf" InitialValue="m_tree->m_buf"/>
|
||||
<Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
|
||||
<Loop>
|
||||
<Item>buf + curr</Item>
|
||||
<Exec>curr = (buf + curr)->m_next_sibling</Exec>
|
||||
<Break Condition="curr == c4::yml::NONE"/>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::ConstNodeRef">
|
||||
<DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
|
||||
<DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="id">m_id</Item>
|
||||
<Item Name="element">*(m_tree->m_buf + m_id)</Item>
|
||||
<Item Name="tree">m_tree</Item>
|
||||
<Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) && (((m_tree->m_buf + m_id)->m_type.type & (c4::yml::MAP|c4::yml::SEQ)) != 0)">
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="tree" InitialValue="m_tree"/>
|
||||
<Variable Name="buf" InitialValue="m_tree->m_buf"/>
|
||||
<Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
|
||||
<Loop>
|
||||
<Item>buf + curr</Item>
|
||||
<Exec>curr = (buf + curr)->m_next_sibling</Exec>
|
||||
<Break Condition="curr == c4::yml::NONE"/>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::detail::ReferenceResolver">
|
||||
<DisplayString>#refs={refs.m_size} #nodes={t->m_size}</DisplayString>
|
||||
<Expand>
|
||||
<Synthetic Name="[ref_nodes]">
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="curr" InitialValue="0"/>
|
||||
<Loop>
|
||||
<Item>t->m_buf + (refs.m_stack + curr)->node</Item>
|
||||
<Exec>curr = curr+1</Exec>
|
||||
<Break Condition="curr >= refs.m_size"/>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[refs]">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>refs.m_size</Size>
|
||||
<ValuePointer>refs.m_stack</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Item Name="[tree]">t</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::detail::stack<*,*>">
|
||||
<DisplayString>sz={m_size} cap={m_capacity}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[size]">m_size</Item>
|
||||
<Item Name="[capacity]">m_capacity</Item>
|
||||
<Item Name="[is small]">m_buf == m_stack</Item>
|
||||
<Synthetic Name="[items]">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>m_size</Size>
|
||||
<ValuePointer>m_stack</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::detail::FilterProcessorSrcDst">
|
||||
<DisplayString>src={src.str,[rpos]} dst={dst.str,[wpos]}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[src]">src</Item>
|
||||
<Item Name="[dst]">dst</Item>
|
||||
<Item Name="[rpos]">rpos</Item>
|
||||
<Item Name="[wpos]">wpos</Item>
|
||||
<Synthetic Name="[read]">
|
||||
<StringView>src.str,[rpos]</StringView>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>rpos</Size>
|
||||
<ValuePointer>src.str</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="c4::yml::detail::FilterProcessorInplace">
|
||||
<DisplayString>src={src.str,[rpos]} dst={src.str,[wpos]}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[rpos]">rpos</Item>
|
||||
<Item Name="[wpos]">wpos</Item>
|
||||
<Item Name="[wcap]">wcap</Item>
|
||||
<Synthetic Name="[buf]">
|
||||
<StringView>src.str,[wcap]</StringView>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>wcap</Size>
|
||||
<ValuePointer>src.str</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Item Name="[src]">src</Item>
|
||||
<Synthetic Name="[to be read]">
|
||||
<StringView>src.str+rpos,[src.len-rpos]</StringView>
|
||||
<Expand>
|
||||
<ArrayItems><Size>src.len-rpos</Size><ValuePointer>src.str+rpos</ValuePointer></ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[read]">
|
||||
<StringView>src.str,[rpos]</StringView>
|
||||
<Expand>
|
||||
<ArrayItems><Size>rpos</Size><ValuePointer>src.str</ValuePointer></ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[written]">
|
||||
<StringView>src.str,[wpos]</StringView>
|
||||
<Expand>
|
||||
<ArrayItems><Size>wpos</Size><ValuePointer>src.str</ValuePointer></ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
</AutoVisualizer>
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
#ifndef _RYML_STD_HPP_
|
||||
#define _RYML_STD_HPP_
|
||||
|
||||
#include "./c4/yml/std/std.hpp"
|
||||
|
||||
#endif /* _RYML_STD_HPP_ */
|
||||
Vendored
-139
@@ -1,139 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{DE9653B6-17DD-356A-9EE0-28A731772587}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectName>rapidyaml</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset Condition="!$(Configuration.Contains(Clang))">$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<PlatformToolset Condition="$(Configuration.Contains(Clang))">ClangCL</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
|
||||
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
|
||||
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\DefaultProjectRootDir.props" />
|
||||
<Import Project="..\3rdparty.props" />
|
||||
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
|
||||
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
|
||||
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
|
||||
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);C4_NO_DEBUG_BREAK</PreprocessorDefinitions>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)src;$(ProjectDir)include;$(ProjectDir)..\fast_float\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="$(Configuration.Contains(Debug))">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="!$(Configuration.Contains(Debug))">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\c4\base64.hpp" />
|
||||
<ClInclude Include="include\c4\blob.hpp" />
|
||||
<ClInclude Include="include\c4\charconv.hpp" />
|
||||
<ClInclude Include="include\c4\compiler.hpp" />
|
||||
<ClInclude Include="include\c4\config.hpp" />
|
||||
<ClInclude Include="include\c4\cpu.hpp" />
|
||||
<ClInclude Include="include\c4\dump.hpp" />
|
||||
<ClInclude Include="include\c4\error.hpp" />
|
||||
<ClInclude Include="include\c4\export.hpp" />
|
||||
<ClInclude Include="include\c4\format.hpp" />
|
||||
<ClInclude Include="include\c4\language.hpp" />
|
||||
<ClInclude Include="include\c4\memory_util.hpp" />
|
||||
<ClInclude Include="include\c4\platform.hpp" />
|
||||
<ClInclude Include="include\c4\preprocessor.hpp" />
|
||||
<ClInclude Include="include\c4\std\std.hpp" />
|
||||
<ClInclude Include="include\c4\std\std_fwd.hpp" />
|
||||
<ClInclude Include="include\c4\std\string.hpp" />
|
||||
<ClInclude Include="include\c4\std\string_fwd.hpp" />
|
||||
<ClInclude Include="include\c4\std\string_view.hpp" />
|
||||
<ClInclude Include="include\c4\std\tuple.hpp" />
|
||||
<ClInclude Include="include\c4\std\vector.hpp" />
|
||||
<ClInclude Include="include\c4\std\vector_fwd.hpp" />
|
||||
<ClInclude Include="include\c4\substr.hpp" />
|
||||
<ClInclude Include="include\c4\substr_fwd.hpp" />
|
||||
<ClInclude Include="include\c4\szconv.hpp" />
|
||||
<ClInclude Include="include\c4\types.hpp" />
|
||||
<ClInclude Include="include\c4\utf.hpp" />
|
||||
<ClInclude Include="include\c4\windows.hpp" />
|
||||
<ClInclude Include="include\c4\windows_pop.hpp" />
|
||||
<ClInclude Include="include\c4\windows_push.hpp" />
|
||||
<ClInclude Include="include\c4\yml\common.hpp" />
|
||||
<ClInclude Include="include\c4\yml\detail\checks.hpp" />
|
||||
<ClInclude Include="include\c4\yml\detail\dbgprint.hpp" />
|
||||
<ClInclude Include="include\c4\yml\detail\print.hpp" />
|
||||
<ClInclude Include="include\c4\yml\detail\stack.hpp" />
|
||||
<ClInclude Include="include\c4\yml\emit.def.hpp" />
|
||||
<ClInclude Include="include\c4\yml\emit.hpp" />
|
||||
<ClInclude Include="include\c4\yml\export.hpp" />
|
||||
<ClInclude Include="include\c4\yml\node.hpp" />
|
||||
<ClInclude Include="include\c4\yml\parse.hpp" />
|
||||
<ClInclude Include="include\c4\yml\preprocess.hpp" />
|
||||
<ClInclude Include="include\c4\yml\std\map.hpp" />
|
||||
<ClInclude Include="include\c4\yml\std\std.hpp" />
|
||||
<ClInclude Include="include\c4\yml\std\string.hpp" />
|
||||
<ClInclude Include="include\c4\yml\std\vector.hpp" />
|
||||
<ClInclude Include="include\c4\yml\tag.hpp" />
|
||||
<ClInclude Include="include\c4\yml\version.hpp" />
|
||||
<ClInclude Include="include\c4\yml\tree.hpp" />
|
||||
<ClInclude Include="include\c4\yml\writer.hpp" />
|
||||
<ClInclude Include="include\c4\yml\event_handler_stack.hpp" />
|
||||
<ClInclude Include="include\c4\yml\event_handler_tree.hpp" />
|
||||
<ClInclude Include="include\c4\yml\filter_processor.hpp" />
|
||||
<ClInclude Include="include\c4\yml\fwd.hpp" />
|
||||
<ClInclude Include="include\c4\yml\node_type.hpp" />
|
||||
<ClInclude Include="include\c4\yml\parse_engine.def.hpp" />
|
||||
<ClInclude Include="include\c4\yml\parse_engine.hpp" />
|
||||
<ClInclude Include="include\c4\yml\parser_state.hpp" />
|
||||
<ClInclude Include="include\c4\yml\reference_resolver.hpp" />
|
||||
<ClInclude Include="include\c4\yml\yml.hpp" />
|
||||
<ClInclude Include="include\ryml.hpp" />
|
||||
<ClInclude Include="include\ryml_std.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="include\c4\c4core.natvis" />
|
||||
<Natvis Include="include\ryml.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\c4\base64.cpp" />
|
||||
<ClCompile Include="src\c4\error.cpp" />
|
||||
<ClCompile Include="src\c4\format.cpp" />
|
||||
<ClCompile Include="src\c4\language.cpp" />
|
||||
<ClCompile Include="src\c4\memory_util.cpp" />
|
||||
<ClCompile Include="src\c4\utf.cpp" />
|
||||
<ClCompile Include="src\c4\yml\common.cpp" />
|
||||
<ClCompile Include="src\c4\yml\node.cpp" />
|
||||
<ClCompile Include="src\c4\yml\parse.cpp" />
|
||||
<ClCompile Include="src\c4\yml\preprocess.cpp" />
|
||||
<ClCompile Include="src\c4\yml\tree.cpp" />
|
||||
<ClCompile Include="src\c4\yml\node_type.cpp" />
|
||||
<ClCompile Include="src\c4\yml\reference_resolver.cpp" />
|
||||
<ClCompile Include="src\c4\yml\tag.cpp" />
|
||||
<ClCompile Include="src\c4\yml\version.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Vendored
-226
@@ -1,226 +0,0 @@
|
||||
#include "c4/base64.hpp"
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wchar-subscripts" // array subscript is of type 'char'
|
||||
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wuseless-cast"
|
||||
# pragma GCC diagnostic ignored "-Wchar-subscripts"
|
||||
# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
|
||||
// NOLINTBEGIN(bugprone-signed-char-misuse,cert-str34-c,hicpp-signed-bitwise)
|
||||
|
||||
namespace c4 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr static const char base64_sextet_to_char_[64] = {
|
||||
/* 0/ 65*/ 'A', /* 1/ 66*/ 'B', /* 2/ 67*/ 'C', /* 3/ 68*/ 'D',
|
||||
/* 4/ 69*/ 'E', /* 5/ 70*/ 'F', /* 6/ 71*/ 'G', /* 7/ 72*/ 'H',
|
||||
/* 8/ 73*/ 'I', /* 9/ 74*/ 'J', /*10/ 75*/ 'K', /*11/ 74*/ 'L',
|
||||
/*12/ 77*/ 'M', /*13/ 78*/ 'N', /*14/ 79*/ 'O', /*15/ 78*/ 'P',
|
||||
/*16/ 81*/ 'Q', /*17/ 82*/ 'R', /*18/ 83*/ 'S', /*19/ 82*/ 'T',
|
||||
/*20/ 85*/ 'U', /*21/ 86*/ 'V', /*22/ 87*/ 'W', /*23/ 88*/ 'X',
|
||||
/*24/ 89*/ 'Y', /*25/ 90*/ 'Z', /*26/ 97*/ 'a', /*27/ 98*/ 'b',
|
||||
/*28/ 99*/ 'c', /*29/100*/ 'd', /*30/101*/ 'e', /*31/102*/ 'f',
|
||||
/*32/103*/ 'g', /*33/104*/ 'h', /*34/105*/ 'i', /*35/106*/ 'j',
|
||||
/*36/107*/ 'k', /*37/108*/ 'l', /*38/109*/ 'm', /*39/110*/ 'n',
|
||||
/*40/111*/ 'o', /*41/112*/ 'p', /*42/113*/ 'q', /*43/114*/ 'r',
|
||||
/*44/115*/ 's', /*45/116*/ 't', /*46/117*/ 'u', /*47/118*/ 'v',
|
||||
/*48/119*/ 'w', /*49/120*/ 'x', /*50/121*/ 'y', /*51/122*/ 'z',
|
||||
/*52/ 48*/ '0', /*53/ 49*/ '1', /*54/ 50*/ '2', /*55/ 51*/ '3',
|
||||
/*56/ 52*/ '4', /*57/ 53*/ '5', /*58/ 54*/ '6', /*59/ 55*/ '7',
|
||||
/*60/ 56*/ '8', /*61/ 57*/ '9', /*62/ 43*/ '+', /*63/ 47*/ '/',
|
||||
};
|
||||
|
||||
// https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
|
||||
constexpr static const char base64_char_to_sextet_[128] = {
|
||||
#define __ char(-1) // undefined below
|
||||
/* 0 NUL*/ __, /* 1 SOH*/ __, /* 2 STX*/ __, /* 3 ETX*/ __,
|
||||
/* 4 EOT*/ __, /* 5 ENQ*/ __, /* 6 ACK*/ __, /* 7 BEL*/ __,
|
||||
/* 8 BS */ __, /* 9 TAB*/ __, /* 10 LF */ __, /* 11 VT */ __,
|
||||
/* 12 FF */ __, /* 13 CR */ __, /* 14 SO */ __, /* 15 SI */ __,
|
||||
/* 16 DLE*/ __, /* 17 DC1*/ __, /* 18 DC2*/ __, /* 19 DC3*/ __,
|
||||
/* 20 DC4*/ __, /* 21 NAK*/ __, /* 22 SYN*/ __, /* 23 ETB*/ __,
|
||||
/* 24 CAN*/ __, /* 25 EM */ __, /* 26 SUB*/ __, /* 27 ESC*/ __,
|
||||
/* 28 FS */ __, /* 29 GS */ __, /* 30 RS */ __, /* 31 US */ __,
|
||||
/* 32 SPC*/ __, /* 33 ! */ __, /* 34 " */ __, /* 35 # */ __,
|
||||
/* 36 $ */ __, /* 37 % */ __, /* 38 & */ __, /* 39 ' */ __,
|
||||
/* 40 ( */ __, /* 41 ) */ __, /* 42 * */ __, /* 43 + */ 62,
|
||||
/* 44 , */ __, /* 45 - */ __, /* 46 . */ __, /* 47 / */ 63,
|
||||
/* 48 0 */ 52, /* 49 1 */ 53, /* 50 2 */ 54, /* 51 3 */ 55,
|
||||
/* 52 4 */ 56, /* 53 5 */ 57, /* 54 6 */ 58, /* 55 7 */ 59,
|
||||
/* 56 8 */ 60, /* 57 9 */ 61, /* 58 : */ __, /* 59 ; */ __,
|
||||
/* 60 < */ __, /* 61 = */ __, /* 62 > */ __, /* 63 ? */ __,
|
||||
/* 64 @ */ __, /* 65 A */ 0, /* 66 B */ 1, /* 67 C */ 2,
|
||||
/* 68 D */ 3, /* 69 E */ 4, /* 70 F */ 5, /* 71 G */ 6,
|
||||
/* 72 H */ 7, /* 73 I */ 8, /* 74 J */ 9, /* 75 K */ 10,
|
||||
/* 76 L */ 11, /* 77 M */ 12, /* 78 N */ 13, /* 79 O */ 14,
|
||||
/* 80 P */ 15, /* 81 Q */ 16, /* 82 R */ 17, /* 83 S */ 18,
|
||||
/* 84 T */ 19, /* 85 U */ 20, /* 86 V */ 21, /* 87 W */ 22,
|
||||
/* 88 X */ 23, /* 89 Y */ 24, /* 90 Z */ 25, /* 91 [ */ __,
|
||||
/* 92 \ */ __, /* 93 ] */ __, /* 94 ^ */ __, /* 95 _ */ __,
|
||||
/* 96 ` */ __, /* 97 a */ 26, /* 98 b */ 27, /* 99 c */ 28,
|
||||
/*100 d */ 29, /*101 e */ 30, /*102 f */ 31, /*103 g */ 32,
|
||||
/*104 h */ 33, /*105 i */ 34, /*106 j */ 35, /*107 k */ 36,
|
||||
/*108 l */ 37, /*109 m */ 38, /*110 n */ 39, /*111 o */ 40,
|
||||
/*112 p */ 41, /*113 q */ 42, /*114 r */ 43, /*115 s */ 44,
|
||||
/*116 t */ 45, /*117 u */ 46, /*118 v */ 47, /*119 w */ 48,
|
||||
/*120 x */ 49, /*121 y */ 50, /*122 z */ 51, /*123 { */ __,
|
||||
/*124 | */ __, /*125 } */ __, /*126 ~ */ __, /*127 DEL*/ __,
|
||||
#undef __
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
void base64_test_tables()
|
||||
{
|
||||
for(size_t i = 0; i < C4_COUNTOF(detail::base64_sextet_to_char_); ++i)
|
||||
{
|
||||
char s2c = base64_sextet_to_char_[i];
|
||||
char c2s = base64_char_to_sextet_[(unsigned)s2c];
|
||||
C4_CHECK((size_t)c2s == i);
|
||||
}
|
||||
for(size_t i = 0; i < C4_COUNTOF(detail::base64_char_to_sextet_); ++i)
|
||||
{
|
||||
char c2s = base64_char_to_sextet_[i];
|
||||
if(c2s == char(-1))
|
||||
continue;
|
||||
char s2c = base64_sextet_to_char_[(unsigned)c2s];
|
||||
C4_CHECK((size_t)s2c == i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
|
||||
bool base64_valid(csubstr encoded)
|
||||
{
|
||||
if((encoded.len & size_t(3u)) != size_t(0)) // (encoded.len % 4u)
|
||||
return false;
|
||||
for(const char c : encoded)
|
||||
{
|
||||
if(c < 0/* || c >= 128*/)
|
||||
return false;
|
||||
if(c == '=')
|
||||
continue;
|
||||
if(detail::base64_char_to_sextet_[c] == char(-1))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
size_t base64_encode(substr buf, cblob data)
|
||||
{
|
||||
#define c4append_(c) { if(pos < buf.len) { buf.str[pos] = (c); } ++pos; }
|
||||
#define c4append_idx_(char_idx) \
|
||||
{\
|
||||
C4_XASSERT((char_idx) < sizeof(detail::base64_sextet_to_char_));\
|
||||
c4append_(detail::base64_sextet_to_char_[(char_idx)]);\
|
||||
}
|
||||
size_t rem, pos = 0;
|
||||
constexpr const uint32_t sextet_mask = uint32_t(1 << 6) - 1;
|
||||
const unsigned char *C4_RESTRICT d = (const unsigned char *) data.buf; // cast to unsigned to avoid wrapping high-bits
|
||||
for(rem = data.len; rem >= 3; rem -= 3, d += 3)
|
||||
{
|
||||
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8) | (uint32_t(d[2])));
|
||||
c4append_idx_((val >> 18) & sextet_mask);
|
||||
c4append_idx_((val >> 12) & sextet_mask);
|
||||
c4append_idx_((val >> 6) & sextet_mask);
|
||||
c4append_idx_((val ) & sextet_mask);
|
||||
}
|
||||
C4_ASSERT(rem < 3);
|
||||
if(rem == 2)
|
||||
{
|
||||
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8));
|
||||
c4append_idx_((val >> 18) & sextet_mask);
|
||||
c4append_idx_((val >> 12) & sextet_mask);
|
||||
c4append_idx_((val >> 6) & sextet_mask);
|
||||
c4append_('=');
|
||||
}
|
||||
else if(rem == 1)
|
||||
{
|
||||
const uint32_t val = ((uint32_t(d[0]) << 16));
|
||||
c4append_idx_((val >> 18) & sextet_mask);
|
||||
c4append_idx_((val >> 12) & sextet_mask);
|
||||
c4append_('=');
|
||||
c4append_('=');
|
||||
}
|
||||
return pos;
|
||||
|
||||
#undef c4append_
|
||||
#undef c4append_idx_
|
||||
}
|
||||
|
||||
|
||||
size_t base64_decode(csubstr encoded, blob data)
|
||||
{
|
||||
#define c4append_(c) { if(wpos < data.len) { data.buf[wpos] = static_cast<c4::byte>(c); } ++wpos; }
|
||||
#define c4appendval_(c, shift)\
|
||||
{\
|
||||
C4_XASSERT((c) >= 0);\
|
||||
C4_XASSERT(size_t(c) < sizeof(detail::base64_char_to_sextet_));\
|
||||
val |= static_cast<uint32_t>(detail::base64_char_to_sextet_[(c)]) << ((shift) * 6);\
|
||||
}
|
||||
C4_ASSERT(base64_valid(encoded));
|
||||
C4_CHECK((encoded.len & 3u) == 0);
|
||||
size_t wpos = 0; // the write position
|
||||
const char *C4_RESTRICT d = encoded.str;
|
||||
constexpr const uint32_t full_byte = 0xff;
|
||||
// process every quartet of input 6 bits --> triplet of output bytes
|
||||
for(size_t rpos = 0; rpos < encoded.len; rpos += 4, d += 4)
|
||||
{
|
||||
if(d[2] == '=' || d[3] == '=') // skip the last quartet if it is padded
|
||||
{
|
||||
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||
break;
|
||||
}
|
||||
uint32_t val = 0;
|
||||
c4appendval_(d[3], 0);
|
||||
c4appendval_(d[2], 1);
|
||||
c4appendval_(d[1], 2);
|
||||
c4appendval_(d[0], 3);
|
||||
c4append_((val >> (2 * 8)) & full_byte);
|
||||
c4append_((val >> (1 * 8)) & full_byte);
|
||||
c4append_((val ) & full_byte);
|
||||
}
|
||||
// deal with the last quartet when it is padded
|
||||
if(d == encoded.str + encoded.len)
|
||||
return wpos;
|
||||
if(d[2] == '=') // 2 padding chars
|
||||
{
|
||||
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||
C4_ASSERT(d[3] == '=');
|
||||
uint32_t val = 0;
|
||||
c4appendval_(d[1], 2);
|
||||
c4appendval_(d[0], 3);
|
||||
c4append_((val >> (2 * 8)) & full_byte);
|
||||
}
|
||||
else if(d[3] == '=') // 1 padding char
|
||||
{
|
||||
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||
uint32_t val = 0;
|
||||
c4appendval_(d[2], 1);
|
||||
c4appendval_(d[1], 2);
|
||||
c4appendval_(d[0], 3);
|
||||
c4append_((val >> (2 * 8)) & full_byte);
|
||||
c4append_((val >> (1 * 8)) & full_byte);
|
||||
}
|
||||
return wpos;
|
||||
#undef c4append_
|
||||
#undef c4appendval_
|
||||
}
|
||||
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(bugprone-signed-char-misuse,cert-str34-c,hicpp-signed-bitwise)
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
Vendored
-234
@@ -1,234 +0,0 @@
|
||||
#include "c4/error.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define C4_LOGF_ERR(...) (void)fprintf(stderr, __VA_ARGS__); (void)fflush(stderr)
|
||||
#define C4_LOGF_WARN(...) (void)fprintf(stderr, __VA_ARGS__); (void)fflush(stderr)
|
||||
#define C4_LOGP(msg, ...) (void)printf(msg)
|
||||
|
||||
#if defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
|
||||
# include "c4/windows.hpp"
|
||||
#elif defined(C4_PS4)
|
||||
# include <libdbg.h>
|
||||
#elif defined(C4_UNIX) || defined(C4_LINUX)
|
||||
# include <sys/stat.h>
|
||||
# include <cstring>
|
||||
# include <fcntl.h>
|
||||
#elif defined(C4_MACOS) || defined(C4_IOS)
|
||||
# include <assert.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
// the amalgamation tool is dumb and was omitting this include under MACOS.
|
||||
// So do it only once:
|
||||
#if defined(C4_UNIX) || defined(C4_LINUX) || defined(C4_MACOS) || defined(C4_IOS)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
|
||||
# include <exception>
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
// NOLINTBEGIN(*use-anonymous-namespace*,cert-dcl50-cpp)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace c4 {
|
||||
|
||||
static error_flags s_error_flags = ON_ERROR_DEFAULTS;
|
||||
static error_callback_type s_error_callback = nullptr;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
error_flags get_error_flags()
|
||||
{
|
||||
return s_error_flags;
|
||||
}
|
||||
void set_error_flags(error_flags flags)
|
||||
{
|
||||
s_error_flags = flags;
|
||||
}
|
||||
|
||||
error_callback_type get_error_callback()
|
||||
{
|
||||
return s_error_callback;
|
||||
}
|
||||
/** Set the function which is called when an error occurs. */
|
||||
void set_error_callback(error_callback_type cb)
|
||||
{
|
||||
s_error_callback = cb;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void handle_error(srcloc where, const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t msglen = 0;
|
||||
if(s_error_flags & (ON_ERROR_LOG|ON_ERROR_CALLBACK))
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ilen = vsnprintf(buf, sizeof(buf), fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized)
|
||||
va_end(args);
|
||||
msglen = ilen >= 0 && ilen < (int)sizeof(buf) ? static_cast<size_t>(ilen) : sizeof(buf)-1;
|
||||
}
|
||||
|
||||
if(s_error_flags & ON_ERROR_LOG)
|
||||
{
|
||||
C4_LOGF_ERR("\n");
|
||||
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
|
||||
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
|
||||
C4_LOGF_ERR("%s:%d: ERROR here: %s\n", where.file, where.line, where.func);
|
||||
#elif defined(C4_ERROR_SHOWS_FILELINE)
|
||||
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
|
||||
#elif ! defined(C4_ERROR_SHOWS_FUNC)
|
||||
C4_LOGF_ERR("ERROR: %s\n", buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(s_error_flags & ON_ERROR_CALLBACK)
|
||||
{
|
||||
if(s_error_callback)
|
||||
{
|
||||
s_error_callback(buf, msglen);
|
||||
}
|
||||
}
|
||||
|
||||
if(s_error_flags & ON_ERROR_THROW)
|
||||
{
|
||||
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
|
||||
throw std::runtime_error(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(s_error_flags & ON_ERROR_ABORT)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
abort(); // abort anyway, in case nothing was set
|
||||
C4_UNREACHABLE_AFTER_ERR();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void handle_warning(srcloc where, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[1024];
|
||||
va_start(args, fmt);
|
||||
int ret = vsnprintf(buf, sizeof(buf), fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized)
|
||||
if(ret+1 > (int)sizeof(buf))
|
||||
buf[sizeof(buf) - 1] = '\0'; // truncate
|
||||
else if(ret < 0)
|
||||
buf[0] = '\0'; // output/format error
|
||||
va_end(args);
|
||||
C4_LOGF_WARN("\n");
|
||||
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
|
||||
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf);
|
||||
C4_LOGF_WARN("%s:%d: WARNING: here: %s\n", where.file, where.line, where.func);
|
||||
#elif defined(C4_ERROR_SHOWS_FILELINE)
|
||||
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf);
|
||||
#elif ! defined(C4_ERROR_SHOWS_FUNC)
|
||||
C4_LOGF_WARN("WARNING: %s\n", buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool is_debugger_attached()
|
||||
{
|
||||
#if defined(C4_UNIX) || defined(C4_LINUX)
|
||||
static bool first_call = true;
|
||||
static bool first_call_result = false;
|
||||
if(first_call)
|
||||
{
|
||||
first_call = false;
|
||||
C4_SUPPRESS_WARNING_GCC_PUSH
|
||||
#if defined(__GNUC__) && __GNUC__ > 9
|
||||
C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak")
|
||||
#endif
|
||||
//! @see http://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb
|
||||
//! (this answer: http://stackoverflow.com/a/24969863/3968589 )
|
||||
char buf[1024] = "";
|
||||
int status_fd = open("/proc/self/status", O_RDONLY); // NOLINT
|
||||
if (status_fd == -1)
|
||||
return false;
|
||||
ssize_t num_read = ::read(status_fd, buf, sizeof(buf));
|
||||
if (num_read > 0)
|
||||
{
|
||||
static const char TracerPid[] = "TracerPid:";
|
||||
char *tracer_pid;
|
||||
if(num_read < 1024)
|
||||
buf[num_read] = 0;
|
||||
tracer_pid = strstr(buf, TracerPid);
|
||||
if(tracer_pid)
|
||||
first_call_result = !!::atoi(tracer_pid + sizeof(TracerPid) - 1); // NOLINT
|
||||
}
|
||||
close(status_fd);
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
}
|
||||
return first_call_result;
|
||||
#elif defined(C4_PS4)
|
||||
return (sceDbgIsDebuggerAttached() != 0);
|
||||
#elif defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
|
||||
return IsDebuggerPresent() != 0;
|
||||
#elif defined(C4_MACOS) || defined(C4_IOS)
|
||||
// https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x
|
||||
// Returns true if the current process is being debugged (either
|
||||
// running under the debugger or has a debugger attached post facto).
|
||||
int junk;
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size;
|
||||
|
||||
// Initialize the flags so that, if sysctl fails for some bizarre
|
||||
// reason, we get a predictable result.
|
||||
|
||||
info.kp_proc.p_flag = 0;
|
||||
|
||||
// Initialize mib, which tells sysctl the info we want, in this case
|
||||
// we're looking for information about a specific process ID.
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
// Call sysctl.
|
||||
|
||||
size = sizeof(info);
|
||||
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
||||
assert(junk == 0);
|
||||
(void)junk;
|
||||
|
||||
// We're being debugged if the P_TRACED flag is set.
|
||||
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} // is_debugger_attached()
|
||||
|
||||
} // namespace c4
|
||||
|
||||
// NOLINTEND(*use-anonymous-namespace*,cert-dcl50-cpp)
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
Vendored
-64
@@ -1,64 +0,0 @@
|
||||
#include "c4/format.hpp"
|
||||
|
||||
#include <memory> // for std::align
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
|
||||
namespace c4 {
|
||||
|
||||
|
||||
size_t to_chars(substr buf, fmt::const_raw_wrapper r)
|
||||
{
|
||||
void * vptr = buf.str;
|
||||
size_t space = buf.len;
|
||||
char * ptr = (char*) std::align(r.alignment, r.len, vptr, space);
|
||||
if(ptr == nullptr)
|
||||
{
|
||||
// if it was not possible to align, return a conservative estimate
|
||||
// of the required space
|
||||
return r.alignment + r.len;
|
||||
}
|
||||
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
|
||||
size_t sz = static_cast<size_t>(ptr - buf.str) + r.len;
|
||||
if(sz <= buf.len)
|
||||
{
|
||||
memcpy(ptr, r.buf, r.len);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
bool from_chars(csubstr buf, fmt::raw_wrapper *r)
|
||||
{
|
||||
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wcast-qual")
|
||||
void * vptr = (void*)buf.str;
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
size_t space = buf.len;
|
||||
char * ptr = (char*) std::align(r->alignment, r->len, vptr, space);
|
||||
C4_CHECK(ptr != nullptr);
|
||||
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
|
||||
C4_SUPPRESS_WARNING_GCC_PUSH
|
||||
#if defined(__GNUC__) && __GNUC__ > 9
|
||||
C4_SUPPRESS_WARNING_GCC("-Wanalyzer-null-argument")
|
||||
#endif
|
||||
memcpy(r->buf, ptr, r->len);
|
||||
C4_SUPPRESS_WARNING_GCC_POP
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace c4
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
#include "c4/language.hpp"
|
||||
|
||||
namespace c4 {
|
||||
namespace detail {
|
||||
|
||||
#ifndef __GNUC__
|
||||
void use_char_pointer(char const volatile* v)
|
||||
{
|
||||
C4_UNUSED(v);
|
||||
}
|
||||
#else
|
||||
void foo() {} // to avoid empty file warning from the linker
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace c4
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
#include "c4/memory_util.hpp"
|
||||
#include "c4/error.hpp"
|
||||
|
||||
namespace c4 {
|
||||
|
||||
|
||||
/** Fills 'dest' with the first 'pattern_size' bytes at 'pattern', 'num_times'. */
|
||||
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times)
|
||||
{
|
||||
if(C4_UNLIKELY(num_times == 0))
|
||||
return;
|
||||
C4_ASSERT( ! mem_overlaps(dest, pattern, num_times*pattern_size, pattern_size));
|
||||
char *begin = static_cast<char*>(dest);
|
||||
char *end = begin + num_times * pattern_size;
|
||||
// copy the pattern once
|
||||
::memcpy(begin, pattern, pattern_size);
|
||||
// now copy from dest to itself, doubling up every time
|
||||
size_t n = pattern_size;
|
||||
while(begin + 2*n < end)
|
||||
{
|
||||
::memcpy(begin + n, begin, n);
|
||||
n <<= 1u; // double n
|
||||
}
|
||||
// copy the missing part
|
||||
if(begin + n < end)
|
||||
{
|
||||
::memcpy(begin + n, begin, static_cast<size_t>(end - (begin + n)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace c4
|
||||
Vendored
-114
@@ -1,114 +0,0 @@
|
||||
#include "c4/utf.hpp"
|
||||
#include "c4/charconv.hpp"
|
||||
|
||||
namespace c4 {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, const uint32_t code)
|
||||
{
|
||||
C4_ASSERT(buf);
|
||||
C4_ASSERT(buflen >= 4);
|
||||
C4_UNUSED(buflen);
|
||||
if (code <= UINT32_C(0x7f))
|
||||
{
|
||||
buf[0] = (uint8_t)code;
|
||||
return 1u;
|
||||
}
|
||||
else if(code <= UINT32_C(0x7ff))
|
||||
{
|
||||
buf[0] = (uint8_t)(UINT32_C(0xc0) | (code >> 6u)); /* 110xxxxx */
|
||||
buf[1] = (uint8_t)(UINT32_C(0x80) | (code & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
return 2u;
|
||||
}
|
||||
else if(code <= UINT32_C(0xffff))
|
||||
{
|
||||
buf[0] = (uint8_t)(UINT32_C(0xe0) | ((code >> 12u))); /* 1110xxxx */
|
||||
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 6u) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
return 3u;
|
||||
}
|
||||
else if(code <= UINT32_C(0x10ffff))
|
||||
{
|
||||
buf[0] = (uint8_t)(UINT32_C(0xf0) | ((code >> 18u))); /* 11110xxx */
|
||||
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 12u) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code >> 6u) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
buf[3] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||
return 4u;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
substr decode_code_point(substr out, csubstr code_point)
|
||||
{
|
||||
C4_ASSERT(out.len >= 4);
|
||||
C4_ASSERT(!code_point.begins_with("U+"));
|
||||
C4_ASSERT(!code_point.begins_with("\\x"));
|
||||
C4_ASSERT(!code_point.begins_with("\\u"));
|
||||
C4_ASSERT(!code_point.begins_with("\\U"));
|
||||
C4_ASSERT(!code_point.begins_with('0'));
|
||||
C4_ASSERT(code_point.len <= 8);
|
||||
C4_ASSERT(code_point.len > 0);
|
||||
uint32_t code_point_val;
|
||||
C4_CHECK(read_hex(code_point, &code_point_val));
|
||||
size_t ret = decode_code_point((uint8_t*)out.str, out.len, code_point_val);
|
||||
C4_ASSERT(ret <= 4);
|
||||
return out.first(ret);
|
||||
}
|
||||
|
||||
size_t first_non_bom(csubstr s)
|
||||
{
|
||||
#define c4check2_(s, c0, c1) ((s).len >= 2) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)))
|
||||
#define c4check3_(s, c0, c1, c2) ((s).len >= 3) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)) && ((s).str[2] == (c2)))
|
||||
#define c4check4_(s, c0, c1, c2, c3) ((s).len >= 4) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)) && ((s).str[2] == (c2)) && ((s).str[3] == (c3)))
|
||||
// see https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding
|
||||
if(s.len < 2u)
|
||||
return false;
|
||||
else if(c4check3_(s, '\xef', '\xbb', '\xbf')) // UTF-8
|
||||
return 3u;
|
||||
else if(c4check4_(s, '\x00', '\x00', '\xfe', '\xff')) // UTF-32BE
|
||||
return 4u;
|
||||
else if(c4check4_(s, '\xff', '\xfe', '\x00', '\x00')) // UTF-32LE
|
||||
return 4u;
|
||||
else if(c4check2_(s, '\xfe', '\xff')) // UTF-16BE
|
||||
return 2u;
|
||||
else if(c4check2_(s, '\xff', '\xfe')) // UTF-16BE
|
||||
return 2u;
|
||||
else if(c4check3_(s, '\x2b', '\x2f', '\x76')) // UTF-7
|
||||
return 3u;
|
||||
else if(c4check3_(s, '\xf7', '\x64', '\x4c')) // UTF-1
|
||||
return 3u;
|
||||
else if(c4check4_(s, '\xdd', '\x73', '\x66', '\x73')) // UTF-EBCDIC
|
||||
return 4u;
|
||||
else if(c4check3_(s, '\x0e', '\xfe', '\xff')) // SCSU
|
||||
return 3u;
|
||||
else if(c4check3_(s, '\xfb', '\xee', '\x28')) // BOCU-1
|
||||
return 3u;
|
||||
else if(c4check4_(s, '\x84', '\x31', '\x95', '\x33')) // GB18030
|
||||
return 4u;
|
||||
return 0u;
|
||||
#undef c4check2_
|
||||
#undef c4check3_
|
||||
#undef c4check4_
|
||||
}
|
||||
|
||||
substr get_bom(substr s)
|
||||
{
|
||||
return s.first(first_non_bom(s));
|
||||
}
|
||||
csubstr get_bom(csubstr s)
|
||||
{
|
||||
return s.first(first_non_bom(s));
|
||||
}
|
||||
substr skip_bom(substr s)
|
||||
{
|
||||
return s.sub(first_non_bom(s));
|
||||
}
|
||||
csubstr skip_bom(csubstr s)
|
||||
{
|
||||
return s.sub(first_non_bom(s));
|
||||
}
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} // namespace c4
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
#include "c4/yml/common.hpp"
|
||||
|
||||
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
|
||||
# include <stdexcept>
|
||||
# endif
|
||||
#endif // RYML_NO_DEFAULT_CALLBACKS
|
||||
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702/*unreachable code*/) // on the call to the unreachable macro
|
||||
|
||||
namespace {
|
||||
Callbacks s_default_callbacks;
|
||||
} // anon namespace
|
||||
|
||||
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||
void report_error_impl(const char* msg, size_t length, Location loc, FILE *f)
|
||||
{
|
||||
if(!f)
|
||||
f = stderr;
|
||||
if(loc)
|
||||
{
|
||||
if(!loc.name.empty())
|
||||
{
|
||||
// this is more portable than using fprintf("%.*s:") which
|
||||
// is not available in some embedded platforms
|
||||
fwrite(loc.name.str, 1, loc.name.len, f); // NOLINT
|
||||
fputc(':', f); // NOLINT
|
||||
}
|
||||
fprintf(f, "%zu:", loc.line); // NOLINT
|
||||
if(loc.col)
|
||||
fprintf(f, "%zu:", loc.col); // NOLINT
|
||||
if(loc.offset)
|
||||
fprintf(f, " (%zuB):", loc.offset); // NOLINT
|
||||
fputc(' ', f); // NOLINT
|
||||
}
|
||||
RYML_ASSERT(!csubstr(msg, length).ends_with('\0'));
|
||||
fwrite(msg, 1, length, f); // NOLINT
|
||||
fputc('\n', f); // NOLINT
|
||||
fflush(f); // NOLINT
|
||||
}
|
||||
|
||||
[[noreturn]] void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
|
||||
{
|
||||
RYML_ASSERT(!csubstr(msg, length).ends_with('\0'));
|
||||
report_error_impl(msg, length, loc, nullptr);
|
||||
#ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
|
||||
throw std::runtime_error(std::string(msg, length));
|
||||
#else
|
||||
::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
|
||||
{
|
||||
void *mem = ::malloc(length);
|
||||
if(mem == nullptr)
|
||||
{
|
||||
const char msg[] = "could not allocate memory";
|
||||
error_impl(msg, sizeof(msg)-1, {}, nullptr);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
|
||||
{
|
||||
::free(mem);
|
||||
}
|
||||
#endif // RYML_NO_DEFAULT_CALLBACKS
|
||||
|
||||
|
||||
|
||||
Callbacks::Callbacks() noexcept
|
||||
:
|
||||
m_user_data(nullptr),
|
||||
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||
m_allocate(allocate_impl),
|
||||
m_free(free_impl),
|
||||
m_error(error_impl)
|
||||
#else
|
||||
m_allocate(nullptr),
|
||||
m_free(nullptr),
|
||||
m_error(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error error_)
|
||||
:
|
||||
m_user_data(user_data),
|
||||
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||
m_allocate(alloc_ ? alloc_ : allocate_impl),
|
||||
m_free(free_ ? free_ : free_impl),
|
||||
m_error((error_ ? error_ : error_impl))
|
||||
#else
|
||||
m_allocate(alloc_),
|
||||
m_free(free_),
|
||||
m_error(error_)
|
||||
#endif
|
||||
{
|
||||
RYML_CHECK(m_allocate);
|
||||
RYML_CHECK(m_free);
|
||||
RYML_CHECK(m_error);
|
||||
}
|
||||
|
||||
|
||||
void set_callbacks(Callbacks const& c)
|
||||
{
|
||||
s_default_callbacks = c;
|
||||
}
|
||||
|
||||
Callbacks const& get_callbacks()
|
||||
{
|
||||
return s_default_callbacks;
|
||||
}
|
||||
|
||||
void reset_callbacks()
|
||||
{
|
||||
set_callbacks(Callbacks());
|
||||
}
|
||||
|
||||
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
|
||||
// https://en.cppreference.com/w/cpp/language/attributes/noreturn
|
||||
[[noreturn]] void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc)
|
||||
{
|
||||
cb.m_error(msg, msg_len, loc, cb.m_user_data);
|
||||
abort(); // call abort in case the error callback didn't interrupt execution
|
||||
C4_UNREACHABLE();
|
||||
}
|
||||
|
||||
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
|
||||
// see https://en.cppreference.com/w/cpp/language/attributes/noreturn
|
||||
[[noreturn]] void error(const char *msg, size_t msg_len, Location loc)
|
||||
{
|
||||
error(s_default_callbacks, msg, msg_len, loc);
|
||||
C4_UNREACHABLE();
|
||||
}
|
||||
|
||||
C4_SUPPRESS_WARNING_MSVC_POP
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
#include "c4/yml/node.hpp"
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
size_t NodeRef::set_key_serialized(c4::fmt::const_base64_wrapper w)
|
||||
{
|
||||
_apply_seed();
|
||||
csubstr encoded = this->to_arena(w);
|
||||
this->set_key(encoded);
|
||||
return encoded.len;
|
||||
}
|
||||
|
||||
size_t NodeRef::set_val_serialized(c4::fmt::const_base64_wrapper w)
|
||||
{
|
||||
_apply_seed();
|
||||
csubstr encoded = this->to_arena(w);
|
||||
this->set_val(encoded);
|
||||
return encoded.len;
|
||||
}
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
-215
@@ -1,215 +0,0 @@
|
||||
#include "c4/yml/node_type.hpp"
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
const char* NodeType::type_str(NodeType_e ty) noexcept
|
||||
{
|
||||
switch(ty & _TYMASK)
|
||||
{
|
||||
case KEYVAL:
|
||||
return "KEYVAL";
|
||||
case KEY:
|
||||
return "KEY";
|
||||
case VAL:
|
||||
return "VAL";
|
||||
case MAP:
|
||||
return "MAP";
|
||||
case SEQ:
|
||||
return "SEQ";
|
||||
case KEYMAP:
|
||||
return "KEYMAP";
|
||||
case KEYSEQ:
|
||||
return "KEYSEQ";
|
||||
case DOCSEQ:
|
||||
return "DOCSEQ";
|
||||
case DOCMAP:
|
||||
return "DOCMAP";
|
||||
case DOCVAL:
|
||||
return "DOCVAL";
|
||||
case DOC:
|
||||
return "DOC";
|
||||
case STREAM:
|
||||
return "STREAM";
|
||||
case NOTYPE:
|
||||
return "NOTYPE";
|
||||
default:
|
||||
if((ty & KEYVAL) == KEYVAL)
|
||||
return "KEYVAL***";
|
||||
if((ty & KEYMAP) == KEYMAP)
|
||||
return "KEYMAP***";
|
||||
if((ty & KEYSEQ) == KEYSEQ)
|
||||
return "KEYSEQ***";
|
||||
if((ty & DOCSEQ) == DOCSEQ)
|
||||
return "DOCSEQ***";
|
||||
if((ty & DOCMAP) == DOCMAP)
|
||||
return "DOCMAP***";
|
||||
if((ty & DOCVAL) == DOCVAL)
|
||||
return "DOCVAL***";
|
||||
if(ty & KEY)
|
||||
return "KEY***";
|
||||
if(ty & VAL)
|
||||
return "VAL***";
|
||||
if(ty & MAP)
|
||||
return "MAP***";
|
||||
if(ty & SEQ)
|
||||
return "SEQ***";
|
||||
if(ty & DOC)
|
||||
return "DOC***";
|
||||
return "(unk)";
|
||||
}
|
||||
}
|
||||
|
||||
csubstr NodeType::type_str(substr buf, NodeType_e flags) noexcept
|
||||
{
|
||||
size_t pos = 0;
|
||||
bool gotone = false;
|
||||
|
||||
#define _prflag(fl, txt) \
|
||||
do { \
|
||||
if((flags & (fl)) == (fl)) \
|
||||
{ \
|
||||
if(gotone) \
|
||||
{ \
|
||||
if(pos + 1 < buf.len) \
|
||||
buf[pos] = '|'; \
|
||||
++pos; \
|
||||
} \
|
||||
csubstr fltxt = txt; \
|
||||
if(pos + fltxt.len <= buf.len) \
|
||||
memcpy(buf.str + pos, fltxt.str, fltxt.len); \
|
||||
pos += fltxt.len; \
|
||||
gotone = true; \
|
||||
flags = (flags & ~(fl)); /*remove the flag*/ \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
_prflag(STREAM, "STREAM");
|
||||
_prflag(DOC, "DOC");
|
||||
// key properties
|
||||
_prflag(KEY, "KEY");
|
||||
_prflag(KEYNIL, "KNIL");
|
||||
_prflag(KEYTAG, "KTAG");
|
||||
_prflag(KEYANCH, "KANCH");
|
||||
_prflag(KEYREF, "KREF");
|
||||
_prflag(KEY_LITERAL, "KLITERAL");
|
||||
_prflag(KEY_FOLDED, "KFOLDED");
|
||||
_prflag(KEY_SQUO, "KSQUO");
|
||||
_prflag(KEY_DQUO, "KDQUO");
|
||||
_prflag(KEY_PLAIN, "KPLAIN");
|
||||
_prflag(KEY_UNFILT, "KUNFILT");
|
||||
// val properties
|
||||
_prflag(VAL, "VAL");
|
||||
_prflag(VALNIL, "VNIL");
|
||||
_prflag(VALTAG, "VTAG");
|
||||
_prflag(VALANCH, "VANCH");
|
||||
_prflag(VALREF, "VREF");
|
||||
_prflag(VAL_UNFILT, "VUNFILT");
|
||||
_prflag(VAL_LITERAL, "VLITERAL");
|
||||
_prflag(VAL_FOLDED, "VFOLDED");
|
||||
_prflag(VAL_SQUO, "VSQUO");
|
||||
_prflag(VAL_DQUO, "VDQUO");
|
||||
_prflag(VAL_PLAIN, "VPLAIN");
|
||||
_prflag(VAL_UNFILT, "VUNFILT");
|
||||
// container properties
|
||||
_prflag(MAP, "MAP");
|
||||
_prflag(SEQ, "SEQ");
|
||||
_prflag(FLOW_SL, "FLOWSL");
|
||||
_prflag(FLOW_ML, "FLOWML");
|
||||
_prflag(BLOCK, "BLCK");
|
||||
if(pos == 0)
|
||||
_prflag(NOTYPE, "NOTYPE");
|
||||
|
||||
#undef _prflag
|
||||
|
||||
if(pos < buf.len)
|
||||
{
|
||||
buf[pos] = '\0';
|
||||
return buf.first(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
csubstr failed;
|
||||
failed.len = pos + 1;
|
||||
failed.str = nullptr;
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// see https://www.yaml.info/learn/quote.html#noplain
|
||||
bool scalar_style_query_squo(csubstr s) noexcept
|
||||
{
|
||||
return ! s.first_of_any("\n ", "\n\t");
|
||||
}
|
||||
|
||||
// see https://www.yaml.info/learn/quote.html#noplain
|
||||
bool scalar_style_query_plain(csubstr s) noexcept
|
||||
{
|
||||
if(s.begins_with("-."))
|
||||
{
|
||||
if(s == "-.inf" || s == "-.INF")
|
||||
return true;
|
||||
else if(s.sub(2).is_number())
|
||||
return true;
|
||||
}
|
||||
else if(s.begins_with_any("0123456789.-+") && s.is_number())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return s != ':'
|
||||
&& ( ! s.begins_with_any("-:?*&,'\"{}[]|>%#@`\r")) // @ and ` are reserved characters
|
||||
&& ( ! s.ends_with_any(":#"))
|
||||
// make this check in the last place, as it has linear
|
||||
// complexity, while the previous ones are
|
||||
// constant-time
|
||||
&& (s.first_of("\n#:[]{},") == npos);
|
||||
}
|
||||
|
||||
NodeType_e scalar_style_choose(csubstr s) noexcept
|
||||
{
|
||||
if(s.len)
|
||||
{
|
||||
if(s.begins_with_any(" \n\t")
|
||||
||
|
||||
s.ends_with_any(" \n\t"))
|
||||
{
|
||||
return SCALAR_DQUO;
|
||||
}
|
||||
else if( ! scalar_style_query_plain(s))
|
||||
{
|
||||
return scalar_style_query_squo(s) ? SCALAR_SQUO : SCALAR_DQUO;
|
||||
}
|
||||
// nothing remarkable - use plain
|
||||
return SCALAR_PLAIN;
|
||||
}
|
||||
return s.str ? SCALAR_SQUO : SCALAR_PLAIN;
|
||||
}
|
||||
|
||||
NodeType_e scalar_style_json_choose(csubstr s) noexcept
|
||||
{
|
||||
// do not quote special cases
|
||||
bool plain = (
|
||||
(s == "true" || s == "false" || s == "null")
|
||||
||
|
||||
(
|
||||
// do not quote numbers
|
||||
s.is_number()
|
||||
&&
|
||||
(
|
||||
// quote integral numbers if they have a leading 0
|
||||
// https://github.com/biojppm/rapidyaml/issues/291
|
||||
(!(s.len > 1 && s.begins_with('0')))
|
||||
// do not quote reals with leading 0
|
||||
// https://github.com/biojppm/rapidyaml/issues/313
|
||||
|| (s.find('.') != csubstr::npos)
|
||||
)
|
||||
)
|
||||
);
|
||||
return plain ? SCALAR_PLAIN : SCALAR_DQUO;
|
||||
}
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
#include "c4/yml/parse.hpp"
|
||||
|
||||
#ifndef _C4_YML_NODE_HPP_
|
||||
#include "c4/yml/node.hpp"
|
||||
#endif
|
||||
#ifndef _C4_YML_PARSE_ENGINE_HPP_
|
||||
#include "c4/yml/parse_engine.hpp"
|
||||
#endif
|
||||
#ifndef _C4_YML_PARSE_ENGINE_DEF_HPP_
|
||||
#include "c4/yml/parse_engine.def.hpp"
|
||||
#endif
|
||||
#ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
|
||||
#include "c4/yml/event_handler_tree.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
// instantiate the parser class
|
||||
template class ParseEngine<EventHandlerTree>;
|
||||
|
||||
namespace {
|
||||
inline void _reset_tree_handler(Parser *parser, Tree *t, id_type node_id)
|
||||
{
|
||||
RYML_ASSERT(parser);
|
||||
RYML_ASSERT(t);
|
||||
if(!parser->m_evt_handler)
|
||||
_RYML_CB_ERR(t->m_callbacks, "event handler is not set");
|
||||
parser->m_evt_handler->reset(t, node_id);
|
||||
RYML_ASSERT(parser->m_evt_handler->m_tree == t);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id)
|
||||
{
|
||||
_reset_tree_handler(parser, t, node_id);
|
||||
parser->parse_in_place_ev(filename, yaml);
|
||||
}
|
||||
|
||||
void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id)
|
||||
{
|
||||
_reset_tree_handler(parser, t, node_id);
|
||||
parser->parse_json_in_place_ev(filename, json);
|
||||
}
|
||||
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_in_place(Parser *parser, substr yaml, Tree *t, id_type node_id) { parse_in_place(parser, {}, yaml, t, node_id); }
|
||||
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t ) { RYML_CHECK(t); parse_in_place(parser, filename, yaml, t, t->root_id()); }
|
||||
void parse_in_place(Parser *parser, substr yaml, Tree *t ) { RYML_CHECK(t); parse_in_place(parser, {} , yaml, t, t->root_id()); }
|
||||
void parse_in_place(Parser *parser, csubstr filename, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_in_place(parser, filename, yaml, node.tree(), node.id()); }
|
||||
void parse_in_place(Parser *parser, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_in_place(parser, {} , yaml, node.tree(), node.id()); }
|
||||
Tree parse_in_place(Parser *parser, csubstr filename, substr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_in_place(parser, filename, yaml, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_in_place(Parser *parser, substr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_in_place(parser, {} , yaml, &tree, tree.root_id()); return tree; }
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_in_place(csubstr filename, substr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, t, node_id); }
|
||||
void parse_in_place( substr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, t, node_id); }
|
||||
void parse_in_place(csubstr filename, substr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, t, t->root_id()); }
|
||||
void parse_in_place( substr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, t, t->root_id()); }
|
||||
void parse_in_place(csubstr filename, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, node.tree(), node.id()); }
|
||||
void parse_in_place( substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, node.tree(), node.id()); }
|
||||
Tree parse_in_place(csubstr filename, substr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_in_place(&parser, filename, yaml, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_in_place( substr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_in_place(&parser, {} , yaml, &tree, tree.root_id()); return tree; }
|
||||
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_json_in_place(Parser *parser, substr json, Tree *t, id_type node_id) { parse_json_in_place(parser, {}, json, t, node_id); }
|
||||
void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t ) { RYML_CHECK(t); parse_json_in_place(parser, filename, json, t, t->root_id()); }
|
||||
void parse_json_in_place(Parser *parser, substr json, Tree *t ) { RYML_CHECK(t); parse_json_in_place(parser, {} , json, t, t->root_id()); }
|
||||
void parse_json_in_place(Parser *parser, csubstr filename, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_json_in_place(parser, filename, json, node.tree(), node.id()); }
|
||||
void parse_json_in_place(Parser *parser, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_json_in_place(parser, {} , json, node.tree(), node.id()); }
|
||||
Tree parse_json_in_place(Parser *parser, csubstr filename, substr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_json_in_place(parser, filename, json, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_json_in_place(Parser *parser, substr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_json_in_place(parser, {} , json, &tree, tree.root_id()); return tree; }
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_json_in_place(csubstr filename, substr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, t, node_id); }
|
||||
void parse_json_in_place( substr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, t, node_id); }
|
||||
void parse_json_in_place(csubstr filename, substr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, t, t->root_id()); }
|
||||
void parse_json_in_place( substr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, t, t->root_id()); }
|
||||
void parse_json_in_place(csubstr filename, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, node.tree(), node.id()); }
|
||||
void parse_json_in_place( substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, node.tree(), node.id()); }
|
||||
Tree parse_json_in_place(csubstr filename, substr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_json_in_place(&parser, filename, json, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_json_in_place( substr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_json_in_place(&parser, {} , json, &tree, tree.root_id()); return tree; }
|
||||
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, filename, src, t, node_id); }
|
||||
void parse_in_arena(Parser *parser, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, {} , src, t, node_id); }
|
||||
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, filename, src, t, t->root_id()); }
|
||||
void parse_in_arena(Parser *parser, csubstr yaml, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, {} , src, t, t->root_id()); }
|
||||
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(parser, filename, src, node.tree(), node.id()); }
|
||||
void parse_in_arena(Parser *parser, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(parser, {} , src, node.tree(), node.id()); }
|
||||
Tree parse_in_arena(Parser *parser, csubstr filename, csubstr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(parser, filename, src, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_in_arena(Parser *parser, csubstr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(parser, {} , src, &tree, tree.root_id()); return tree; }
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, filename, src, t, node_id); }
|
||||
void parse_in_arena( csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, {} , src, t, node_id); }
|
||||
void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, filename, src, t, t->root_id()); }
|
||||
void parse_in_arena( csubstr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, {} , src, t, t->root_id()); }
|
||||
void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(&parser, filename, src, node.tree(), node.id()); }
|
||||
void parse_in_arena( csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(&parser, {} , src, node.tree(), node.id()); }
|
||||
Tree parse_in_arena(csubstr filename, csubstr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(&parser, filename, src, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_in_arena( csubstr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(&parser, {} , src, &tree, tree.root_id()); return tree; }
|
||||
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, filename, src, t, node_id); }
|
||||
void parse_json_in_arena(Parser *parser, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, {} , src, t, node_id); }
|
||||
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, filename, src, t, t->root_id()); }
|
||||
void parse_json_in_arena(Parser *parser, csubstr json, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, {} , src, t, t->root_id()); }
|
||||
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(parser, filename, src, node.tree(), node.id()); }
|
||||
void parse_json_in_arena(Parser *parser, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(parser, {} , src, node.tree(), node.id()); }
|
||||
Tree parse_json_in_arena(Parser *parser, csubstr filename, csubstr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(parser, filename, src, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_json_in_arena(Parser *parser, csubstr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(parser, {} , src, &tree, tree.root_id()); return tree; }
|
||||
|
||||
// this is vertically aligned to highlight the parameter differences.
|
||||
void parse_json_in_arena(csubstr filename, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, filename, src, t, node_id); }
|
||||
void parse_json_in_arena( csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, {} , src, t, node_id); }
|
||||
void parse_json_in_arena(csubstr filename, csubstr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, filename, src, t, t->root_id()); }
|
||||
void parse_json_in_arena( csubstr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, {} , src, t, t->root_id()); }
|
||||
void parse_json_in_arena(csubstr filename, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(&parser, filename, src, node.tree(), node.id()); }
|
||||
void parse_json_in_arena( csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(&parser, {} , src, node.tree(), node.id()); }
|
||||
Tree parse_json_in_arena(csubstr filename, csubstr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(&parser, filename, src, &tree, tree.root_id()); return tree; }
|
||||
Tree parse_json_in_arena( csubstr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(&parser, {} , src, &tree, tree.root_id()); return tree; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
RYML_EXPORT id_type estimate_tree_capacity(csubstr src)
|
||||
{
|
||||
id_type num_nodes = 1; // root
|
||||
for(size_t i = 0; i < src.len; ++i)
|
||||
{
|
||||
const char c = src.str[i];
|
||||
num_nodes += (c == '\n') || (c == ',') || (c == '[') || (c == '{');
|
||||
}
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
#include "c4/yml/preprocess.hpp"
|
||||
#include "c4/yml/detail/dbgprint.hpp"
|
||||
|
||||
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
C4_ALWAYS_INLINE bool _is_idchar(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')
|
||||
|| (c == '_' || c == '-' || c == '~' || c == '$');
|
||||
}
|
||||
|
||||
enum _ppstate : int { kReadPending = 0, kKeyPending = 1, kValPending = 2 };
|
||||
C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
|
||||
{
|
||||
int n = (int)s + 1;
|
||||
return (_ppstate)(n <= (int)kValPending ? n : 0);
|
||||
}
|
||||
} // empty namespace
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
size_t preprocess_rxmap(csubstr s, substr buf)
|
||||
{
|
||||
detail::_SubstrWriter writer(buf);
|
||||
_ppstate state = kReadPending;
|
||||
size_t last = 0;
|
||||
|
||||
if(s.begins_with('{'))
|
||||
{
|
||||
RYML_CHECK(s.ends_with('}'));
|
||||
s = s.offs(1, 1);
|
||||
}
|
||||
|
||||
writer.append('{');
|
||||
|
||||
for(size_t i = 0; i < s.len; ++i)
|
||||
{
|
||||
const char curr = s[i];
|
||||
const char next = i+1 < s.len ? s[i+1] : '\0';
|
||||
|
||||
if(curr == '\'' || curr == '"')
|
||||
{
|
||||
csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
|
||||
i += static_cast<size_t>(ss.end() - (s.str + i));
|
||||
state = _next(state);
|
||||
}
|
||||
else if(state == kReadPending && _is_idchar(curr))
|
||||
{
|
||||
state = _next(state);
|
||||
}
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case kKeyPending:
|
||||
{
|
||||
if(curr == ':' && next == ' ')
|
||||
{
|
||||
state = _next(state);
|
||||
}
|
||||
else if(curr == ',' && next == ' ')
|
||||
{
|
||||
writer.append(s.range(last, i));
|
||||
writer.append(": 1, ");
|
||||
last = i + 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kValPending:
|
||||
{
|
||||
if(curr == '[' || curr == '{' || curr == '(')
|
||||
{
|
||||
csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
|
||||
i += static_cast<size_t>(ss.end() - (s.str + i));
|
||||
state = _next(state);
|
||||
}
|
||||
else if(curr == ',' && next == ' ')
|
||||
{
|
||||
state = _next(state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer.append(s.sub(last));
|
||||
if(state == kKeyPending)
|
||||
writer.append(": 1");
|
||||
writer.append('}');
|
||||
|
||||
return writer.pos;
|
||||
}
|
||||
|
||||
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
@@ -1,333 +0,0 @@
|
||||
#include "c4/yml/reference_resolver.hpp"
|
||||
#include "c4/yml/common.hpp"
|
||||
#include "c4/yml/detail/dbgprint.hpp"
|
||||
#ifdef RYML_DBG
|
||||
#include "c4/yml/detail/print.hpp"
|
||||
#else
|
||||
#define _c4dbg_tree(...)
|
||||
#define _c4dbg_node(...)
|
||||
#endif
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
/** @cond dev */
|
||||
|
||||
id_type ReferenceResolver::count_anchors_and_refs_(id_type n)
|
||||
{
|
||||
id_type c = 0;
|
||||
c += m_tree->has_key_anchor(n);
|
||||
c += m_tree->has_val_anchor(n);
|
||||
c += m_tree->is_key_ref(n);
|
||||
c += m_tree->is_val_ref(n);
|
||||
c += m_tree->has_key(n) && m_tree->key(n) == "<<";
|
||||
for(id_type ch = m_tree->first_child(n); ch != NONE; ch = m_tree->next_sibling(ch))
|
||||
c += count_anchors_and_refs_(ch);
|
||||
return c;
|
||||
}
|
||||
|
||||
void ReferenceResolver::gather_anchors_and_refs__(id_type n)
|
||||
{
|
||||
// insert key refs BEFORE inserting val refs
|
||||
if(m_tree->has_key(n))
|
||||
{
|
||||
if(!m_tree->is_key_quoted(n) && m_tree->key(n) == "<<")
|
||||
{
|
||||
_c4dbgpf("node[{}]: key is <<", n);
|
||||
if(m_tree->has_val(n))
|
||||
{
|
||||
if(m_tree->is_val_ref(n))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance[{}]: val ref, inheriting! '{}'", n, m_refs.size(), m_tree->val_ref(n));
|
||||
m_refs.push({VALREF, n, NONE, NONE, NONE, NONE});
|
||||
//m_refs.push({KEYREF, n, NONE, NONE, NONE, NONE});
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("node[{}]: not ref!", n);
|
||||
}
|
||||
}
|
||||
else if(m_tree->is_seq(n))
|
||||
{
|
||||
// for merging multiple inheritance targets
|
||||
// <<: [ *CENTER, *BIG ]
|
||||
_c4dbgpf("node[{}]: is seq!", n);
|
||||
for(id_type ich = m_tree->first_child(n); ich != NONE; ich = m_tree->next_sibling(ich))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance [{}]: val ref, inheriting multiple: {} '{}'", n, m_refs.size(), ich, m_tree->val_ref(ich));
|
||||
if(m_tree->is_container(ich))
|
||||
{
|
||||
detail::_report_err(m_tree->m_callbacks, "ERROR: node {} child {}: refs for << cannot be containers.'", n, ich);
|
||||
C4_UNREACHABLE_AFTER_ERR();
|
||||
}
|
||||
m_refs.push({VALREF, ich, NONE, NONE, n, m_tree->next_sibling(n)});
|
||||
}
|
||||
return; // don't descend into the seq
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::_report_err(m_tree->m_callbacks, "ERROR: node {}: refs for << must be either val or seq", n);
|
||||
C4_UNREACHABLE_AFTER_ERR();
|
||||
}
|
||||
}
|
||||
else if(m_tree->is_key_ref(n))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance[{}]: key ref: '{}', key='{}'", n, m_refs.size(), m_tree->key_ref(n), m_tree->has_key(n) ? m_tree->key(n) : csubstr{"-"});
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->key(n) != "<<");
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, (!m_tree->has_key(n)) || m_tree->key(n).ends_with(m_tree->key_ref(n)));
|
||||
m_refs.push({KEYREF, n, NONE, NONE, NONE, NONE});
|
||||
}
|
||||
}
|
||||
// val ref
|
||||
if(m_tree->is_val_ref(n) && (!m_tree->has_key(n) || m_tree->key(n) != "<<"))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance[{}]: val ref: '{}'", n, m_refs.size(), m_tree->val_ref(n));
|
||||
RYML_CHECK((!m_tree->has_val(n)) || m_tree->val(n).ends_with(m_tree->val_ref(n)));
|
||||
m_refs.push({VALREF, n, NONE, NONE, NONE, NONE});
|
||||
}
|
||||
// anchors
|
||||
if(m_tree->has_key_anchor(n))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance[{}]: key anchor: '{}'", n, m_refs.size(), m_tree->key_anchor(n));
|
||||
RYML_CHECK(m_tree->has_key(n));
|
||||
m_refs.push({KEYANCH, n, NONE, NONE, NONE, NONE});
|
||||
}
|
||||
if(m_tree->has_val_anchor(n))
|
||||
{
|
||||
_c4dbgpf("node[{}]: instance[{}]: val anchor: '{}'", n, m_refs.size(), m_tree->val_anchor(n));
|
||||
RYML_CHECK(m_tree->has_val(n) || m_tree->is_container(n));
|
||||
m_refs.push({VALANCH, n, NONE, NONE, NONE, NONE});
|
||||
}
|
||||
// recurse
|
||||
for(id_type ch = m_tree->first_child(n); ch != NONE; ch = m_tree->next_sibling(ch))
|
||||
gather_anchors_and_refs__(ch);
|
||||
}
|
||||
|
||||
void ReferenceResolver::gather_anchors_and_refs_()
|
||||
{
|
||||
_c4dbgp("gathering anchors and refs...");
|
||||
|
||||
// minimize (re-)allocations by counting first
|
||||
id_type num_anchors_and_refs = count_anchors_and_refs_(m_tree->root_id());
|
||||
if(!num_anchors_and_refs)
|
||||
return;
|
||||
m_refs.reserve(num_anchors_and_refs);
|
||||
m_refs.clear();
|
||||
|
||||
// now descend through the hierarchy
|
||||
gather_anchors_and_refs__(m_tree->root_id());
|
||||
|
||||
_c4dbgpf("found {} anchors/refs", m_refs.size());
|
||||
|
||||
// finally connect the reference list
|
||||
id_type prev_anchor = NONE;
|
||||
id_type count = 0;
|
||||
for(auto &rd : m_refs)
|
||||
{
|
||||
rd.prev_anchor = prev_anchor;
|
||||
if(rd.type.has_anchor())
|
||||
prev_anchor = count;
|
||||
++count;
|
||||
}
|
||||
_c4dbgp("gathering anchors and refs: finished");
|
||||
}
|
||||
|
||||
id_type ReferenceResolver::lookup_(RefData const* C4_RESTRICT ra)
|
||||
{
|
||||
#ifdef RYML_DBG
|
||||
id_type instance = static_cast<id_type>(ra-m_refs.m_stack);
|
||||
id_type node = ra->node;
|
||||
#endif
|
||||
RYML_ASSERT(ra->type.is_key_ref() || ra->type.is_val_ref());
|
||||
RYML_ASSERT(ra->type.is_key_ref() != ra->type.is_val_ref());
|
||||
csubstr refname;
|
||||
_c4dbgpf("instance[{}:node{}]: lookup from node={}...", instance, node, ra->node);
|
||||
if(ra->type.is_val_ref())
|
||||
{
|
||||
refname = m_tree->val_ref(ra->node);
|
||||
_c4dbgpf("instance[{}:node{}]: valref: '{}'", instance, node, refname);
|
||||
}
|
||||
else
|
||||
{
|
||||
RYML_ASSERT(ra->type.is_key_ref());
|
||||
refname = m_tree->key_ref(ra->node);
|
||||
_c4dbgpf("instance[{}:node{}]: keyref: '{}'", instance, node, refname);
|
||||
}
|
||||
while(ra->prev_anchor != NONE)
|
||||
{
|
||||
ra = &m_refs[ra->prev_anchor];
|
||||
_c4dbgpf("instance[{}:node{}]: lookup '{}' at [{}:node{}]: keyref='{}' valref='{}'", instance, node, refname, ra-m_refs.m_stack, ra->node,
|
||||
(m_tree->has_key_anchor(ra->node) ? m_tree->key_anchor(ra->node) : csubstr("~")),
|
||||
(m_tree->has_val_anchor(ra->node) ? m_tree->val_anchor(ra->node) : csubstr("~")));
|
||||
if(m_tree->has_anchor(ra->node, refname))
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}]: got it at [{}:node{}]!", instance, node, ra-m_refs.m_stack, ra->node);
|
||||
return ra->node;
|
||||
}
|
||||
}
|
||||
detail::_report_err(m_tree->m_callbacks, "ERROR: anchor not found: '{}'", refname);
|
||||
C4_UNREACHABLE_AFTER_ERR();
|
||||
}
|
||||
|
||||
void ReferenceResolver::reset_(Tree *t_)
|
||||
{
|
||||
if(t_->callbacks() != m_refs.m_callbacks)
|
||||
{
|
||||
m_refs.m_callbacks = t_->callbacks();
|
||||
}
|
||||
m_tree = t_;
|
||||
m_refs.clear();
|
||||
}
|
||||
|
||||
void ReferenceResolver::resolve_()
|
||||
{
|
||||
/* from the specs: "an alias node refers to the most recent
|
||||
* node in the serialization having the specified anchor". So
|
||||
* we need to start looking upward from ref nodes.
|
||||
*
|
||||
* @see http://yaml.org/spec/1.2/spec.html#id2765878 */
|
||||
_c4dbgp("matching anchors/refs...");
|
||||
for(id_type i = 0, e = m_refs.size(); i < e; ++i)
|
||||
{
|
||||
RefData &C4_RESTRICT refdata = m_refs.top(i);
|
||||
if( ! refdata.type.is_ref())
|
||||
continue;
|
||||
refdata.target = lookup_(&refdata);
|
||||
}
|
||||
_c4dbgp("matching anchors/refs: finished");
|
||||
|
||||
// insert the resolved references
|
||||
_c4dbgp("modifying tree...");
|
||||
id_type prev_parent_ref = NONE;
|
||||
id_type prev_parent_ref_after = NONE;
|
||||
for(id_type i = 0, e = m_refs.size(); i < e; ++i)
|
||||
{
|
||||
RefData const& C4_RESTRICT refdata = m_refs[i];
|
||||
_c4dbgpf("instance[{}:node{}]: {}/{}...", i, refdata.node, i+1, e);
|
||||
if( ! refdata.type.is_ref())
|
||||
continue;
|
||||
_c4dbgpf("instance[{}:node{}]: is reference!", i, refdata.node);
|
||||
if(refdata.parent_ref != NONE)
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] has parent: {}", i, refdata.node, refdata.parent_ref);
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref));
|
||||
const id_type p = m_tree->parent(refdata.parent_ref);
|
||||
const id_type after = (prev_parent_ref != refdata.parent_ref) ?
|
||||
refdata.parent_ref//prev_sibling(rd.parent_ref_sibling)
|
||||
:
|
||||
prev_parent_ref_after;
|
||||
prev_parent_ref = refdata.parent_ref;
|
||||
prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
|
||||
m_tree->remove(refdata.node);
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] has no parent", i, refdata.node, refdata.parent_ref);
|
||||
if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) == "<<")
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] is inheriting", i, refdata.node);
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_keyval(refdata.node));
|
||||
const id_type p = m_tree->parent(refdata.node);
|
||||
const id_type after = m_tree->prev_sibling(refdata.node);
|
||||
_c4dbgpf("instance[{}:node{}] p={} after={}", i, refdata.node, p, after);
|
||||
m_tree->duplicate_children_no_rep(refdata.target, p, after);
|
||||
m_tree->remove(refdata.node);
|
||||
}
|
||||
else if(refdata.type.is_key_ref())
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] is key ref", i, refdata.node);
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node));
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target));
|
||||
if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] target.anchor==val.anchor=={}", i, refdata.node, m_tree->val_anchor(refdata.target));
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
|
||||
const type_bits existing_style_flags = VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
|
||||
static_assert((VAL_STYLE >> 1u) == (KEY_STYLE), "bad flags");
|
||||
m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
|
||||
m_tree->_add_flags(refdata.node, KEY | (existing_style_flags >> 1u));
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] don't inherit container flags", i, refdata.node);
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
|
||||
m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
|
||||
// keys cannot be containers, so don't inherit container flags
|
||||
const type_bits existing_style_flags = KEY_STYLE & m_tree->_p(refdata.target)->m_type.type;
|
||||
m_tree->_add_flags(refdata.node, KEY | existing_style_flags);
|
||||
}
|
||||
}
|
||||
else // val ref
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] is val ref", i, refdata.node);
|
||||
_RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
|
||||
if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->key_anchor(refdata.target));
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
|
||||
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
|
||||
// keys cannot be containers, so don't inherit container flags
|
||||
const type_bits existing_style_flags = (KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
|
||||
static_assert((KEY_STYLE << 1u) == (VAL_STYLE), "bad flags");
|
||||
m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
|
||||
m_tree->_add_flags(refdata.node, VAL | (existing_style_flags << 1u));
|
||||
}
|
||||
else
|
||||
{
|
||||
_c4dbgpf("instance[{}:node{}] duplicate contents", i, refdata.node);
|
||||
m_tree->duplicate_contents(refdata.target, refdata.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
_c4dbg_tree("after insertion", *m_tree);
|
||||
}
|
||||
}
|
||||
|
||||
void ReferenceResolver::resolve(Tree *t_, bool clear_anchors)
|
||||
{
|
||||
_c4dbgp("resolving references...");
|
||||
|
||||
reset_(t_);
|
||||
|
||||
_c4dbg_tree("unresolved tree", *m_tree);
|
||||
|
||||
gather_anchors_and_refs_();
|
||||
if(m_refs.empty())
|
||||
return;
|
||||
resolve_();
|
||||
_c4dbg_tree("resolved tree", *m_tree);
|
||||
|
||||
// clear anchors and refs
|
||||
if(clear_anchors)
|
||||
{
|
||||
_c4dbgp("clearing anchors/refs");
|
||||
auto clear_ = [this]{
|
||||
for(auto const& C4_RESTRICT ar : m_refs)
|
||||
{
|
||||
m_tree->rem_anchor_ref(ar.node);
|
||||
if(ar.parent_ref != NONE)
|
||||
if(m_tree->type(ar.parent_ref) != NOTYPE)
|
||||
m_tree->remove(ar.parent_ref);
|
||||
}
|
||||
};
|
||||
clear_();
|
||||
// some of the elements injected during the resolution may
|
||||
// have nested anchors; these anchors will have been newly
|
||||
// injected during the resolution; collect again, and clear
|
||||
// again, to ensure those are also cleared:
|
||||
gather_anchors_and_refs_();
|
||||
clear_();
|
||||
_c4dbgp("clearing anchors/refs: finished");
|
||||
}
|
||||
|
||||
_c4dbg_tree("final resolved tree", *m_tree);
|
||||
|
||||
m_tree = nullptr;
|
||||
_c4dbgp("resolving references: finished");
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
} // namespace ryml
|
||||
} // namespace c4
|
||||
-316
@@ -1,316 +0,0 @@
|
||||
#include "c4/yml/tag.hpp"
|
||||
#include "c4/yml/detail/dbgprint.hpp"
|
||||
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
bool is_custom_tag(csubstr tag)
|
||||
{
|
||||
if((tag.len > 2) && (tag.str[0] == '!'))
|
||||
{
|
||||
size_t pos = tag.find('!', 1);
|
||||
return pos != npos && pos > 1 && tag.str[1] != '<';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
csubstr normalize_tag(csubstr tag)
|
||||
{
|
||||
YamlTag_e t = to_tag(tag);
|
||||
if(t != TAG_NONE)
|
||||
return from_tag(t);
|
||||
if(tag.begins_with("!<"))
|
||||
tag = tag.sub(1);
|
||||
if(tag.begins_with("<!"))
|
||||
return tag;
|
||||
return tag;
|
||||
}
|
||||
|
||||
csubstr normalize_tag_long(csubstr tag)
|
||||
{
|
||||
YamlTag_e t = to_tag(tag);
|
||||
if(t != TAG_NONE)
|
||||
return from_tag_long(t);
|
||||
if(tag.begins_with("!<"))
|
||||
tag = tag.sub(1);
|
||||
if(tag.begins_with("<!"))
|
||||
return tag;
|
||||
return tag;
|
||||
}
|
||||
|
||||
csubstr normalize_tag_long(csubstr tag, substr output)
|
||||
{
|
||||
csubstr result = normalize_tag_long(tag);
|
||||
if(result.begins_with("!!"))
|
||||
{
|
||||
tag = tag.sub(2);
|
||||
const csubstr pfx = "<tag:yaml.org,2002:";
|
||||
const size_t len = pfx.len + tag.len + 1;
|
||||
if(len <= output.len)
|
||||
{
|
||||
memcpy(output.str , pfx.str, pfx.len);
|
||||
memcpy(output.str + pfx.len, tag.str, tag.len);
|
||||
output[pfx.len + tag.len] = '>';
|
||||
result = output.first(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.str = nullptr;
|
||||
result.len = len;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
YamlTag_e to_tag(csubstr tag)
|
||||
{
|
||||
if(tag.begins_with("!<"))
|
||||
tag = tag.sub(1);
|
||||
if(tag.begins_with("!!"))
|
||||
tag = tag.sub(2);
|
||||
else if(tag.begins_with('!'))
|
||||
return TAG_NONE;
|
||||
else if(tag.begins_with("tag:yaml.org,2002:"))
|
||||
{
|
||||
RYML_ASSERT(csubstr("tag:yaml.org,2002:").len == 18);
|
||||
tag = tag.sub(18);
|
||||
}
|
||||
else if(tag.begins_with("<tag:yaml.org,2002:"))
|
||||
{
|
||||
RYML_ASSERT(csubstr("<tag:yaml.org,2002:").len == 19);
|
||||
tag = tag.sub(19);
|
||||
if(!tag.len)
|
||||
return TAG_NONE;
|
||||
tag = tag.offs(0, 1);
|
||||
}
|
||||
|
||||
if(tag == "map")
|
||||
return TAG_MAP;
|
||||
else if(tag == "omap")
|
||||
return TAG_OMAP;
|
||||
else if(tag == "pairs")
|
||||
return TAG_PAIRS;
|
||||
else if(tag == "set")
|
||||
return TAG_SET;
|
||||
else if(tag == "seq")
|
||||
return TAG_SEQ;
|
||||
else if(tag == "binary")
|
||||
return TAG_BINARY;
|
||||
else if(tag == "bool")
|
||||
return TAG_BOOL;
|
||||
else if(tag == "float")
|
||||
return TAG_FLOAT;
|
||||
else if(tag == "int")
|
||||
return TAG_INT;
|
||||
else if(tag == "merge")
|
||||
return TAG_MERGE;
|
||||
else if(tag == "null")
|
||||
return TAG_NULL;
|
||||
else if(tag == "str")
|
||||
return TAG_STR;
|
||||
else if(tag == "timestamp")
|
||||
return TAG_TIMESTAMP;
|
||||
else if(tag == "value")
|
||||
return TAG_VALUE;
|
||||
else if(tag == "yaml")
|
||||
return TAG_YAML;
|
||||
|
||||
return TAG_NONE;
|
||||
}
|
||||
|
||||
csubstr from_tag_long(YamlTag_e tag)
|
||||
{
|
||||
switch(tag)
|
||||
{
|
||||
case TAG_MAP:
|
||||
return {"<tag:yaml.org,2002:map>"};
|
||||
case TAG_OMAP:
|
||||
return {"<tag:yaml.org,2002:omap>"};
|
||||
case TAG_PAIRS:
|
||||
return {"<tag:yaml.org,2002:pairs>"};
|
||||
case TAG_SET:
|
||||
return {"<tag:yaml.org,2002:set>"};
|
||||
case TAG_SEQ:
|
||||
return {"<tag:yaml.org,2002:seq>"};
|
||||
case TAG_BINARY:
|
||||
return {"<tag:yaml.org,2002:binary>"};
|
||||
case TAG_BOOL:
|
||||
return {"<tag:yaml.org,2002:bool>"};
|
||||
case TAG_FLOAT:
|
||||
return {"<tag:yaml.org,2002:float>"};
|
||||
case TAG_INT:
|
||||
return {"<tag:yaml.org,2002:int>"};
|
||||
case TAG_MERGE:
|
||||
return {"<tag:yaml.org,2002:merge>"};
|
||||
case TAG_NULL:
|
||||
return {"<tag:yaml.org,2002:null>"};
|
||||
case TAG_STR:
|
||||
return {"<tag:yaml.org,2002:str>"};
|
||||
case TAG_TIMESTAMP:
|
||||
return {"<tag:yaml.org,2002:timestamp>"};
|
||||
case TAG_VALUE:
|
||||
return {"<tag:yaml.org,2002:value>"};
|
||||
case TAG_YAML:
|
||||
return {"<tag:yaml.org,2002:yaml>"};
|
||||
case TAG_NONE:
|
||||
default:
|
||||
return {""};
|
||||
}
|
||||
}
|
||||
|
||||
csubstr from_tag(YamlTag_e tag)
|
||||
{
|
||||
switch(tag)
|
||||
{
|
||||
case TAG_MAP:
|
||||
return {"!!map"};
|
||||
case TAG_OMAP:
|
||||
return {"!!omap"};
|
||||
case TAG_PAIRS:
|
||||
return {"!!pairs"};
|
||||
case TAG_SET:
|
||||
return {"!!set"};
|
||||
case TAG_SEQ:
|
||||
return {"!!seq"};
|
||||
case TAG_BINARY:
|
||||
return {"!!binary"};
|
||||
case TAG_BOOL:
|
||||
return {"!!bool"};
|
||||
case TAG_FLOAT:
|
||||
return {"!!float"};
|
||||
case TAG_INT:
|
||||
return {"!!int"};
|
||||
case TAG_MERGE:
|
||||
return {"!!merge"};
|
||||
case TAG_NULL:
|
||||
return {"!!null"};
|
||||
case TAG_STR:
|
||||
return {"!!str"};
|
||||
case TAG_TIMESTAMP:
|
||||
return {"!!timestamp"};
|
||||
case TAG_VALUE:
|
||||
return {"!!value"};
|
||||
case TAG_YAML:
|
||||
return {"!!yaml"};
|
||||
case TAG_NONE:
|
||||
default:
|
||||
return {""};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TagDirective::create_from_str(csubstr directive_)
|
||||
{
|
||||
csubstr directive = directive_;
|
||||
directive = directive.sub(4);
|
||||
if(!directive.begins_with(' '))
|
||||
return false;
|
||||
directive = directive.triml(' ');
|
||||
size_t pos = directive.find(' ');
|
||||
if(pos == npos)
|
||||
return false;
|
||||
handle = directive.first(pos);
|
||||
directive = directive.sub(handle.len).triml(' ');
|
||||
pos = directive.find(' ');
|
||||
if(pos != npos)
|
||||
directive = directive.first(pos);
|
||||
prefix = directive;
|
||||
next_node_id = NONE;
|
||||
_c4dbgpf("%TAG: handle={} prefix={}", handle, prefix);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets) const
|
||||
{
|
||||
_c4dbgpf("%TAG: handle={} prefix={} next_node={}. tag={}", handle, prefix, next_node_id, tag);
|
||||
_RYML_CB_ASSERT(callbacks, tag.len >= handle.len);
|
||||
csubstr rest = tag.sub(handle.len);
|
||||
_c4dbgpf("%TAG: rest={}", rest);
|
||||
if(rest.begins_with('<'))
|
||||
{
|
||||
_c4dbgpf("%TAG: begins with <. rest={}", rest);
|
||||
if(C4_UNLIKELY(!rest.ends_with('>')))
|
||||
_RYML_CB_ERR(callbacks, "malformed tag");
|
||||
rest = rest.offs(1, 1);
|
||||
if(rest.begins_with(prefix))
|
||||
{
|
||||
_c4dbgpf("%TAG: already transformed! actual={}", rest.sub(prefix.len));
|
||||
return 0; // return 0 to signal that the tag is local and cannot be resolved
|
||||
}
|
||||
}
|
||||
size_t len = prefix.len + rest.len;
|
||||
if(with_brackets)
|
||||
len += 2;
|
||||
size_t numpc = rest.count('%');
|
||||
if(numpc == 0)
|
||||
{
|
||||
if(len <= output.len)
|
||||
{
|
||||
if(with_brackets)
|
||||
{
|
||||
output.str[0] = '<';
|
||||
memcpy(1u + output.str, prefix.str, prefix.len);
|
||||
memcpy(1u + output.str + prefix.len, rest.str, rest.len);
|
||||
output.str[1u + prefix.len + rest.len] = '>';
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(output.str, prefix.str, prefix.len);
|
||||
memcpy(output.str + prefix.len, rest.str, rest.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to decode URI % sequences
|
||||
size_t pos = rest.find('%');
|
||||
_RYML_CB_ASSERT(callbacks, pos != npos);
|
||||
do {
|
||||
size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
|
||||
if(next == npos)
|
||||
next = rest.len;
|
||||
_RYML_CB_CHECK(callbacks, pos+1 < next);
|
||||
_RYML_CB_CHECK(callbacks, pos+1 + 2 <= next);
|
||||
size_t delta = next - (pos+1);
|
||||
len -= delta;
|
||||
pos = rest.find('%', pos+1);
|
||||
} while(pos != npos);
|
||||
if(len <= output.len)
|
||||
{
|
||||
size_t prev = 0, wpos = 0;
|
||||
auto appendstr = [&](csubstr s) { memcpy(output.str + wpos, s.str, s.len); wpos += s.len; };
|
||||
auto appendchar = [&](char c) { output.str[wpos++] = c; };
|
||||
if(with_brackets)
|
||||
appendchar('<');
|
||||
appendstr(prefix);
|
||||
pos = rest.find('%');
|
||||
_RYML_CB_ASSERT(callbacks, pos != npos);
|
||||
do {
|
||||
size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
|
||||
if(next == npos)
|
||||
next = rest.len;
|
||||
_RYML_CB_CHECK(callbacks, pos+1 < next);
|
||||
_RYML_CB_CHECK(callbacks, pos+1 + 2 <= next);
|
||||
uint8_t val;
|
||||
if(C4_UNLIKELY(!read_hex(rest.range(pos+1, next), &val) || val > 127))
|
||||
_RYML_CB_ERR(callbacks, "invalid URI character");
|
||||
appendstr(rest.range(prev, pos));
|
||||
appendchar(static_cast<char>(val));
|
||||
prev = next;
|
||||
pos = rest.find('%', pos+1);
|
||||
} while(pos != npos);
|
||||
_RYML_CB_ASSERT(callbacks, pos == npos);
|
||||
_RYML_CB_ASSERT(callbacks, prev > 0);
|
||||
_RYML_CB_ASSERT(callbacks, rest.len >= prev);
|
||||
appendstr(rest.sub(prev));
|
||||
if(with_brackets)
|
||||
appendchar('>');
|
||||
_RYML_CB_ASSERT(callbacks, wpos == len);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
-1978
File diff suppressed because it is too large
Load Diff
-27
@@ -1,27 +0,0 @@
|
||||
#include "c4/yml/version.hpp"
|
||||
|
||||
namespace c4 {
|
||||
namespace yml {
|
||||
|
||||
csubstr version()
|
||||
{
|
||||
return RYML_VERSION;
|
||||
}
|
||||
|
||||
int version_major()
|
||||
{
|
||||
return RYML_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
int version_minor()
|
||||
{
|
||||
return RYML_VERSION_MINOR;
|
||||
}
|
||||
|
||||
int version_patch()
|
||||
{
|
||||
return RYML_VERSION_PATCH;
|
||||
}
|
||||
|
||||
} // namespace yml
|
||||
} // namespace c4
|
||||
@@ -25,8 +25,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "3rdparty\simpl
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "3rdparty\cubeb\cubeb.vcxproj", "{BF74C473-DC04-44B3-92E8-4145F4E77342}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rapidyaml", "3rdparty\rapidyaml\rapidyaml.vcxproj", "{DE9653B6-17DD-356A-9EE0-28A731772587}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzip", "3rdparty\libzip\libzip.vcxproj", "{20B2E9FE-F020-42A0-B324-956F5B06EA68}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d12memalloc", "3rdparty\d3d12memalloc\d3d12memalloc.vcxproj", "{D45CEC7A-3171-40DD-975D-E1544CF16139}"
|
||||
@@ -473,45 +471,6 @@ Global
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|ARM64.ActiveCfg = Release Clang|ARM64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.ActiveCfg = Release|x64
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.Build.0 = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|ARM64.ActiveCfg = Debug Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang AVX2|ARM64.ActiveCfg = Debug Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang AVX2|x64.ActiveCfg = Debug Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang AVX2|x64.Build.0 = Debug Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang|ARM64.ActiveCfg = Debug Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang|ARM64.Build.0 = Debug Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang|x64.ActiveCfg = Debug Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug Clang|x64.Build.0 = Debug Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|ARM64.ActiveCfg = Debug Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.Build.0 = Debug|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|ARM64.ActiveCfg = Devel Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang AVX2|ARM64.ActiveCfg = Devel Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang AVX2|x64.ActiveCfg = Devel Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang AVX2|x64.Build.0 = Devel Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang|ARM64.ActiveCfg = Devel Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang|ARM64.Build.0 = Devel Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang|x64.ActiveCfg = Devel Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel Clang|x64.Build.0 = Devel Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|ARM64.ActiveCfg = Devel Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.Build.0 = Devel|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|ARM64.ActiveCfg = Release Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.Build.0 = Release AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang AVX2|ARM64.ActiveCfg = Release Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang AVX2|x64.ActiveCfg = Release Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang AVX2|x64.Build.0 = Release Clang AVX2|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang|ARM64.ActiveCfg = Release Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang|ARM64.Build.0 = Release Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang|x64.ActiveCfg = Release Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release Clang|x64.Build.0 = Release Clang|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|ARM64.ActiveCfg = Release Clang|ARM64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.ActiveCfg = Release|x64
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.Build.0 = Release|x64
|
||||
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|ARM64.ActiveCfg = Debug Clang|ARM64
|
||||
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
|
||||
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
|
||||
@@ -1040,7 +999,6 @@ Global
|
||||
{88FB34EC-845E-4F21-A552-F1573B9ED167} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{BF74C473-DC04-44B3-92E8-4145F4E77342} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{DE9653B6-17DD-356A-9EE0-28A731772587} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{20B2E9FE-F020-42A0-B324-956F5B06EA68} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{D45CEC7A-3171-40DD-975D-E1544CF16139} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{A4323327-3F2B-4271-83D9-7F9A3C66B6B2} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
|
||||
@@ -21,6 +21,7 @@ find_package(SDL3 3.2.6 REQUIRED)
|
||||
find_package(Freetype 2.12 REQUIRED)
|
||||
find_package(plutovg 1.1.0 REQUIRED)
|
||||
find_package(plutosvg 0.0.7 REQUIRED)
|
||||
find_package(ryml REQUIRED)
|
||||
|
||||
if(USE_VULKAN)
|
||||
find_package(Shaderc REQUIRED)
|
||||
@@ -80,7 +81,6 @@ endif()
|
||||
set(CMAKE_FIND_FRAMEWORK ${FIND_FRAMEWORK_BACKUP})
|
||||
|
||||
add_subdirectory(3rdparty/fast_float EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/rapidyaml EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/lzma EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libchdr EXCLUDE_FROM_ALL)
|
||||
disable_compiler_warnings_for_target(libchdr)
|
||||
|
||||
@@ -211,7 +211,7 @@ target_link_libraries(common PRIVATE
|
||||
target_link_libraries(common PUBLIC
|
||||
fmt::fmt
|
||||
fast_float
|
||||
rapidyaml::rapidyaml
|
||||
ryml::ryml
|
||||
)
|
||||
|
||||
fixup_file_properties(common)
|
||||
|
||||
+46
-1
@@ -3,8 +3,11 @@
|
||||
|
||||
#include "YAML.h"
|
||||
|
||||
#include "Assertions.h"
|
||||
|
||||
#include "c4/yml/error.def.hpp" // for ryml::err_basic_format etc
|
||||
|
||||
#include <csetjmp>
|
||||
#include <cstdlib>
|
||||
|
||||
struct RapidYAMLContext
|
||||
{
|
||||
@@ -18,6 +21,47 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
|
||||
context.error = error;
|
||||
|
||||
ryml::Callbacks callbacks;
|
||||
|
||||
#if RYML_VERSION_MAJOR > 0 || RYML_VERSION_MINOR >= 11
|
||||
callbacks.set_user_data(static_cast<void*>(&context));
|
||||
|
||||
callbacks.set_error_basic([](ryml::csubstr msg, const ryml::ErrorDataBasic& errdata, void* user_data) {
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_basic_format(std::move(callback), msg, errdata);
|
||||
|
||||
// We might have already returned, so don't try to recover.
|
||||
pxFailRel(description.c_str());
|
||||
std::abort();
|
||||
});
|
||||
|
||||
callbacks.set_error_parse([](ryml::csubstr msg, const ryml::ErrorDataParse& errdata, void* user_data) {
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_parse_format(std::move(callback), msg, errdata);
|
||||
|
||||
Error::SetString(context->error, std::move(description));
|
||||
std::longjmp(context->env, 1);
|
||||
});
|
||||
|
||||
callbacks.set_error_visit([](ryml::csubstr msg, const ryml::ErrorDataVisit& errdata, void* user_data) {
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_visit_format(std::move(callback), msg, errdata);
|
||||
|
||||
// We've probably already returned, so don't try to recover.
|
||||
pxFailRel(description.c_str());
|
||||
std::abort();
|
||||
});
|
||||
#else
|
||||
callbacks.m_user_data = static_cast<void*>(&context);
|
||||
callbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location location, void* user_data) {
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
@@ -25,6 +69,7 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
|
||||
Error::SetString(context->error, std::string(msg, msg_len));
|
||||
std::longjmp(context->env, 1);
|
||||
};
|
||||
#endif
|
||||
|
||||
ryml::EventHandlerTree event_handler(callbacks);
|
||||
ryml::Parser parser(&event_handler);
|
||||
|
||||
+1
-2
@@ -5,9 +5,8 @@
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
#include "ryml.hpp"
|
||||
#include "ryml_std.hpp"
|
||||
#include "ryml.hpp"
|
||||
#include "ryml.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<ForcedIncludeFiles>PrecompiledHeader.h</ForcedIncludeFiles>
|
||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(DepsLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib;ryml.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies Condition="$(Configuration.Contains(Debug))">%(AdditionalDependencies);kddockwidgets-qt6d.lib;</AdditionalDependencies>
|
||||
<AdditionalDependencies Condition="!$(Configuration.Contains(Debug))">%(AdditionalDependencies);kddockwidgets-qt6.lib;</AdditionalDependencies>
|
||||
</Link>
|
||||
@@ -27,6 +27,7 @@
|
||||
<DepsDLLs Condition="!$(Configuration.Contains(Debug))" Include="$(DepsBinDir)kddockwidgets-qt6.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)plutovg.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)plutosvg.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)ryml.dll" />
|
||||
<DepsDLLs Condition="Exists('$(DepsBinDir)avcodec-62.dll')" Include="$(DepsBinDir)avcodec-62.dll" />
|
||||
<DepsDLLs Condition="Exists('$(DepsBinDir)avformat-62.dll')" Include="$(DepsBinDir)avformat-62.dll" />
|
||||
<DepsDLLs Condition="Exists('$(DepsBinDir)avutil-60.dll')" Include="$(DepsBinDir)avutil-60.dll" />
|
||||
|
||||
@@ -1310,7 +1310,7 @@ function(setup_main_executable target)
|
||||
|
||||
# Copy dependency libraries.
|
||||
set(DEPS_BINDIR "${CMAKE_SOURCE_DIR}/deps/bin")
|
||||
set(DEPS_TO_COPY freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll libsharpyuv.dll libwebp.dll libwebpdemux.dll libwebpmux.dll lz4.dll SDL3.dll shaderc_shared.dll z.dll zstd.dll plutovg.dll plutosvg.dll)
|
||||
set(DEPS_TO_COPY freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll libsharpyuv.dll libwebp.dll libwebpdemux.dll libwebpmux.dll lz4.dll SDL3.dll shaderc_shared.dll z.dll zstd.dll plutovg.dll plutosvg.dll ryml.dll)
|
||||
set(DEPS_TO_COPY
|
||||
$<IF:$<CONFIG:Debug>,kddockwidgets-qt6d.dll,kddockwidgets-qt6.dll>
|
||||
${DEPS_TO_COPY}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "common/YAML.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "ryml_std.hpp"
|
||||
#include "ryml.hpp"
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include <fstream>
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\simpleini\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libzip\msvc;$(SolutionDir)3rdparty\libzip\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\cpuinfo\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rcheevos\include;$(SolutionDir)3rdparty\rainterface</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\soundtouch\soundtouch</AdditionalIncludeDirectories>
|
||||
@@ -983,9 +982,6 @@
|
||||
<ProjectReference Include="$(SolutionDir)3rdparty\cubeb\cubeb.vcxproj">
|
||||
<Project>{bf74c473-dc04-44b3-92e8-4145f4e77342}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)3rdparty\rapidyaml\rapidyaml.vcxproj">
|
||||
<Project>{de9653b6-17dd-356a-9ee0-28a731772587}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
|
||||
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
Reference in New Issue
Block a user