diff --git a/.github/workflows/scripts/linux/build-dependencies-qt.sh b/.github/workflows/scripts/linux/build-dependencies-qt.sh index c94d517610..7b37f27566 100755 --- a/.github/workflows/scripts/linux/build-dependencies-qt.sh +++ b/.github/workflows/scripts/linux/build-dependencies-qt.sh @@ -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" diff --git a/.github/workflows/scripts/linux/build-dependencies-runner.sh b/.github/workflows/scripts/linux/build-dependencies-runner.sh index 5a7080a8fb..8bc05470ed 100755 --- a/.github/workflows/scripts/linux/build-dependencies-runner.sh +++ b/.github/workflows/scripts/linux/build-dependencies-runner.sh @@ -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" diff --git a/.github/workflows/scripts/linux/flatpak/modules/28-rapidyaml.json b/.github/workflows/scripts/linux/flatpak/modules/28-rapidyaml.json new file mode 100644 index 0000000000..2e24cdde6a --- /dev/null +++ b/.github/workflows/scripts/linux/flatpak/modules/28-rapidyaml.json @@ -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" + ] +} diff --git a/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json b/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json index 75545dc50b..729766901a 100644 --- a/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json +++ b/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json @@ -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 @@ } ] } - diff --git a/.github/workflows/scripts/macos/build-dependencies-universal.sh b/.github/workflows/scripts/macos/build-dependencies-universal.sh index fe7b9f0867..a74564b673 100755 --- a/.github/workflows/scripts/macos/build-dependencies-universal.sh +++ b/.github/workflows/scripts/macos/build-dependencies-universal.sh @@ -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 diff --git a/.github/workflows/scripts/macos/build-dependencies.sh b/.github/workflows/scripts/macos/build-dependencies.sh index f4f06d3c7a..648cb053c4 100755 --- a/.github/workflows/scripts/macos/build-dependencies.sh +++ b/.github/workflows/scripts/macos/build-dependencies.sh @@ -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 diff --git a/.github/workflows/scripts/windows/build-dependencies-arm64.bat b/.github/workflows/scripts/windows/build-dependencies-arm64.bat index 573816f5e3..1d38378e95 100644 --- a/.github/workflows/scripts/windows/build-dependencies-arm64.bat +++ b/.github/workflows/scripts/windows/build-dependencies-arm64.bat @@ -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 diff --git a/.github/workflows/scripts/windows/build-dependencies.bat b/.github/workflows/scripts/windows/build-dependencies.bat index e402e85b47..250e7edb59 100644 --- a/.github/workflows/scripts/windows/build-dependencies.bat +++ b/.github/workflows/scripts/windows/build-dependencies.bat @@ -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 diff --git a/3rdparty/rapidyaml/CMakeLists.txt b/3rdparty/rapidyaml/CMakeLists.txt deleted file mode 100644 index b2375d8cf8..0000000000 --- a/3rdparty/rapidyaml/CMakeLists.txt +++ /dev/null @@ -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) diff --git a/3rdparty/rapidyaml/include/c4/base64.hpp b/3rdparty/rapidyaml/include/c4/base64.hpp deleted file mode 100644 index 4456c0ce83..0000000000 --- a/3rdparty/rapidyaml/include/c4/base64.hpp +++ /dev/null @@ -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 -struct base64_wrapper_ -{ - blob_ data; - base64_wrapper_() : data() {} - base64_wrapper_(blob_ blob) : data(blob) {} -}; -/** a tag type to mark a payload as base64-encoded */ -using const_base64_wrapper = base64_wrapper_; -/** a tag type to mark a payload to be encoded as base64 */ -using base64_wrapper = base64_wrapper_; - - -/** mark a variable to be written in base64 format */ -template -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 -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 -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/blob.hpp b/3rdparty/rapidyaml/include/c4/blob.hpp deleted file mode 100644 index be241f2f4a..0000000000 --- a/3rdparty/rapidyaml/include/c4/blob.hpp +++ /dev/null @@ -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 -struct blob_; - -namespace detail { -template struct is_blob_type : std::integral_constant {}; -template struct is_blob_type> : std::integral_constant {}; -template struct is_blob_value_type : std::integral_constant::value || std::is_trivially_copyable::value)> {}; -} // namespace - -// NOLINTBEGIN(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) - -template -struct blob_ -{ - static_assert(std::is_same::value || std::is_same::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::value && std::is_same::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_ const& that) noexcept : buf(that.buf), len(that.len) {} // NOLINT - template::value && std::is_same::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_ && that) noexcept : buf(that.buf), len(that.len) {} // NOLINT - template::value && std::is_same::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_ && that) noexcept { buf = that.buf; len = that.len; } // NOLINT - template::value && std::is_same::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_ const& that) noexcept { buf = that.buf; len = that.len; } // NOLINT - - C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast(ptr)), len(n) {} // NOLINT - C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast(ptr)), len(n) {} // NOLINT - - #define _C4_REQUIRE_BLOBTYPE(ty) class=typename std::enable_if<((!detail::is_blob_type::value) && (detail::is_blob_value_type::value)), T>::type - template C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast(&var)), len(sizeof(U)) {} // NOLINT - template C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); } // NOLINT - template C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast(&var); len = sizeof(U); return *this; } // NOLINT - template C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast(arr)), len(sizeof(U) * N) {} // NOLINT - template C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast(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_; -/** 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_ diff --git a/3rdparty/rapidyaml/include/c4/c4core.natvis b/3rdparty/rapidyaml/include/c4/c4core.natvis deleted file mode 100644 index 7cd138fe66..0000000000 --- a/3rdparty/rapidyaml/include/c4/c4core.natvis +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - {str,[len]} (sz={len}) - str,[len] - - len - - len - str - - - - - - {m_ptr,[m_size]} (sz={m_size}) - - m_size - - m_size - m_ptr - - - - - {m_ptr,[m_size]} (sz={m_size}, cap={m_capacity}) - - m_size - m_capacity - - m_size - m_ptr - - - - - - {m_ptr,[m_size]} (sz={m_size}) - m_ptr,[m_size] - - m_size - - m_size - m_ptr - - - - - {m_ptr,[m_size]} (sz={m_size}) - m_ptr,[m_size] - - m_size - - m_size - m_ptr - - - - - - {m_ptr,[m_size]} (sz={m_size}, cap={m_capacity}) - m_ptr,[m_size] - - m_size - m_capacity - - m_size - m_ptr - - - - - {m_ptr,[m_size]} (sz={m_size}, cap={m_capacity}) - m_ptr,[m_size] - - m_size - m_capacity - - m_size - m_ptr - - - - - - - {(($T3*)this)->m_str,[(($T3*)this)->m_size]} (sz={(($T3*)this)->m_size}) - (($T3*)this)->m_str,[(($T3*)this)->m_size] - - - {(($T3*)this)->m_str,[(($T3*)this)->m_size]} - (($T3*)this)->m_str,[(($T3*)this)->m_size] - - - {(($T3*)this)->m_size} - - - - - {m_str,[m_size]} (sz={m_size}) - m_str,[m_size] - - - {m_size} - - - - - {m_str,[m_size]} (sz={m_size},cap={m_capacity}) - m_str,[m_size] - - - {m_size} - - - {m_capacity} - - - {m_str,[m_capacity]} - m_str,[m_capacity] - - - - - {m_str,[m_size]} (sz={m_size},cap={m_capacity}) - m_str,[m_size] - - - {m_size} - - - {m_str,[m_capacity]} - m_str,[m_capacity] - - - - - - - {value} - {name} - - value - name - - - - {m_symbols,[m_num]} (sz={m_num}) - - m_num - - m_num - m_symbols - - - - - diff --git a/3rdparty/rapidyaml/include/c4/charconv.hpp b/3rdparty/rapidyaml/include/c4/charconv.hpp deleted file mode 100644 index d43bd17126..0000000000 --- a/3rdparty/rapidyaml/include/c4/charconv.hpp +++ /dev/null @@ -1,2670 +0,0 @@ -#ifndef _C4_CHARCONV_HPP_ -#define _C4_CHARCONV_HPP_ - -/** @file charconv.hpp Lightweight generic type-safe wrappers for - * converting individual values to/from strings. - */ - -#include "c4/language.hpp" -#include -#include -#include -#include -#include - -#include "c4/config.hpp" -#include "c4/substr.hpp" -#include "c4/std/std_fwd.hpp" -#include "c4/memory_util.hpp" -#include "c4/szconv.hpp" - -#ifndef C4CORE_NO_FAST_FLOAT -# if (C4_CPP >= 17) -# if defined(_MSC_VER) -# if (C4_MSVC_VERSION >= C4_MSVC_VERSION_2019) // VS2017 and lower do not have these macros -# include -# define C4CORE_HAVE_STD_TOCHARS 1 -# define C4CORE_HAVE_STD_FROMCHARS 0 // prefer fast_float with MSVC -# define C4CORE_HAVE_FAST_FLOAT 1 -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# define C4CORE_HAVE_FAST_FLOAT 1 -# endif -# else -# if __has_include() -# include -# if defined(__cpp_lib_to_chars) -# define C4CORE_HAVE_STD_TOCHARS 1 -# define C4CORE_HAVE_STD_FROMCHARS 0 // glibc uses fast_float internally -# define C4CORE_HAVE_FAST_FLOAT 1 -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# define C4CORE_HAVE_FAST_FLOAT 1 -# endif -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# define C4CORE_HAVE_FAST_FLOAT 1 -# endif -# endif -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# define C4CORE_HAVE_FAST_FLOAT 1 -# endif -# if C4CORE_HAVE_FAST_FLOAT -#include "fast_float/fast_float.h" -# endif -#elif (C4_CPP >= 17) -# define C4CORE_HAVE_FAST_FLOAT 0 -# if defined(_MSC_VER) -# if (C4_MSVC_VERSION >= C4_MSVC_VERSION_2019) // VS2017 and lower do not have these macros -# include -# define C4CORE_HAVE_STD_TOCHARS 1 -# define C4CORE_HAVE_STD_FROMCHARS 1 -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# endif -# else -# if __has_include() -# include -# if defined(__cpp_lib_to_chars) -# define C4CORE_HAVE_STD_TOCHARS 1 -# define C4CORE_HAVE_STD_FROMCHARS 1 // glibc uses fast_float internally -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# endif -# else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# endif -# endif -#else -# define C4CORE_HAVE_STD_TOCHARS 0 -# define C4CORE_HAVE_STD_FROMCHARS 0 -# define C4CORE_HAVE_FAST_FLOAT 0 -#endif - - -#if !C4CORE_HAVE_STD_FROMCHARS -#include -#endif - - -#if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(push) -# pragma warning(disable: 4996) // snprintf/scanf: this function or variable may be unsafe -# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017 -# pragma warning(disable: 4800) //'int': forcing value to bool 'true' or 'false' (performance warning) -# endif -#elif defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" -# pragma clang diagnostic ignored "-Wformat-nonliteral" -# pragma clang diagnostic ignored "-Wdouble-promotion" // implicit conversion increases floating-point precision -# pragma clang diagnostic ignored "-Wold-style-cast" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-nonliteral" -# pragma GCC diagnostic ignored "-Wdouble-promotion" // implicit conversion increases floating-point precision -# pragma GCC diagnostic ignored "-Wuseless-cast" -# pragma GCC diagnostic ignored "-Wold-style-cast" -#endif - -#if defined(__clang__) -#define C4_NO_UBSAN_IOVRFLW __attribute__((no_sanitize("signed-integer-overflow"))) -#elif defined(__GNUC__) -#if __GNUC__ > 7 -#define C4_NO_UBSAN_IOVRFLW __attribute__((no_sanitize("signed-integer-overflow"))) -#else -#define C4_NO_UBSAN_IOVRFLW -#endif -#else -#define C4_NO_UBSAN_IOVRFLW -#endif - -// NOLINTBEGIN(hicpp-signed-bitwise) - -namespace c4 { - -/** @defgroup doc_charconv Charconv utilities - * - * Lightweight, very fast generic type-safe wrappers for converting - * individual values to/from strings. These are the main generic - * functions: - * - @ref doc_to_chars and its alias @ref xtoa(): implemented by calling @ref itoa() / @ref utoa() / @ref ftoa() / @ref dtoa() (or generically @ref xtoa()) - * - @ref doc_from_chars and its alias @ref atox(): implemented by calling @ref atoi() / @ref atou() / @ref atof() / @ref atod() (or generically @ref atox()) - * - @ref to_chars_sub() - * - @ref from_chars_first() - * - @ref xtoa() and @ref atox() are implemented in terms of @ref write_dec() / @ref read_dec() et al (see @ref doc_write / @ref doc_read()) - * - * And also some modest brag is in order: these functions are really - * fast: faster even than C++17 `std::to_chars()` and - * `std::to_chars()`, and many dozens of times faster than the - * iostream abominations. - * - * For example, here are some benchmark comparisons for @ref - * doc_from_chars (link leads to the main project README, where these - * results are shown more systematically). - * - * - * - *
atox,int64_t
g++12, linux Visual Studio 2019 - *
\image html linux-x86_64-gxx12.1-Release-c4core-bm-charconv-atox-mega_bytes_per_second-i64.png \image html windows-x86_64-vs2019-Release-c4core-bm-charconv-atox-mega_bytes_per_second-i64.png - *
- * - * - * - *
xtoa,int64_t
g++12, linux Visual Studio 2019 - *
\image html linux-x86_64-gxx12.1-Release-c4core-bm-charconv-xtoa-mega_bytes_per_second-i64.png \image html windows-x86_64-vs2019-Release-c4core-bm-charconv-xtoa-mega_bytes_per_second-i64.png - *
- * - * To parse floating point, c4core uses - * [fastfloat](https://github.com/fastfloat/fast_float), which is - * extremely fast, by an even larger factor: - * - * - * - *
atox,float
g++12, linux Visual Studio 2019 - *
\image html linux-x86_64-gxx12.1-Release-c4core-bm-charconv-atof-mega_bytes_per_second-float.png \image html windows-x86_64-vs2019-Release-c4core-bm-charconv-atof-mega_bytes_per_second-float.png - *
- * - * @{ - */ - -#if C4CORE_HAVE_STD_TOCHARS -/** @warning Use only the symbol. Do not rely on the type or naked value of this enum. */ -typedef enum : std::underlying_type::type { - /** print the real number in floating point format (like %f) */ - FTOA_FLOAT = static_cast::type>(std::chars_format::fixed), - /** print the real number in scientific format (like %e) */ - FTOA_SCIENT = static_cast::type>(std::chars_format::scientific), - /** print the real number in flexible format (like %g) */ - FTOA_FLEX = static_cast::type>(std::chars_format::general), - /** print the real number in hexadecimal format (like %a) */ - FTOA_HEXA = static_cast::type>(std::chars_format::hex), -} RealFormat_e; -#else -/** @warning Use only the symbol. Do not rely on the type or naked value of this enum. */ -typedef enum : char { - /** print the real number in floating point format (like %f) */ - FTOA_FLOAT = 'f', - /** print the real number in scientific format (like %e) */ - FTOA_SCIENT = 'e', - /** print the real number in flexible format (like %g) */ - FTOA_FLEX = 'g', - /** print the real number in hexadecimal format (like %a) */ - FTOA_HEXA = 'a', -} RealFormat_e; -#endif - -/** @cond dev */ -/** in some platforms, int,unsigned int - * are not any of int8_t...int64_t and - * long,unsigned long are not any of uint8_t...uint64_t */ -template -struct is_fixed_length -{ - enum : bool { - /** true if T is one of the fixed length signed types */ - value_i = (std::is_integral::value - && (std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value)), - /** true if T is one of the fixed length unsigned types */ - value_u = (std::is_integral::value - && (std::is_same::value - || std::is_same::value - || std::is_same::value - || std::is_same::value)), - /** true if T is one of the fixed length signed or unsigned types */ - value = value_i || value_u - }; -}; -/** @endcond */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -#if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(push) -#elif defined(__clang__) -# pragma clang diagnostic push -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wconversion" -# if __GNUC__ >= 6 -# pragma GCC diagnostic ignored "-Wnull-dereference" -# endif -#endif - -/** @cond dev */ -namespace detail { - -/* python command to get the values below: -def dec(v): - return str(v) -for bits in (8, 16, 32, 64): - imin, imax, umax = (-(1 << (bits - 1))), (1 << (bits - 1)) - 1, (1 << bits) - 1 - for vname, v in (("imin", imin), ("imax", imax), ("umax", umax)): - for f in (bin, oct, dec, hex): - print(f"{bits}b: {vname}={v} {f.__name__}: len={len(f(v)):2d}: {v} {f(v)}") -*/ - -// do not use the type as the template argument because in some -// platforms long!=int32 and long!=int64. Just use the numbytes -// which is more generic and spares lengthy SFINAE code. -template struct charconv_digits_; -template using charconv_digits = charconv_digits_::value>; - -template<> struct charconv_digits_<1u, true> // int8_t -{ - enum : size_t { - maxdigits_bin = 1 + 2 + 8, // -128==-0b10000000 - maxdigits_oct = 1 + 2 + 3, // -128==-0o200 - maxdigits_dec = 1 + 3, // -128 - maxdigits_hex = 1 + 2 + 2, // -128==-0x80 - maxdigits_bin_nopfx = 8, // -128==-0b10000000 - maxdigits_oct_nopfx = 3, // -128==-0o200 - maxdigits_dec_nopfx = 3, // -128 - maxdigits_hex_nopfx = 2, // -128==-0x80 - }; - // min values without sign! - static constexpr csubstr min_value_dec() noexcept { return csubstr("128"); } - static constexpr csubstr min_value_hex() noexcept { return csubstr("80"); } - static constexpr csubstr min_value_oct() noexcept { return csubstr("200"); } - static constexpr csubstr min_value_bin() noexcept { return csubstr("10000000"); } - static constexpr csubstr max_value_dec() noexcept { return csubstr("127"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 3) || (str.len == 3 && str[0] <= '1')); } -}; -template<> struct charconv_digits_<1u, false> // uint8_t -{ - enum : size_t { - maxdigits_bin = 2 + 8, // 255 0b11111111 - maxdigits_oct = 2 + 3, // 255 0o377 - maxdigits_dec = 3, // 255 - maxdigits_hex = 2 + 2, // 255 0xff - maxdigits_bin_nopfx = 8, // 255 0b11111111 - maxdigits_oct_nopfx = 3, // 255 0o377 - maxdigits_dec_nopfx = 3, // 255 - maxdigits_hex_nopfx = 2, // 255 0xff - }; - static constexpr csubstr max_value_dec() noexcept { return csubstr("255"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 3) || (str.len == 3 && str[0] <= '3')); } -}; -template<> struct charconv_digits_<2u, true> // int16_t -{ - enum : size_t { - maxdigits_bin = 1 + 2 + 16, // -32768 -0b1000000000000000 - maxdigits_oct = 1 + 2 + 6, // -32768 -0o100000 - maxdigits_dec = 1 + 5, // -32768 -32768 - maxdigits_hex = 1 + 2 + 4, // -32768 -0x8000 - maxdigits_bin_nopfx = 16, // -32768 -0b1000000000000000 - maxdigits_oct_nopfx = 6, // -32768 -0o100000 - maxdigits_dec_nopfx = 5, // -32768 -32768 - maxdigits_hex_nopfx = 4, // -32768 -0x8000 - }; - // min values without sign! - static constexpr csubstr min_value_dec() noexcept { return csubstr("32768"); } - static constexpr csubstr min_value_hex() noexcept { return csubstr("8000"); } - static constexpr csubstr min_value_oct() noexcept { return csubstr("100000"); } - static constexpr csubstr min_value_bin() noexcept { return csubstr("1000000000000000"); } - static constexpr csubstr max_value_dec() noexcept { return csubstr("32767"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 6)); } -}; -template<> struct charconv_digits_<2u, false> // uint16_t -{ - enum : size_t { - maxdigits_bin = 2 + 16, // 65535 0b1111111111111111 - maxdigits_oct = 2 + 6, // 65535 0o177777 - maxdigits_dec = 6, // 65535 65535 - maxdigits_hex = 2 + 4, // 65535 0xffff - maxdigits_bin_nopfx = 16, // 65535 0b1111111111111111 - maxdigits_oct_nopfx = 6, // 65535 0o177777 - maxdigits_dec_nopfx = 6, // 65535 65535 - maxdigits_hex_nopfx = 4, // 65535 0xffff - }; - static constexpr csubstr max_value_dec() noexcept { return csubstr("65535"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 6) || (str.len == 6 && str[0] <= '1')); } -}; -template<> struct charconv_digits_<4u, true> // int32_t -{ - enum : size_t { - maxdigits_bin = 1 + 2 + 32, // len=35: -2147483648 -0b10000000000000000000000000000000 - maxdigits_oct = 1 + 2 + 11, // len=14: -2147483648 -0o20000000000 - maxdigits_dec = 1 + 10, // len=11: -2147483648 -2147483648 - maxdigits_hex = 1 + 2 + 8, // len=11: -2147483648 -0x80000000 - maxdigits_bin_nopfx = 32, // len=35: -2147483648 -0b10000000000000000000000000000000 - maxdigits_oct_nopfx = 11, // len=14: -2147483648 -0o20000000000 - maxdigits_dec_nopfx = 10, // len=11: -2147483648 -2147483648 - maxdigits_hex_nopfx = 8, // len=11: -2147483648 -0x80000000 - }; - // min values without sign! - static constexpr csubstr min_value_dec() noexcept { return csubstr("2147483648"); } - static constexpr csubstr min_value_hex() noexcept { return csubstr("80000000"); } - static constexpr csubstr min_value_oct() noexcept { return csubstr("20000000000"); } - static constexpr csubstr min_value_bin() noexcept { return csubstr("10000000000000000000000000000000"); } - static constexpr csubstr max_value_dec() noexcept { return csubstr("2147483647"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 11) || (str.len == 11 && str[0] <= '1')); } -}; -template<> struct charconv_digits_<4u, false> // uint32_t -{ - enum : size_t { - maxdigits_bin = 2 + 32, // len=34: 4294967295 0b11111111111111111111111111111111 - maxdigits_oct = 2 + 11, // len=13: 4294967295 0o37777777777 - maxdigits_dec = 10, // len=10: 4294967295 4294967295 - maxdigits_hex = 2 + 8, // len=10: 4294967295 0xffffffff - maxdigits_bin_nopfx = 32, // len=34: 4294967295 0b11111111111111111111111111111111 - maxdigits_oct_nopfx = 11, // len=13: 4294967295 0o37777777777 - maxdigits_dec_nopfx = 10, // len=10: 4294967295 4294967295 - maxdigits_hex_nopfx = 8, // len=10: 4294967295 0xffffffff - }; - static constexpr csubstr max_value_dec() noexcept { return csubstr("4294967295"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 11) || (str.len == 11 && str[0] <= '3')); } -}; -template<> struct charconv_digits_<8u, true> // int64_t -{ - enum : size_t { - maxdigits_bin = 1 + 2 + 64, // len=67: -9223372036854775808 -0b1000000000000000000000000000000000000000000000000000000000000000 - maxdigits_oct = 1 + 2 + 22, // len=25: -9223372036854775808 -0o1000000000000000000000 - maxdigits_dec = 1 + 19, // len=20: -9223372036854775808 -9223372036854775808 - maxdigits_hex = 1 + 2 + 16, // len=19: -9223372036854775808 -0x8000000000000000 - maxdigits_bin_nopfx = 64, // len=67: -9223372036854775808 -0b1000000000000000000000000000000000000000000000000000000000000000 - maxdigits_oct_nopfx = 22, // len=25: -9223372036854775808 -0o1000000000000000000000 - maxdigits_dec_nopfx = 19, // len=20: -9223372036854775808 -9223372036854775808 - maxdigits_hex_nopfx = 16, // len=19: -9223372036854775808 -0x8000000000000000 - }; - static constexpr csubstr min_value_dec() noexcept { return csubstr("9223372036854775808"); } - static constexpr csubstr min_value_hex() noexcept { return csubstr("8000000000000000"); } - static constexpr csubstr min_value_oct() noexcept { return csubstr("1000000000000000000000"); } - static constexpr csubstr min_value_bin() noexcept { return csubstr("1000000000000000000000000000000000000000000000000000000000000000"); } - static constexpr csubstr max_value_dec() noexcept { return csubstr("9223372036854775807"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 22)); } -}; -template<> struct charconv_digits_<8u, false> // uint64_t -{ - enum : size_t { - maxdigits_bin = 2 + 64, // len=66: 18446744073709551615 0b1111111111111111111111111111111111111111111111111111111111111111 - maxdigits_oct = 2 + 22, // len=24: 18446744073709551615 0o1777777777777777777777 - maxdigits_dec = 20, // len=20: 18446744073709551615 18446744073709551615 - maxdigits_hex = 2 + 16, // len=18: 18446744073709551615 0xffffffffffffffff - maxdigits_bin_nopfx = 64, // len=66: 18446744073709551615 0b1111111111111111111111111111111111111111111111111111111111111111 - maxdigits_oct_nopfx = 22, // len=24: 18446744073709551615 0o1777777777777777777777 - maxdigits_dec_nopfx = 20, // len=20: 18446744073709551615 18446744073709551615 - maxdigits_hex_nopfx = 16, // len=18: 18446744073709551615 0xffffffffffffffff - }; - static constexpr csubstr max_value_dec() noexcept { return csubstr("18446744073709551615"); } - static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 22) || (str.len == 22 && str[0] <= '1')); } -}; -} // namespace detail - -// Helper macros, undefined below -#define _c4append(c) { if(C4_LIKELY(pos < buf.len)) { buf.str[pos++] = static_cast(c); } else { ++pos; } } -#define _c4appendhex(i) { if(C4_LIKELY(pos < buf.len)) { buf.str[pos++] = hexchars[i]; } else { ++pos; } } - -/** @endcond */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/** @defgroup doc_digits Get number of digits - * - * @note At first sight this code may look heavily branchy and - * therefore inefficient. However, measurements revealed this to be - * the fastest among the alternatives. - * - * @see https://github.com/biojppm/c4core/pull/77 - * - * @{ - */ - -/** decimal digits for 8 bit integers */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE -auto digits_dec(T v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - return ((v >= 100) ? 3u : ((v >= 10) ? 2u : 1u)); -} - -/** decimal digits for 16 bit integers */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE -auto digits_dec(T v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - return ((v >= 10000) ? 5u : (v >= 1000) ? 4u : (v >= 100) ? 3u : (v >= 10) ? 2u : 1u); -} - -/** decimal digits for 32 bit integers */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE -auto digits_dec(T v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - return ((v >= 1000000000) ? 10u : (v >= 100000000) ? 9u : (v >= 10000000) ? 8u : - (v >= 1000000) ? 7u : (v >= 100000) ? 6u : (v >= 10000) ? 5u : - (v >= 1000) ? 4u : (v >= 100) ? 3u : (v >= 10) ? 2u : 1u); -} - -/** decimal digits for 64 bit integers */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE -auto digits_dec(T v) noexcept - -> typename std::enable_if::type -{ - // thanks @fargies!!! - // https://github.com/biojppm/c4core/pull/77#issuecomment-1063753568 - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - if(v >= 1000000000) // 10 - { - if(v >= 100000000000000) // 15 [15-20] range - { - if(v >= 100000000000000000) // 18 (15 + (20 - 15) / 2) - { - if((typename std::make_unsigned::type)v >= 10000000000000000000u) // 20 - return 20u; - else - return (v >= 1000000000000000000) ? 19u : 18u; - } - else if(v >= 10000000000000000) // 17 - return 17u; - else - return(v >= 1000000000000000) ? 16u : 15u; - } - else if(v >= 1000000000000) // 13 - return (v >= 10000000000000) ? 14u : 13u; - else if(v >= 100000000000) // 12 - return 12; - else - return(v >= 10000000000) ? 11u : 10u; - } - else if(v >= 10000) // 5 [5-9] range - { - if(v >= 10000000) // 8 - return (v >= 100000000) ? 9u : 8u; - else if(v >= 1000000) // 7 - return 7; - else - return (v >= 100000) ? 6u : 5u; - } - else if(v >= 100) - return (v >= 1000) ? 4u : 3u; - else - return (v >= 10) ? 2u : 1u; -} - - -/** return the number of digits required to encode an hexadecimal number. */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE unsigned digits_hex(T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - return v ? 1u + (msb((typename std::make_unsigned::type)v) >> 2u) : 1u; -} - -/** return the number of digits required to encode a binary number. */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE unsigned digits_bin(T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - return v ? 1u + msb((typename std::make_unsigned::type)v) : 1u; -} - -/** return the number of digits required to encode an octal number. */ -template -C4_CONSTEXPR14 C4_ALWAYS_INLINE unsigned digits_oct(T v_) noexcept -{ - // TODO: is there a better way? - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v_ >= 0); - using U = typename std::conditional::type>::type; - U v = (U) v_; // safe because we require v_ >= 0 // NOLINT - uint32_t __n = 1; - enum : U { - __b2 = 64u, - __b3 = 64u * 8u, - __b4 = 64u * 8u * 8u, - }; - while(true) - { - if(v < 8u) - return __n; - else if(v < __b2) - return __n + 1; - else if(v < __b3) - return __n + 2; - else if(v < __b4) - return __n + 3; - v /= (U) __b4; - __n += 4; - } -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -namespace detail { -C4_INLINE_CONSTEXPR const char hexchars[] = "0123456789abcdef"; -C4_INLINE_CONSTEXPR const char digits0099[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; -} // namespace detail -/** @endcond */ - -C4_SUPPRESS_WARNING_GCC_PUSH -C4_SUPPRESS_WARNING_GCC("-Warray-bounds") // gcc has false positives here -#if (defined(__GNUC__) && (__GNUC__ >= 7)) -C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow") // gcc has false positives here -#endif - -/** @defgroup doc_write_unchecked Write with known number of digits - * - * Writes a value without checking the buffer length with regards to - * the required number of digits to encode the value. It is the - * responsibility of the caller to ensure that the provided number of - * digits is enough to write the given value. Notwithstanding the - * name, assertions are liberally performed, so this code is safe. - * - * @{ */ - -template -C4_HOT C4_ALWAYS_INLINE -void write_dec_unchecked(substr buf, T v, unsigned digits_v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - C4_ASSERT(buf.len >= digits_v); - C4_XASSERT(digits_v == digits_dec(v)); - // in bm_xtoa: checkoncelog_singlediv_write2 - while(v >= T(100)) - { - T quo = v; - quo /= T(100); - const auto num = (v - quo * T(100)) << 1u; // NOLINT - v = quo; - buf.str[--digits_v] = detail::digits0099[num + 1]; - buf.str[--digits_v] = detail::digits0099[num]; - } - if(v >= T(10)) - { - C4_ASSERT(digits_v == 2); - const auto num = v << 1u; - buf.str[1] = detail::digits0099[num + 1]; - buf.str[0] = detail::digits0099[num]; - } - else - { - C4_ASSERT(digits_v == 1); - buf.str[0] = (char)('0' + v); - } -} - - -template -C4_HOT C4_ALWAYS_INLINE -void write_hex_unchecked(substr buf, T v, unsigned digits_v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - C4_ASSERT(buf.len >= digits_v); - C4_XASSERT(digits_v == digits_hex(v)); - do { - buf.str[--digits_v] = detail::hexchars[v & T(15)]; - v >>= 4; - } while(v); - C4_ASSERT(digits_v == 0); -} - - -template -C4_HOT C4_ALWAYS_INLINE -void write_oct_unchecked(substr buf, T v, unsigned digits_v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - C4_ASSERT(buf.len >= digits_v); - C4_XASSERT(digits_v == digits_oct(v)); - do { - buf.str[--digits_v] = (char)('0' + (v & T(7))); - v >>= 3; - } while(v); - C4_ASSERT(digits_v == 0); -} - - -template -C4_HOT C4_ALWAYS_INLINE -void write_bin_unchecked(substr buf, T v, unsigned digits_v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - C4_ASSERT(buf.len >= digits_v); - C4_XASSERT(digits_v == digits_bin(v)); - do { - buf.str[--digits_v] = (char)('0' + (v & T(1))); - v >>= 1; - } while(v); - C4_ASSERT(digits_v == 0); -} - -/** @} */ // write_unchecked - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_write Write a value - * - * Writes a value without checking the buffer length - * decimal number -- but asserting. - * - * @{ */ - -/** write an integer to a string in decimal format. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the required size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t write_dec(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - unsigned digits = digits_dec(v); - if(C4_LIKELY(buf.len >= digits)) - write_dec_unchecked(buf, v, digits); - return digits; -} - -/** write an integer to a string in hexadecimal format. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not prefix with 0x - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the required size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t write_hex(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - unsigned digits = digits_hex(v); - if(C4_LIKELY(buf.len >= digits)) - write_hex_unchecked(buf, v, digits); - return digits; -} - -/** write an integer to a string in octal format. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not prefix with 0o - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the required size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t write_oct(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - unsigned digits = digits_oct(v); - if(C4_LIKELY(buf.len >= digits)) - write_oct_unchecked(buf, v, digits); - return digits; -} - -/** write an integer to a string in binary format. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not prefix with 0b - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the required size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t write_bin(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(v >= 0); - unsigned digits = digits_bin(v); - C4_ASSERT(digits > 0); - if(C4_LIKELY(buf.len >= digits)) - write_bin_unchecked(buf, v, digits); - return digits; -} - - -/** @cond dev */ -namespace detail { -template using NumberWriter = size_t (*)(substr, U); -template writer> -size_t write_num_digits(substr buf, T v, size_t num_digits) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - const size_t ret = writer(buf, v); - if(ret >= num_digits) - return ret; - else if(ret >= buf.len || num_digits > buf.len) - return num_digits; - C4_ASSERT(num_digits >= ret); - const size_t delta = static_cast(num_digits - ret); // NOLINT - C4_ASSERT(ret + delta <= buf.len); - if(ret) - memmove(buf.str + delta, buf.str, ret); - if(delta) - memset(buf.str, '0', delta); - return num_digits; -} -} // namespace detail -/** @endcond */ - - -/** same as c4::write_dec(), but pad with zeroes on the left - * such that the resulting string is @p num_digits wide. - * If the given number is requires more than num_digits, then the number prevails. */ -template -C4_ALWAYS_INLINE size_t write_dec(substr buf, T val, size_t num_digits) noexcept -{ - return detail::write_num_digits>(buf, val, num_digits); -} - -/** same as c4::write_hex(), but pad with zeroes on the left - * such that the resulting string is @p num_digits wide. - * If the given number is requires more than num_digits, then the number prevails. */ -template -C4_ALWAYS_INLINE size_t write_hex(substr buf, T val, size_t num_digits) noexcept -{ - return detail::write_num_digits>(buf, val, num_digits); -} - -/** same as c4::write_bin(), but pad with zeroes on the left - * such that the resulting string is @p num_digits wide. - * If the given number is requires more than num_digits, then the number prevails. */ -template -C4_ALWAYS_INLINE size_t write_bin(substr buf, T val, size_t num_digits) noexcept -{ - return detail::write_num_digits>(buf, val, num_digits); -} - -/** same as c4::write_oct(), but pad with zeroes on the left - * such that the resulting string is @p num_digits wide. - * If the given number is requires more than num_digits, then the number prevails. */ -template -C4_ALWAYS_INLINE size_t write_oct(substr buf, T val, size_t num_digits) noexcept -{ - return detail::write_num_digits>(buf, val, num_digits); -} - -/** @} */ // write - -C4_SUPPRESS_WARNING_GCC_POP - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -C4_SUPPRESS_WARNING_MSVC_PUSH -C4_SUPPRESS_WARNING_MSVC(4365) // '=': conversion from 'int' to 'I', signed/unsigned mismatch - -/** @defgroup doc_read Read a value - * - * @{ */ - -/** read a decimal integer from a string. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note The string must be trimmed. Whitespace is not accepted. - * @note the string must not be empty - * @note there is no check for overflow; the value wraps around - * in a way similar to the standard C/C++ overflow behavior. - * For example, `read_dec("128", &val)` returns true - * and val will be set to 0 because 127 is the max i8 value. - * @see overflows() to find out if a number string overflows a type range - * @return true if the conversion was successful (no overflow check) */ -template -C4_NO_UBSAN_IOVRFLW -C4_ALWAYS_INLINE bool read_dec(csubstr s, I *C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(!s.empty()); - *v = 0; - for(char c : s) - { - if(C4_UNLIKELY(c < '0' || c > '9')) - return false; - *v = (*v) * I(10) + (I(c) - I('0')); - } - return true; -} - -/** read an hexadecimal integer from a string. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not accept leading 0x or 0X - * @note the string must not be empty - * @note the string must be trimmed. Whitespace is not accepted. - * @note there is no check for overflow; the value wraps around - * in a way similar to the standard C/C++ overflow behavior. - * For example, `read_hex("80", &val)` returns true - * and val will be set to 0 because 7f is the max i8 value. - * @see overflows() to find out if a number string overflows a type range - * @return true if the conversion was successful (no overflow check) */ -template -C4_NO_UBSAN_IOVRFLW -C4_ALWAYS_INLINE bool read_hex(csubstr s, I *C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(!s.empty()); - *v = 0; - for(char c : s) - { - I cv; - if(c >= '0' && c <= '9') - cv = I(c) - I('0'); - else if(c >= 'a' && c <= 'f') - cv = I(10) + (I(c) - I('a')); - else if(c >= 'A' && c <= 'F') - cv = I(10) + (I(c) - I('A')); - else - return false; - *v = (*v) * I(16) + cv; - } - return true; -} - -/** read a binary integer from a string. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not accept leading 0b or 0B - * @note the string must not be empty - * @note the string must be trimmed. Whitespace is not accepted. - * @note there is no check for overflow; the value wraps around - * in a way similar to the standard C/C++ overflow behavior. - * For example, `read_bin("10000000", &val)` returns true - * and val will be set to 0 because 1111111 is the max i8 value. - * @see overflows() to find out if a number string overflows a type range - * @return true if the conversion was successful (no overflow check) */ -template -C4_NO_UBSAN_IOVRFLW -C4_ALWAYS_INLINE bool read_bin(csubstr s, I *C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(!s.empty()); - *v = 0; - for(char c : s) - { - *v <<= 1; - if(c == '1') - *v |= 1; - else if(c != '0') - return false; - } - return true; -} - -/** read an octal integer from a string. This is the - * lowest level (and the fastest) function to do this task. - * @note does not accept negative numbers - * @note does not accept leading 0o or 0O - * @note the string must not be empty - * @note the string must be trimmed. Whitespace is not accepted. - * @note there is no check for overflow; the value wraps around - * in a way similar to the standard C/C++ overflow behavior. - * For example, `read_oct("200", &val)` returns true - * and val will be set to 0 because 177 is the max i8 value. - * @see overflows() to find out if a number string overflows a type range - * @return true if the conversion was successful (no overflow check) */ -template -C4_NO_UBSAN_IOVRFLW -C4_ALWAYS_INLINE bool read_oct(csubstr s, I *C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_ASSERT(!s.empty()); - *v = 0; - for(char c : s) - { - if(C4_UNLIKELY(c < '0' || c > '7')) - return false; - *v = (*v) * I(8) + (I(c) - I('0')); - } - return true; -} - -/** @} */ - -C4_SUPPRESS_WARNING_MSVC_POP - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wswitch-default") - -/** @cond dev */ -namespace detail { -inline size_t _itoa2buf(substr buf, size_t pos, csubstr val) noexcept -{ - C4_ASSERT(pos < buf.len); - C4_ASSERT(pos + val.len <= buf.len); - C4_ASSERT(val.len > 0); - memcpy(buf.str + pos, val.str, val.len); - return pos + val.len; -} -inline size_t _itoa2bufwithdigits(substr buf, size_t pos, size_t num_digits, csubstr val) noexcept -{ - num_digits = num_digits > val.len ? num_digits - val.len : 0; - C4_ASSERT(num_digits + val.len <= buf.len); - for(size_t i = 0; i < num_digits; ++i) - _c4append('0'); - return detail::_itoa2buf(buf, pos, val); -} -template -C4_NO_INLINE size_t _itoadec2buf(substr buf) noexcept -{ - using digits_type = detail::charconv_digits; - if(C4_UNLIKELY(buf.len < digits_type::maxdigits_dec)) - return digits_type::maxdigits_dec; - buf.str[0] = '-'; - return detail::_itoa2buf(buf, 1, digits_type::min_value_dec()); -} -template -C4_NO_INLINE size_t _itoa2buf(substr buf, I radix) noexcept -{ - using digits_type = detail::charconv_digits; - size_t pos = 0; - if(C4_LIKELY(buf.len > 0)) - buf.str[pos++] = '-'; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case I(10): - if(C4_UNLIKELY(buf.len < digits_type::maxdigits_dec)) - return digits_type::maxdigits_dec; - pos =_itoa2buf(buf, pos, digits_type::min_value_dec()); - break; - case I(16): - if(C4_UNLIKELY(buf.len < digits_type::maxdigits_hex)) - return digits_type::maxdigits_hex; - buf.str[pos++] = '0'; - buf.str[pos++] = 'x'; - pos = _itoa2buf(buf, pos, digits_type::min_value_hex()); - break; - case I( 2): - if(C4_UNLIKELY(buf.len < digits_type::maxdigits_bin)) - return digits_type::maxdigits_bin; - buf.str[pos++] = '0'; - buf.str[pos++] = 'b'; - pos = _itoa2buf(buf, pos, digits_type::min_value_bin()); - break; - case I( 8): - if(C4_UNLIKELY(buf.len < digits_type::maxdigits_oct)) - return digits_type::maxdigits_oct; - buf.str[pos++] = '0'; - buf.str[pos++] = 'o'; - pos = _itoa2buf(buf, pos, digits_type::min_value_oct()); - break; - } - return pos; -} -template -C4_NO_INLINE size_t _itoa2buf(substr buf, I radix, size_t num_digits) noexcept -{ - using digits_type = detail::charconv_digits; - size_t pos = 0; - size_t needed_digits = 0; - if(C4_LIKELY(buf.len > 0)) - buf.str[pos++] = '-'; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case I(10): - // add 1 to account for - - needed_digits = num_digits+1 > digits_type::maxdigits_dec ? num_digits+1 : digits_type::maxdigits_dec; - if(C4_UNLIKELY(buf.len < needed_digits)) - return needed_digits; - pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_dec()); - break; - case I(16): - // add 3 to account for -0x - needed_digits = num_digits+3 > digits_type::maxdigits_hex ? num_digits+3 : digits_type::maxdigits_hex; - if(C4_UNLIKELY(buf.len < needed_digits)) - return needed_digits; - buf.str[pos++] = '0'; - buf.str[pos++] = 'x'; - pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_hex()); - break; - case I(2): - // add 3 to account for -0b - needed_digits = num_digits+3 > digits_type::maxdigits_bin ? num_digits+3 : digits_type::maxdigits_bin; - if(C4_UNLIKELY(buf.len < needed_digits)) - return needed_digits; - C4_ASSERT(buf.len >= digits_type::maxdigits_bin); - buf.str[pos++] = '0'; - buf.str[pos++] = 'b'; - pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_bin()); - break; - case I(8): - // add 3 to account for -0o - needed_digits = num_digits+3 > digits_type::maxdigits_oct ? num_digits+3 : digits_type::maxdigits_oct; - if(C4_UNLIKELY(buf.len < needed_digits)) - return needed_digits; - C4_ASSERT(buf.len >= digits_type::maxdigits_oct); - buf.str[pos++] = '0'; - buf.str[pos++] = 'o'; - pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_oct()); - break; - } - return pos; -} -} // namespace detail -/** @endcond */ - - -/** @defgroup doc_itoa itoa: signed to chars - * - * @{ */ - -/** convert an integral signed decimal to a string. - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t itoa(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_signed::value); - if(v >= T(0)) - { - // write_dec() checks the buffer size, so no need to check here - return write_dec(buf, v); - } - // when T is the min value (eg i8: -128), negating it - // will overflow, so treat the min as a special case - if(C4_LIKELY(v != std::numeric_limits::min())) - { - v = -v; - unsigned digits = digits_dec(v); - if(C4_LIKELY(buf.len >= digits + 1u)) - { - buf.str[0] = '-'; - write_dec_unchecked(buf.sub(1), v, digits); - } - return digits + 1u; - } - return detail::_itoadec2buf(buf); -} - -/** convert an integral signed integer to a string, using a specific - * radix. The radix must be 2, 8, 10 or 16. - * - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t itoa(substr buf, T v, T radix) noexcept -{ - C4_STATIC_ASSERT(std::is_signed::value); - C4_ASSERT(radix == 2 || radix == 8 || radix == 10 || radix == 16); - C4_SUPPRESS_WARNING_GCC_PUSH - #if (defined(__GNUC__) && (__GNUC__ >= 7)) - C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow") // gcc has a false positive here - #endif - // when T is the min value (eg i8: -128), negating it - // will overflow, so treat the min as a special case - if(C4_LIKELY(v != std::numeric_limits::min())) - { - unsigned pos = 0; - if(v < 0) - { - v = -v; - if(C4_LIKELY(buf.len > 0)) - buf.str[pos] = '-'; - ++pos; - } - unsigned digits = 0; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case T(10): - digits = digits_dec(v); - if(C4_LIKELY(buf.len >= pos + digits)) - write_dec_unchecked(buf.sub(pos), v, digits); - break; - case T(16): - digits = digits_hex(v); - if(C4_LIKELY(buf.len >= pos + 2u + digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'x'; - write_hex_unchecked(buf.sub(pos + 2), v, digits); - } - digits += 2u; - break; - case T(2): - digits = digits_bin(v); - if(C4_LIKELY(buf.len >= pos + 2u + digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'b'; - write_bin_unchecked(buf.sub(pos + 2), v, digits); - } - digits += 2u; - break; - case T(8): - digits = digits_oct(v); - if(C4_LIKELY(buf.len >= pos + 2u + digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'o'; - write_oct_unchecked(buf.sub(pos + 2), v, digits); - } - digits += 2u; - break; - } - return pos + digits; - } - C4_SUPPRESS_WARNING_GCC_POP - // when T is the min value (eg i8: -128), negating it - // will overflow - return detail::_itoa2buf(buf, radix); -} - - -/** same as c4::itoa(), but pad with zeroes on the left such that the - * resulting string is @p num_digits wide, not accounting for radix - * prefix (0x,0o,0b). The @p radix must be 2, 8, 10 or 16. - * - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t itoa(substr buf, T v, T radix, size_t num_digits) noexcept -{ - C4_STATIC_ASSERT(std::is_signed::value); - C4_ASSERT(radix == 2 || radix == 8 || radix == 10 || radix == 16); - C4_SUPPRESS_WARNING_GCC_PUSH - #if (defined(__GNUC__) && (__GNUC__ >= 7)) - C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow") // gcc has a false positive here - #endif - // when T is the min value (eg i8: -128), negating it - // will overflow, so treat the min as a special case - if(C4_LIKELY(v != std::numeric_limits::min())) - { - unsigned pos = 0; - if(v < 0) - { - v = -v; - if(C4_LIKELY(buf.len > 0)) - buf.str[pos] = '-'; - ++pos; - } - unsigned total_digits = 0; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case T(10): - total_digits = digits_dec(v); - total_digits = pos + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - write_dec(buf.sub(pos), v, num_digits); - break; - case T(16): - total_digits = digits_hex(v); - total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'x'; - write_hex(buf.sub(pos + 2), v, num_digits); - } - break; - case T(2): - total_digits = digits_bin(v); - total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'b'; - write_bin(buf.sub(pos + 2), v, num_digits); - } - break; - case T(8): - total_digits = digits_oct(v); - total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[pos + 0] = '0'; - buf.str[pos + 1] = 'o'; - write_oct(buf.sub(pos + 2), v, num_digits); - } - break; - } - return total_digits; - } - C4_SUPPRESS_WARNING_GCC_POP - // when T is the min value (eg i8: -128), negating it - // will overflow - return detail::_itoa2buf(buf, radix, num_digits); -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_utoa utoa: unsigned to chars - * - * @{ */ - -/** convert an integral unsigned decimal to a string. - * - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t utoa(substr buf, T v) noexcept -{ - C4_STATIC_ASSERT(std::is_unsigned::value); - // write_dec() does the buffer length check, so no need to check here - return write_dec(buf, v); -} - -/** convert an integral unsigned integer to a string, using a specific - * radix. The radix must be 2, 8, 10 or 16. - * - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t utoa(substr buf, T v, T radix) noexcept -{ - C4_STATIC_ASSERT(std::is_unsigned::value); - C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8); - unsigned digits = 0; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case T(10): - digits = digits_dec(v); - if(C4_LIKELY(buf.len >= digits)) - write_dec_unchecked(buf, v, digits); - break; - case T(16): - digits = digits_hex(v); - if(C4_LIKELY(buf.len >= digits+2u)) - { - buf.str[0] = '0'; - buf.str[1] = 'x'; - write_hex_unchecked(buf.sub(2), v, digits); - } - digits += 2u; - break; - case T(2): - digits = digits_bin(v); - if(C4_LIKELY(buf.len >= digits+2u)) - { - buf.str[0] = '0'; - buf.str[1] = 'b'; - write_bin_unchecked(buf.sub(2), v, digits); - } - digits += 2u; - break; - case T(8): - digits = digits_oct(v); - if(C4_LIKELY(buf.len >= digits+2u)) - { - buf.str[0] = '0'; - buf.str[1] = 'o'; - write_oct_unchecked(buf.sub(2), v, digits); - } - digits += 2u; - break; - } - return digits; -} - -/** same as c4::utoa(), but pad with zeroes on the left such that the - * resulting string is @p num_digits wide. The @p radix must be 2, - * 8, 10 or 16. - * - * @note the resulting string is NOT zero-terminated. - * @note it is ok to call this with an empty or too-small buffer; - * no writes will occur, and the needed size will be returned - * @return the number of characters required for the buffer. */ -template -C4_ALWAYS_INLINE size_t utoa(substr buf, T v, T radix, size_t num_digits) noexcept -{ - C4_STATIC_ASSERT(std::is_unsigned::value); - C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8); - unsigned total_digits = 0; - switch(radix) // NOLINT(hicpp-multiway-paths-covered) - { - case T(10): - total_digits = digits_dec(v); - total_digits = (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - write_dec(buf, v, num_digits); - break; - case T(16): - total_digits = digits_hex(v); - total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[0] = '0'; - buf.str[1] = 'x'; - write_hex(buf.sub(2), v, num_digits); - } - break; - case T(2): - total_digits = digits_bin(v); - total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[0] = '0'; - buf.str[1] = 'b'; - write_bin(buf.sub(2), v, num_digits); - } - break; - case T(8): - total_digits = digits_oct(v); - total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits); - if(C4_LIKELY(buf.len >= total_digits)) - { - buf.str[0] = '0'; - buf.str[1] = 'o'; - write_oct(buf.sub(2), v, num_digits); - } - break; - } - return total_digits; -} -C4_SUPPRESS_WARNING_GCC_POP - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_atoi atoi: chars to signed - * - * @{ */ - -/** Convert a trimmed string to a signed integral value. The input - * string can be formatted as decimal, binary (prefix 0b or 0B), octal - * (prefix 0o or 0O) or hexadecimal (prefix 0x or 0X). Strings with - * leading zeroes are considered as decimal and not octal (unlike the - * C/C++ convention). Every character in the input string is read for - * the conversion; the input string must not contain any leading or - * trailing whitespace. - * - * @return true if the conversion was successful. - * - * @note a positive sign is not accepted. ie, the string must not - * start with '+' - * - * @note overflow is not detected: the return status is true even if - * the conversion would return a value outside of the type's range, in - * which case the result will wrap around the type's range. This is - * similar to native behavior. See @ref doc_overflows and @ref - * doc_overflow_checked for overflow checking utilities. - * - * @see atoi_first() if the string is not trimmed to the value to read. */ -template -C4_NO_UBSAN_IOVRFLW -C4_ALWAYS_INLINE bool atoi(csubstr str, T * C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - C4_STATIC_ASSERT(std::is_signed::value); - - if(C4_UNLIKELY(str.len == 0)) - return false; - - C4_ASSERT(str.str[0] != '+'); - - T sign = 1; - size_t start = 0; - if(str.str[0] == '-') - { - if(C4_UNLIKELY(str.len == ++start)) - return false; - sign = -1; - } - - bool parsed_ok = true; - if(str.str[start] != '0') // this should be the common case, so put it first - { - parsed_ok = read_dec(str.sub(start), v); - } - else if(str.len > start + 1) - { - // starts with 0: is it 0x, 0o, 0b? - const char pfx = str.str[start + 1]; - if(pfx == 'x' || pfx == 'X') - parsed_ok = str.len > start + 2 && read_hex(str.sub(start + 2), v); - else if(pfx == 'b' || pfx == 'B') - parsed_ok = str.len > start + 2 && read_bin(str.sub(start + 2), v); - else if(pfx == 'o' || pfx == 'O') - parsed_ok = str.len > start + 2 && read_oct(str.sub(start + 2), v); - else - parsed_ok = read_dec(str.sub(start + 1), v); - } - else - { - parsed_ok = read_dec(str.sub(start), v); - } - if(C4_LIKELY(parsed_ok)) - *v *= sign; - return parsed_ok; -} - - -/** Select the next range of characters in the string that can be parsed - * as a signed integral value, and convert it using atoi(). Leading - * whitespace (space, newline, tabs) is skipped. - * @return the number of characters read for conversion, or csubstr::npos if the conversion failed - * @see atoi() if the string is already trimmed to the value to read. - * @see csubstr::first_int_span() */ -template -C4_ALWAYS_INLINE size_t atoi_first(csubstr str, T * C4_RESTRICT v) -{ - csubstr trimmed = str.first_int_span(); - if(trimmed.len == 0) - return csubstr::npos; - if(atoi(trimmed, v)) - return static_cast(trimmed.end() - str.begin()); - return csubstr::npos; -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_atou atou: chars to unsigned - * - * @{ */ - -/** Convert a trimmed string to an unsigned integral value. The string can be - * formatted as decimal, binary (prefix 0b or 0B), octal (prefix 0o or 0O) - * or hexadecimal (prefix 0x or 0X). Every character in the input string is read - * for the conversion; it must not contain any leading or trailing whitespace. - * - * @return true if the conversion was successful. - * - * @note overflow is not detected: the return status is true even if - * the conversion would return a value outside of the type's range, in - * which case the result will wrap around the type's range. See @ref - * doc_overflows and @ref doc_overflow_checked for overflow checking - * utilities. - * - * @note If the string has a minus character, the return status - * will be false. - * - * @see atou_first() if the string is not trimmed to the value to read. */ -template -bool atou(csubstr str, T * C4_RESTRICT v) noexcept -{ - C4_STATIC_ASSERT(std::is_integral::value); - - if(C4_UNLIKELY(str.len == 0 || str.front() == '-')) - return false; - - bool parsed_ok = true; - if(str.str[0] != '0') - { - parsed_ok = read_dec(str, v); - } - else - { - if(str.len > 1) - { - const char pfx = str.str[1]; - if(pfx == 'x' || pfx == 'X') - parsed_ok = str.len > 2 && read_hex(str.sub(2), v); - else if(pfx == 'b' || pfx == 'B') - parsed_ok = str.len > 2 && read_bin(str.sub(2), v); - else if(pfx == 'o' || pfx == 'O') - parsed_ok = str.len > 2 && read_oct(str.sub(2), v); - else - parsed_ok = read_dec(str, v); - } - else - { - *v = 0; // we know the first character is 0 - } - } - return parsed_ok; -} - - -/** Select the next range of characters in the string that can be parsed - * as an unsigned integral value, and convert it using atou(). Leading - * whitespace (space, newline, tabs) is skipped. - * @return the number of characters read for conversion, or csubstr::npos if the conversion faileds - * @see atou() if the string is already trimmed to the value to read. - * @see csubstr::first_uint_span() */ -template -C4_ALWAYS_INLINE size_t atou_first(csubstr str, T *v) -{ - csubstr trimmed = str.first_uint_span(); - if(trimmed.len == 0) - return csubstr::npos; - if(atou(trimmed, v)) - return static_cast(trimmed.end() - str.begin()); - return csubstr::npos; -} - - -/** @} */ - -#if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(pop) -#elif defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -namespace detail { -inline bool check_overflow(csubstr str, csubstr limit) noexcept -{ - if(str.len != limit.len) - return str.len > limit.len; - for(size_t i = 0; i < limit.len; ++i) - { - if(str[i] < limit[i]) - return false; - else if(str[i] > limit[i]) - return true; - } - return false; -} -} // namespace detail -/** @endcond */ - - -/** @defgroup doc_overflows overflows: does a number string overflow a type - * - * @{ */ - -/** Test if the following string would overflow when converted to - * associated integral types; this function is dispatched with SFINAE - * to handle differently signed and unsigned types. - * @return true if number will overflow, false if it fits (or doesn't parse) - * @see doc_overflow_checked for format specifiers to enforce no-overflow reads - */ -template -auto overflows(csubstr str) noexcept - -> typename std::enable_if::value, bool>::type -{ - C4_STATIC_ASSERT(std::is_integral::value); - - if(C4_UNLIKELY(str.len == 0)) - { - return false; - } - else if(str.str[0] == '0') - { - if (str.len == 1) - return false; - switch (str.str[1]) - { - case 'x': - case 'X': - { - size_t fno = str.first_not_of('0', 2); - if (fno == csubstr::npos) - return false; - return !(str.len <= fno + (sizeof(T) * 2)); - } - case 'b': - case 'B': - { - size_t fno = str.first_not_of('0', 2); - if (fno == csubstr::npos) - return false; - return !(str.len <= fno +(sizeof(T) * 8)); - } - case 'o': - case 'O': - { - size_t fno = str.first_not_of('0', 2); - if(fno == csubstr::npos) - return false; - return detail::charconv_digits::is_oct_overflow(str.sub(fno)); - } - default: - { - size_t fno = str.first_not_of('0', 1); - if(fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::max_value_dec()); - } - } - } - else if(C4_UNLIKELY(str[0] == '-')) - { - return true; - } - else - { - return detail::check_overflow(str, detail::charconv_digits::max_value_dec()); - } -} - - -/** Test if the following string would overflow when converted to - * associated integral types; this function is dispatched with SFINAE - * to handle differently signed and unsigned types. - * - * @return true if number will overflow, false if it fits (or doesn't parse) - * @see doc_overflow_checked for format specifiers to enforce no-overflow reads - */ -template -auto overflows(csubstr str) noexcept - -> typename std::enable_if::value, bool>::type -{ - C4_STATIC_ASSERT(std::is_integral::value); - if(C4_UNLIKELY(str.len == 0)) - return false; - if(str.str[0] == '-') - { - if(str.str[1] == '0') - { - if(str.len == 2) - return false; - switch(str.str[2]) - { - case 'x': - case 'X': - { - size_t fno = str.first_not_of('0', 3); - if (fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::min_value_hex()); - } - case 'b': - case 'B': - { - size_t fno = str.first_not_of('0', 3); - if (fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::min_value_bin()); - } - case 'o': - case 'O': - { - size_t fno = str.first_not_of('0', 3); - if(fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::min_value_oct()); - } - default: - { - size_t fno = str.first_not_of('0', 2); - if(fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::min_value_dec()); - } - } - } - else - { - return detail::check_overflow(str.sub(1), detail::charconv_digits::min_value_dec()); - } - } - else if(str.str[0] == '0') - { - if (str.len == 1) - return false; - switch(str.str[1]) - { - case 'x': - case 'X': - { - size_t fno = str.first_not_of('0', 2); - if (fno == csubstr::npos) - return false; - const size_t len = str.len - fno; - return !((len < sizeof (T) * 2) || (len == sizeof(T) * 2 && str[fno] <= '7')); - } - case 'b': - case 'B': - { - size_t fno = str.first_not_of('0', 2); - if (fno == csubstr::npos) - return false; - return !(str.len <= fno + (sizeof(T) * 8 - 1)); - } - case 'o': - case 'O': - { - size_t fno = str.first_not_of('0', 2); - if(fno == csubstr::npos) - return false; - return detail::charconv_digits::is_oct_overflow(str.sub(fno)); - } - default: - { - size_t fno = str.first_not_of('0', 1); - if(fno == csubstr::npos) - return false; - return detail::check_overflow(str.sub(fno), detail::charconv_digits::max_value_dec()); - } - } - } - else - { - return detail::check_overflow(str, detail::charconv_digits::max_value_dec()); - } -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -namespace detail { - - -#if (!C4CORE_HAVE_STD_FROMCHARS) -/** @see http://www.exploringbinary.com/ for many good examples on float-str conversion */ -template -void get_real_format_str(char (& C4_RESTRICT fmt)[N], int precision, RealFormat_e formatting, const char* length_modifier="") -{ - int iret; - if(precision == -1) - iret = snprintf(fmt, sizeof(fmt), "%%%s%c", length_modifier, formatting); - else if(precision == 0) - iret = snprintf(fmt, sizeof(fmt), "%%.%s%c", length_modifier, formatting); - else - iret = snprintf(fmt, sizeof(fmt), "%%.%d%s%c", precision, length_modifier, formatting); - C4_ASSERT(iret >= 2 && size_t(iret) < sizeof(fmt)); - C4_UNUSED(iret); -} - - -/** @todo we're depending on snprintf()/sscanf() for converting to/from - * floating point numbers. Apparently, this increases the binary size - * by a considerable amount. There are some lightweight printf - * implementations: - * - * @see http://www.sparetimelabs.com/tinyprintf/tinyprintf.php (BSD) - * @see https://github.com/weiss/c99-snprintf - * @see https://github.com/nothings/stb/blob/master/stb_sprintf.h - * @see http://www.exploringbinary.com/ - * @see https://blog.benoitblanchon.fr/lightweight-float-to-string/ - * @see http://www.ryanjuckett.com/programming/printing-floating-point-numbers/ - */ -template -size_t print_one(substr str, const char* full_fmt, T v) -{ -#ifdef _MSC_VER - /** use _snprintf() to prevent early termination of the output - * for writing the null character at the last position - * @see https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx */ - int iret = _snprintf(str.str, str.len, full_fmt, v); - if(iret < 0) - { - /* when buf.len is not enough, VS returns a negative value. - * so call it again with a negative value for getting an - * actual length of the string */ - iret = snprintf(nullptr, 0, full_fmt, v); - C4_ASSERT(iret > 0); - } - size_t ret = (size_t) iret; - return ret; -#else - int iret = snprintf(str.str, str.len, full_fmt, v); - C4_ASSERT(iret >= 0); - size_t ret = (size_t) iret; - if(ret >= str.len) - ++ret; /* snprintf() reserves the last character to write \0 */ - return ret; -#endif -} -#endif // (!C4CORE_HAVE_STD_FROMCHARS) - - -#if (!C4CORE_HAVE_STD_FROMCHARS) && (!C4CORE_HAVE_FAST_FLOAT) -/** scans a string using the given type format, while at the same time - * allowing non-null-terminated strings AND guaranteeing that the given - * string length is strictly respected, so that no buffer overflows - * might occur. */ -template -inline size_t scan_one(csubstr str, const char *type_fmt, T *v) -{ - /* snscanf() is absolutely needed here as we must be sure that - * str.len is strictly respected, because substr is - * generally not null-terminated. - * - * Alas, there is no snscanf(). - * - * So we fake it by using a dynamic format with an explicit - * field size set to the length of the given span. - * This trick is taken from: - * https://stackoverflow.com/a/18368910/5875572 */ - - /* this is the actual format we'll use for scanning */ - char fmt[16]; - - /* write the length into it. Eg "%12f". - * Also, get the number of characters read from the string. - * So the final format ends up as "%12f%n"*/ - int iret = std::snprintf(fmt, sizeof(fmt), "%%" "%zu" "%s" "%%n", str.len, type_fmt); - /* no nasty surprises, please! */ - C4_ASSERT(iret >= 0 && size_t(iret) < C4_COUNTOF(fmt)); - - /* now we scan with confidence that the span length is respected */ - int num_chars; - iret = std::sscanf(str.str, fmt, v, &num_chars); - /* scanf returns the number of successful conversions */ - if(iret != 1) return csubstr::npos; - C4_ASSERT(num_chars >= 0); - return (size_t)(num_chars); -} -#endif // (!C4CORE_HAVE_STD_FROMCHARS) && (!C4CORE_HAVE_FAST_FLOAT) - - -#if C4CORE_HAVE_STD_TOCHARS -template -C4_ALWAYS_INLINE size_t rtoa(substr buf, T v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept -{ - std::to_chars_result result; - size_t pos = 0; - if(formatting == FTOA_HEXA) - { - if(buf.len > size_t(2)) - { - buf.str[0] = '0'; - buf.str[1] = 'x'; - } - pos += size_t(2); - } - if(precision == -1) - result = std::to_chars(buf.str + pos, buf.str + buf.len, v, (std::chars_format)formatting); - else - result = std::to_chars(buf.str + pos, buf.str + buf.len, v, (std::chars_format)formatting, precision); - if(result.ec == std::errc()) - { - // all good, no errors. - C4_ASSERT(result.ptr >= buf.str); - ptrdiff_t delta = result.ptr - buf.str; - return static_cast(delta); - } - C4_ASSERT(result.ec == std::errc::value_too_large); - // This is unfortunate. - // - // When the result can't fit in the given buffer, - // std::to_chars() returns the end pointer it was originally - // given, which is useless because here we would like to know - // _exactly_ how many characters the buffer must have to fit - // the result. - // - // So we take the pessimistic view, and assume as many digits - // as could ever be required: - size_t ret = static_cast(std::numeric_limits::max_digits10); - return ret > buf.len ? ret : buf.len + 1; -} -#endif // C4CORE_HAVE_STD_TOCHARS - - -#if C4CORE_HAVE_FAST_FLOAT -template -C4_ALWAYS_INLINE bool scan_rhex(csubstr s, T *C4_RESTRICT val) noexcept -{ - C4_ASSERT(s.len > 0); - C4_ASSERT(s.str[0] != '-'); - C4_ASSERT(s.str[0] != '+'); - C4_ASSERT(!s.begins_with("0x")); - C4_ASSERT(!s.begins_with("0X")); - size_t pos = 0; - // integer part - for( ; pos < s.len; ++pos) - { - const char c = s.str[pos]; - if(c >= '0' && c <= '9') - *val = *val * T(16) + T(c - '0'); - else if(c >= 'a' && c <= 'f') - *val = *val * T(16) + T(c - 'a'); - else if(c >= 'A' && c <= 'F') - *val = *val * T(16) + T(c - 'A'); - else if(c == '.') - { - ++pos; - break; // follow on to mantissa - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power; // no mantissa given, jump to power // NOLINT - } - else - { - return false; - } - } - // mantissa - { - // 0.0625 == 1/16 == value of first digit after the comma - for(T digit = T(0.0625); pos < s.len; ++pos, digit /= T(16)) // NOLINT - { - const char c = s.str[pos]; - if(c >= '0' && c <= '9') - *val += digit * T(c - '0'); - else if(c >= 'a' && c <= 'f') - *val += digit * T(c - 'a'); - else if(c >= 'A' && c <= 'F') - *val += digit * T(c - 'A'); - else if(c == 'p' || c == 'P') - { - ++pos; - goto power; // mantissa finished, jump to power // NOLINT - } - else - { - return false; - } - } - } - return true; -power: - if(C4_LIKELY(pos < s.len)) - { - if(s.str[pos] == '+') // atoi() cannot handle a leading '+' - ++pos; - if(C4_LIKELY(pos < s.len)) - { - int16_t powval = {}; - if(C4_LIKELY(atoi(s.sub(pos), &powval))) - { - *val *= ipow(powval); - return true; - } - } - } - return false; -} -#endif - -} // namespace detail -/** @endcond */ - - -#undef _c4appendhex -#undef _c4append - - -/** @defgroup doc_ftoa ftoa: float32 to chars - * - * @{ */ - -/** Convert a single-precision real number to string. The string will - * in general be NOT null-terminated. For FTOA_FLEX, \p precision is - * the number of significand digits. Otherwise \p precision is the - * number of decimals. It is safe to call this function with an empty - * or too-small buffer. - * - * @return the size of the buffer needed to write the number - */ -C4_ALWAYS_INLINE size_t ftoa(substr str, float v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept -{ -#if C4CORE_HAVE_STD_TOCHARS - return detail::rtoa(str, v, precision, formatting); -#else - char fmt[16]; - detail::get_real_format_str(fmt, precision, formatting, /*length_modifier*/""); - return detail::print_one(str, fmt, v); -#endif -} - -/** @} */ - - -/** @defgroup doc_dtoa dtoa: float64 to chars - * - * @{ */ - -/** Convert a double-precision real number to string. The string will - * in general be NOT null-terminated. For FTOA_FLEX, \p precision is - * the number of significand digits. Otherwise \p precision is the - * number of decimals. It is safe to call this function with an empty - * or too-small buffer. - * - * @return the size of the buffer needed to write the number - */ -C4_ALWAYS_INLINE size_t dtoa(substr str, double v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept -{ -#if C4CORE_HAVE_STD_TOCHARS - return detail::rtoa(str, v, precision, formatting); -#else - char fmt[16]; - detail::get_real_format_str(fmt, precision, formatting, /*length_modifier*/"l"); - return detail::print_one(str, fmt, v); -#endif -} - -/** @} */ - - -/** @defgroup doc_atof atof: chars to float32 - * - * @{ */ - -/** Convert a string to a single precision real number. - * The input string must be trimmed to the value, ie - * no leading or trailing whitespace can be present. - * @return true iff the conversion succeeded - * @see atof_first() if the string is not trimmed - */ -C4_ALWAYS_INLINE bool atof(csubstr str, float * C4_RESTRICT v) noexcept -{ - C4_ASSERT(str.len > 0); - C4_ASSERT(str.triml(" \r\t\n").len == str.len); -#if C4CORE_HAVE_FAST_FLOAT - // fastfloat cannot parse hexadecimal floats - bool isneg = (str.str[0] == '-'); - csubstr rem = str.sub(isneg || str.str[0] == '+'); - if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X')))) - { - fast_float::from_chars_result result; - result = fast_float::from_chars(str.str, str.str + str.len, *v); - return result.ec == std::errc(); - } - else if(detail::scan_rhex(rem.sub(2), v)) - { - *v *= isneg ? -1.f : 1.f; - return true; - } - return false; -#elif C4CORE_HAVE_STD_FROMCHARS - std::from_chars_result result; - result = std::from_chars(str.str, str.str + str.len, *v); - return result.ec == std::errc(); -#else - csubstr rem = str.sub(str.str[0] == '-' || str.str[0] == '+'); - if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X')))) - return detail::scan_one(str, "f", v) != csubstr::npos; - else - return detail::scan_one(str, "a", v) != csubstr::npos; -#endif -} - - -/** Convert a string to a single precision real number. - * Leading whitespace is skipped until valid characters are found. - * @return the number of characters read from the string, or npos if - * conversion was not successful or if the string was empty */ -inline size_t atof_first(csubstr str, float * C4_RESTRICT v) noexcept -{ - csubstr trimmed = str.first_real_span(); - if(trimmed.len == 0) - return csubstr::npos; - if(atof(trimmed, v)) - return static_cast(trimmed.end() - str.begin()); - return csubstr::npos; -} - -/** @} */ - - -/** @defgroup doc_atod atod: chars to float64 - * - * @{ */ - -/** Convert a string to a double precision real number. - * The input string must be trimmed to the value, ie - * no leading or trailing whitespace can be present. - * @return true iff the conversion succeeded - * @see atod_first() if the string is not trimmed - */ -C4_ALWAYS_INLINE bool atod(csubstr str, double * C4_RESTRICT v) noexcept -{ - C4_ASSERT(str.len > 0); - C4_ASSERT(str.triml(" \r\t\n").len == str.len); -#if C4CORE_HAVE_FAST_FLOAT - // fastfloat cannot parse hexadecimal floats - bool isneg = (str.str[0] == '-'); - csubstr rem = str.sub(isneg || str.str[0] == '+'); - if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X')))) - { - fast_float::from_chars_result result; - result = fast_float::from_chars(str.str, str.str + str.len, *v); - return result.ec == std::errc(); - } - else if(detail::scan_rhex(rem.sub(2), v)) - { - *v *= isneg ? -1. : 1.; - return true; - } - return false; -#elif C4CORE_HAVE_STD_FROMCHARS - std::from_chars_result result; - result = std::from_chars(str.str, str.str + str.len, *v); - return result.ec == std::errc(); -#else - csubstr rem = str.sub(str.str[0] == '-' || str.str[0] == '+'); - if(!(rem.len >= 2 && (rem.str[0] == '0' && (rem.str[1] == 'x' || rem.str[1] == 'X')))) - return detail::scan_one(str, "lf", v) != csubstr::npos; - else - return detail::scan_one(str, "la", v) != csubstr::npos; -#endif -} - - -/** Convert a string to a double precision real number. - * Leading whitespace is skipped until valid characters are found. - * @return the number of characters read from the string, or npos if - * conversion was not successful or if the string was empty */ -inline size_t atod_first(csubstr str, double * C4_RESTRICT v) noexcept -{ - csubstr trimmed = str.first_real_span(); - if(trimmed.len == 0) - return csubstr::npos; - if(atod(trimmed, v)) - return static_cast(trimmed.end() - str.begin()); - return csubstr::npos; -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// generic versions - -/** @cond dev */ -// on some platforms, (unsigned) int and (unsigned) long -// are not any of the fixed length types above -#define _C4_IF_NOT_FIXED_LENGTH_I(T, ty) typename std::enable_if::value && !is_fixed_length::value_i, ty> -#define _C4_IF_NOT_FIXED_LENGTH_U(T, ty) typename std::enable_if::value && !is_fixed_length::value_u, ty> -/** @endcond*/ - - -/** @defgroup doc_xtoa xtoa: generic value to chars - * - * Dispatches to the most appropriate and efficient conversion - * function - * - * @{ */ -C4_ALWAYS_INLINE size_t xtoa(substr s, uint8_t v) noexcept { return write_dec(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint16_t v) noexcept { return write_dec(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint32_t v) noexcept { return write_dec(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint64_t v) noexcept { return write_dec(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int8_t v) noexcept { return itoa(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int16_t v) noexcept { return itoa(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int32_t v) noexcept { return itoa(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int64_t v) noexcept { return itoa(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, float v) noexcept { return ftoa(s, v); } -C4_ALWAYS_INLINE size_t xtoa(substr s, double v) noexcept { return dtoa(s, v); } - -C4_ALWAYS_INLINE size_t xtoa(substr s, uint8_t v, uint8_t radix) noexcept { return utoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint16_t v, uint16_t radix) noexcept { return utoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint32_t v, uint32_t radix) noexcept { return utoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint64_t v, uint64_t radix) noexcept { return utoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int8_t v, int8_t radix) noexcept { return itoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int16_t v, int16_t radix) noexcept { return itoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int32_t v, int32_t radix) noexcept { return itoa(s, v, radix); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int64_t v, int64_t radix) noexcept { return itoa(s, v, radix); } - -C4_ALWAYS_INLINE size_t xtoa(substr s, uint8_t v, uint8_t radix, size_t num_digits) noexcept { return utoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint16_t v, uint16_t radix, size_t num_digits) noexcept { return utoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint32_t v, uint32_t radix, size_t num_digits) noexcept { return utoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, uint64_t v, uint64_t radix, size_t num_digits) noexcept { return utoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int8_t v, int8_t radix, size_t num_digits) noexcept { return itoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int16_t v, int16_t radix, size_t num_digits) noexcept { return itoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int32_t v, int32_t radix, size_t num_digits) noexcept { return itoa(s, v, radix, num_digits); } -C4_ALWAYS_INLINE size_t xtoa(substr s, int64_t v, int64_t radix, size_t num_digits) noexcept { return itoa(s, v, radix, num_digits); } - -C4_ALWAYS_INLINE size_t xtoa(substr s, float v, int precision, RealFormat_e formatting=FTOA_FLEX) noexcept { return ftoa(s, v, precision, formatting); } -C4_ALWAYS_INLINE size_t xtoa(substr s, double v, int precision, RealFormat_e formatting=FTOA_FLEX) noexcept { return dtoa(s, v, precision, formatting); } - -template C4_ALWAYS_INLINE auto xtoa(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return itoa(buf, v); } -template C4_ALWAYS_INLINE auto xtoa(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return write_dec(buf, v); } -template -C4_ALWAYS_INLINE size_t xtoa(substr s, T *v) noexcept { return itoa(s, (intptr_t)v, (intptr_t)16); } - -/** @} */ - -/** @defgroup doc_atox atox: generic chars to value - * - * Dispatches to the most appropriate and efficient conversion - * function - * - * @{ */ - -C4_ALWAYS_INLINE bool atox(csubstr s, uint8_t *C4_RESTRICT v) noexcept { return atou(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, uint16_t *C4_RESTRICT v) noexcept { return atou(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, uint32_t *C4_RESTRICT v) noexcept { return atou(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, uint64_t *C4_RESTRICT v) noexcept { return atou(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, int8_t *C4_RESTRICT v) noexcept { return atoi(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, int16_t *C4_RESTRICT v) noexcept { return atoi(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, int32_t *C4_RESTRICT v) noexcept { return atoi(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, int64_t *C4_RESTRICT v) noexcept { return atoi(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, float *C4_RESTRICT v) noexcept { return atof(s, v); } -C4_ALWAYS_INLINE bool atox(csubstr s, double *C4_RESTRICT v) noexcept { return atod(s, v); } - -template C4_ALWAYS_INLINE auto atox(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, bool)::type { return atoi(buf, v); } -template C4_ALWAYS_INLINE auto atox(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, bool)::type { return atou(buf, v); } -template -C4_ALWAYS_INLINE bool atox(csubstr s, T **v) noexcept { intptr_t tmp; bool ret = atox(s, &tmp); if(ret) { *v = (T*)tmp; } return ret; } - -/** @} */ - - -/** @defgroup doc_to_chars to_chars: generalized chars to value - * - * Convert the given value, writing into the string. The resulting - * string will NOT be null-terminated. Return the number of - * characters needed. This function is safe to call when the string - * is too small - no writes will occur beyond the string's last - * character. - * - * Dispatches to the most appropriate and efficient conversion - * function. - * - * @see write_dec, doc_utoa, doc_itoa, doc_ftoa, doc_dtoa - * - * @warning When serializing floating point values (float or double), - * be aware that because it uses defaults, to_chars() may cause a - * truncation of the precision. To enforce a particular precision, use - * for example @ref c4::fmt::real, or call directly @ref c4::ftoa or - * @ref c4::dtoa. - * - * @{ */ - -C4_ALWAYS_INLINE size_t to_chars(substr buf, uint8_t v) noexcept { return write_dec(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, uint16_t v) noexcept { return write_dec(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, uint32_t v) noexcept { return write_dec(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, uint64_t v) noexcept { return write_dec(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, int8_t v) noexcept { return itoa(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, int16_t v) noexcept { return itoa(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, int32_t v) noexcept { return itoa(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, int64_t v) noexcept { return itoa(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, float v) noexcept { return ftoa(buf, v); } -C4_ALWAYS_INLINE size_t to_chars(substr buf, double v) noexcept { return dtoa(buf, v); } - -template C4_ALWAYS_INLINE auto to_chars(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return itoa(buf, v); } -template C4_ALWAYS_INLINE auto to_chars(substr buf, T v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return write_dec(buf, v); } -template -C4_ALWAYS_INLINE size_t to_chars(substr s, T *v) noexcept { return itoa(s, (intptr_t)v, (intptr_t)16); } - -/** @} */ - - -/** @defgroup doc_from_chars from_chars: generalized chars to value - * - * Read a value from the string, which must be trimmed to the value - * (ie, no leading/trailing whitespace). return true if the - * conversion succeeded. There is no check for overflow; the value - * wraps around in a way similar to the standard C/C++ overflow - * behavior. For example, from_chars("128", &val) returns true - * and val will be set tot 0. See @ref doc_overflows and @ref - * doc_overflow_checked for facilities enforcing no-overflow. - * - * Dispatches to the most appropriate and efficient conversion - * function - * - * @see doc_from_chars_first, atou, atoi, atof, atod - * @{ */ - -C4_ALWAYS_INLINE bool from_chars(csubstr buf, uint8_t *C4_RESTRICT v) noexcept { return atou(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, uint16_t *C4_RESTRICT v) noexcept { return atou(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, uint32_t *C4_RESTRICT v) noexcept { return atou(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, uint64_t *C4_RESTRICT v) noexcept { return atou(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, int8_t *C4_RESTRICT v) noexcept { return atoi(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, int16_t *C4_RESTRICT v) noexcept { return atoi(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, int32_t *C4_RESTRICT v) noexcept { return atoi(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, int64_t *C4_RESTRICT v) noexcept { return atoi(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, float *C4_RESTRICT v) noexcept { return atof(buf, v); } -C4_ALWAYS_INLINE bool from_chars(csubstr buf, double *C4_RESTRICT v) noexcept { return atod(buf, v); } - -template C4_ALWAYS_INLINE auto from_chars(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, bool)::type { return atoi(buf, v); } -template C4_ALWAYS_INLINE auto from_chars(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, bool)::type { return atou(buf, v); } -template -C4_ALWAYS_INLINE bool from_chars(csubstr buf, T **v) noexcept { intptr_t tmp; bool ret = from_chars(buf, &tmp); if(ret) { *v = (T*)tmp; } return ret; } - -/** @defgroup doc_from_chars_first from_chars_first: generalized chars to value - * - * Read the first valid sequence of characters from the string, - * skipping leading whitespace, and convert it using @ref doc_from_chars . - * Return the number of characters read for converting. - * - * Dispatches to the most appropriate and efficient conversion - * function. - * - * @see atou_first, atoi_first, atof_first, atod_first - * @{ */ - -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, uint8_t *C4_RESTRICT v) noexcept { return atou_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, uint16_t *C4_RESTRICT v) noexcept { return atou_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, uint32_t *C4_RESTRICT v) noexcept { return atou_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, uint64_t *C4_RESTRICT v) noexcept { return atou_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, int8_t *C4_RESTRICT v) noexcept { return atoi_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, int16_t *C4_RESTRICT v) noexcept { return atoi_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, int32_t *C4_RESTRICT v) noexcept { return atoi_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, int64_t *C4_RESTRICT v) noexcept { return atoi_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, float *C4_RESTRICT v) noexcept { return atof_first(buf, v); } -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, double *C4_RESTRICT v) noexcept { return atod_first(buf, v); } - -template C4_ALWAYS_INLINE auto from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_I(T, size_t)::type { return atoi_first(buf, v); } -template C4_ALWAYS_INLINE auto from_chars_first(csubstr buf, T *C4_RESTRICT v) noexcept -> _C4_IF_NOT_FIXED_LENGTH_U(T, size_t)::type { return atou_first(buf, v); } -template -C4_ALWAYS_INLINE size_t from_chars_first(csubstr buf, T **v) noexcept { intptr_t tmp; bool ret = from_chars_first(buf, &tmp); if(ret) { *v = (T*)tmp; } return ret; } - -/** @} */ - -/** @} */ - -#undef _C4_IF_NOT_FIXED_LENGTH_I -#undef _C4_IF_NOT_FIXED_LENGTH_U - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/** call to_chars() and return a substr consisting of the - * written portion of the input buffer. Ie, same as to_chars(), - * but return a substr instead of a size_t. - * Convert the given value to a string using to_chars(), and - * return the resulting string, up to and including the last - * written character. - * @ingroup doc_to_chars - * @see to_chars() */ -template -C4_ALWAYS_INLINE substr to_chars_sub(substr buf, T const& C4_RESTRICT v) noexcept -{ - size_t sz = to_chars(buf, v); - return buf.left_of(sz <= buf.len ? sz : buf.len); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// bool implementation - -/** @ingroup doc_to_chars */ -C4_ALWAYS_INLINE size_t to_chars(substr buf, bool v) noexcept -{ - int val = v; - return to_chars(buf, val); -} - -/** @ingroup doc_from_chars */ -inline bool from_chars(csubstr buf, bool * C4_RESTRICT v) noexcept -{ - if(buf == '0') - { - *v = false; return true; - } - else if(buf == '1') - { - *v = true; return true; - } - else if(buf == "false") - { - *v = false; return true; - } - else if(buf == "true") - { - *v = true; return true; - } - else if(buf == "False") - { - *v = false; return true; - } - else if(buf == "True") - { - *v = true; return true; - } - else if(buf == "FALSE") - { - *v = false; return true; - } - else if(buf == "TRUE") - { - *v = true; return true; - } - // fallback to c-style int bools - int val = 0; - bool ret = from_chars(buf, &val); - if(C4_LIKELY(ret)) - { - *v = (val != 0); - } - return ret; -} - -/** @ingroup doc_from_chars_first */ -inline size_t from_chars_first(csubstr buf, bool * C4_RESTRICT v) noexcept -{ - csubstr trimmed = buf.first_non_empty_span(); - if(trimmed.len == 0 || !from_chars(buf, v)) - return csubstr::npos; - return trimmed.len; -} - - -//----------------------------------------------------------------------------- -// single-char implementation - -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, char v) noexcept -{ - if(buf.len > 0) - { - C4_XASSERT(buf.str); - buf.str[0] = v; - } - return 1; -} - -/** extract a single character from a substring - * @note to extract a string instead and not just a single character, use the csubstr overload - * @ingroup doc_from_chars - * */ -inline bool from_chars(csubstr buf, char * C4_RESTRICT v) noexcept -{ - if(buf.len != 1) - return false; - C4_XASSERT(buf.str); - *v = buf.str[0]; - return true; -} - -/** @ingroup doc_from_chars_first */ -inline size_t from_chars_first(csubstr buf, char * C4_RESTRICT v) noexcept -{ - if(buf.len < 1) - return csubstr::npos; - *v = buf.str[0]; - return 1; -} - - -//----------------------------------------------------------------------------- -// csubstr implementation - -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, csubstr v) noexcept -{ - C4_ASSERT(!buf.overlaps(v)); - size_t len = buf.len < v.len ? buf.len : v.len; - // 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(buf.str != nullptr); - C4_ASSERT(v.str != nullptr); - memcpy(buf.str, v.str, len); - } - return v.len; -} - -/** @ingroup doc_from_chars */ -inline bool from_chars(csubstr buf, csubstr *C4_RESTRICT v) noexcept -{ - *v = buf; - return true; -} - -/** @ingroup doc_from_chars_first */ -inline size_t from_chars_first(substr buf, csubstr * C4_RESTRICT v) noexcept -{ - csubstr trimmed = buf.first_non_empty_span(); - if(trimmed.len == 0) - return csubstr::npos; - *v = trimmed; - return static_cast(trimmed.end() - buf.begin()); -} - - -//----------------------------------------------------------------------------- -// substr - -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, substr v) noexcept -{ - C4_ASSERT(!buf.overlaps(v)); - size_t len = buf.len < v.len ? buf.len : v.len; - // 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(buf.str != nullptr); - C4_ASSERT(v.str != nullptr); - memcpy(buf.str, v.str, len); - } - return v.len; -} - -/** @ingroup doc_from_chars */ -inline bool from_chars(csubstr buf, substr * C4_RESTRICT v) noexcept -{ - C4_ASSERT(!buf.overlaps(*v)); - // is the destination buffer wide enough? - if(v->len >= buf.len) - { - // 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); - C4_ASSERT(v->str != nullptr); - memcpy(v->str, buf.str, buf.len); - } - v->len = buf.len; - return true; - } - return false; -} - -/** @ingroup doc_from_chars_first */ -inline size_t from_chars_first(csubstr buf, substr * C4_RESTRICT v) noexcept -{ - csubstr trimmed = buf.first_non_empty_span(); - C4_ASSERT(!trimmed.overlaps(*v)); - if(C4_UNLIKELY(trimmed.len == 0)) - return csubstr::npos; - size_t len = trimmed.len > v->len ? v->len : trimmed.len; - // 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(buf.str != nullptr); - C4_ASSERT(v->str != nullptr); - memcpy(v->str, trimmed.str, len); - } - if(C4_UNLIKELY(trimmed.len > v->len)) - return csubstr::npos; - return static_cast(trimmed.end() - buf.begin()); -} - - -//----------------------------------------------------------------------------- - -/** @ingroup doc_to_chars */ -template -inline size_t to_chars(substr buf, const char (& C4_RESTRICT v)[N]) noexcept -{ - csubstr sp(v); - return to_chars(buf, sp); -} - -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, const char * C4_RESTRICT v) noexcept -{ - return to_chars(buf, to_csubstr(v)); -} - -/** @} */ - -} // namespace c4 - -// NOLINTEND(hicpp-signed-bitwise) - -#if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(pop) -#elif defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -#endif /* _C4_CHARCONV_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/compiler.hpp b/3rdparty/rapidyaml/include/c4/compiler.hpp deleted file mode 100644 index 07c5e91aa3..0000000000 --- a/3rdparty/rapidyaml/include/c4/compiler.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/config.hpp b/3rdparty/rapidyaml/include/c4/config.hpp deleted file mode 100644 index bda8033b36..0000000000 --- a/3rdparty/rapidyaml/include/c4/config.hpp +++ /dev/null @@ -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_ diff --git a/3rdparty/rapidyaml/include/c4/cpu.hpp b/3rdparty/rapidyaml/include/c4/cpu.hpp deleted file mode 100644 index 2c156d2ee4..0000000000 --- a/3rdparty/rapidyaml/include/c4/cpu.hpp +++ /dev/null @@ -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++ -dM -E - = 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/dump.hpp b/3rdparty/rapidyaml/include/c4/dump.hpp deleted file mode 100644 index 1e3d15d4a3..0000000000 --- a/3rdparty/rapidyaml/include/c4/dump.hpp +++ /dev/null @@ -1,798 +0,0 @@ -#ifndef C4_DUMP_HPP_ -#define C4_DUMP_HPP_ - -#include - -/** @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 struct dump_directly : public std::false_type {}; -template<> struct dump_directly : public std::true_type {}; -template<> struct dump_directly< substr> : public std::true_type {}; -template<> struct dump_directly : public std::true_type {}; -template<> struct dump_directly< char*> : public std::true_type {}; -template struct dump_directly : public std::true_type {}; -template struct dump_directly< char (&)[N]> : public std::true_type {}; -template struct dump_directly : public std::true_type {}; -template 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 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 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 - */ -template -inline auto dump(substr buf, Arg const& a) - -> typename std::enable_if::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 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 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 - * */ -template -inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a) - -> typename std::enable_if::value, size_t>::type -{ - C4_UNUSED(buf); - C4_ASSERT(!buf.overlaps(a)); - // dump directly, no need to serialize to the buffer - std::forward(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 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 to a true type. - * - * @see dump_directly - * - * @return the number of characters required to serialize the - * argument. */ -template -inline auto dump(substr buf, Arg const& a) - -> typename std::enable_if::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 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 to a true type. - * - * @see @ref dump_directly - * - * @return the number of characters required to serialize the - * argument. */ -template -inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a) - -> typename std::enable_if::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)(buf.first(sz)); - // ... but do this instead: - std::forward(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 -size_t cat_dump(SinkFn &&, substr) // NOLINT -{ - return 0; -} - -// terminates the variadic recursion -template -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 -size_t cat_dump(SinkFn &&sinkfn, substr buf, Arg const& a, Args const& ...more) -{ - const size_t size_for_a = dump(std::forward(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), 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 -size_t cat_dump(substr buf, Arg const& a, Args const& ...more) -{ - const size_t size_for_a = dump(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(buf, more...); - return size_for_more > size_for_a ? size_for_more : size_for_a; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/// @cond dev -namespace detail { - -// terminates the variadic recursion -template -C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, DumpResults results, substr) -{ - return results; -} - -// terminates the variadic recursion -template -C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, SinkFn &&, DumpResults results, substr) // NOLINT -{ - return results; -} - -template -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(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, results, buf, more...); -} - -template -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), 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), results, buf, more...); -} -} // namespace detail -/// @endcond - - -template -C4_ALWAYS_INLINE DumpResults cat_dump_resume(substr buf, Arg const& C4_RESTRICT a, Args const& ...more) -{ - return detail::cat_dump_resume(0u, DumpResults{}, buf, a, more...); -} - -template -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), DumpResults{}, buf, a, more...); -} - - -template -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(0u, results, buf, a, more...); -} - -template -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), results, buf, a, more...); -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/// @cond dev -// terminate the recursion -template -size_t catsep_dump(SinkFn &&, substr, Sep const& C4_RESTRICT) // NOLINT -{ - return 0; -} - -// terminate the recursion -template -size_t catsep_dump(substr, Sep const& C4_RESTRICT) // NOLINT -{ - return 0; -} -/// @endcond - -/** take the function pointer as a function argument */ -template -size_t catsep_dump(SinkFn &&sinkfn, substr buf, Sep const& sep, Arg const& a, Args const& ...more) -{ - size_t sz = dump(std::forward(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), 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), buf, sep, more...); - return size_for_more > sz ? size_for_more : sz; -} - -/** take the function pointer as a template argument */ -template -size_t catsep_dump(substr buf, Sep const& sep, Arg const& a, Args const& ...more) -{ - size_t sz = dump(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(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(buf, sep, more...); - return size_for_more > sz ? size_for_more : sz; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/// @cond dev -namespace detail { -template -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(*buf, a); - results->bufsize = sz > results->bufsize ? sz : results->bufsize; - if(C4_LIKELY(sz <= buf->len)) - results->lastok = currarg; - else - buf->len = 0; - } -} - -template -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), *buf, a); - results->bufsize = sz > results->bufsize ? sz : results->bufsize; - if(C4_LIKELY(sz <= buf->len)) - results->lastok = currarg; - else - buf->len = 0; - } -} - -template -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_(currarg, results, buf, a); -} - -template -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), results, buf, a); -} - -template -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_(currarg , results, buf, a); - detail::catsep_dump_resume_(currarg + 1u, results, buf, sep); - detail::catsep_dump_resume (currarg + 2u, results, buf, sep, more...); -} - -template -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), results, buf, a); - detail::catsep_dump_resume_(currarg + 1u, std::forward(sinkfn), results, buf, sep); - detail::catsep_dump_resume (currarg + 2u, std::forward(sinkfn), results, buf, sep, more...); -} -} // namespace detail -/// @endcond - - -template -C4_ALWAYS_INLINE DumpResults catsep_dump_resume(substr buf, Sep const& sep, Args const& ...args) -{ - DumpResults results; - detail::catsep_dump_resume(0u, &results, &buf, sep, args...); - return results; -} - -template -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), &results, &buf, sep, args...); - return results; -} - - -template -C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumpResults results, substr buf, Sep const& sep, Args const& ...args) -{ - detail::catsep_dump_resume(0u, &results, &buf, sep, args...); - return results; -} - -template -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), &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 -C4_ALWAYS_INLINE auto _format_dump_compute_size(T const&) - -> typename std::enable_if::value, size_t>::type -{ - return 0u; // no buffer needed -} -template -C4_ALWAYS_INLINE auto _format_dump_compute_size(T const& v) - -> typename std::enable_if::value, size_t>::type -{ - return to_chars(substr{}, v); -} -template -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 -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)(fmt); - return 0u; -} -// terminate the recursion -/** take the function pointer as a template argument */ -template -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 -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)(fmt); - return 0u; - } - std::forward(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), 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), 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 -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(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(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 -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 -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)(fmt); - results.lastok = currarg; - } - return results; -} - -template -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(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(currarg + 2u, results, buf, fmt.sub(pos + 2), more...); -} - - -template -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)(fmt.first(pos)); - results.lastok = currarg; - } - if(C4_LIKELY(results.write_arg(currarg + 1u))) - { - const size_t len = dump(std::forward(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)(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), results, buf, fmt.sub(pos + 2), more...); -} -} // namespace detail -/// @endcond - - -template -C4_ALWAYS_INLINE DumpResults format_dump_resume(substr buf, csubstr fmt, Args const& ...args) -{ - return detail::format_dump_resume(0u, DumpResults{}, buf, fmt, args...); -} - -template -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), DumpResults{}, buf, fmt, args...); -} - - -template -C4_ALWAYS_INLINE DumpResults format_dump_resume(DumpResults results, substr buf, csubstr fmt, Args const& ...args) -{ - return detail::format_dump_resume(0u, results, buf, fmt, args...); -} - -template -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), results, buf, fmt, args...); -} - -C4_SUPPRESS_WARNING_GCC_CLANG_POP - -} // namespace c4 - - -#endif /* C4_DUMP_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/error.hpp b/3rdparty/rapidyaml/include/c4/error.hpp deleted file mode 100644 index d64f96140f..0000000000 --- a/3rdparty/rapidyaml/include/c4/error.hpp +++ /dev/null @@ -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::value, errmsg) - - -//----------------------------------------------------------------------------- - -#define C4_ASSERT_SAME_TYPE(ty1, ty2) \ - C4_STATIC_ASSERT(std::is_same::value) - -#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \ - C4_STATIC_ASSERT( ! std::is_same::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 -# 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/export.hpp b/3rdparty/rapidyaml/include/c4/export.hpp deleted file mode 100644 index ffd02482f9..0000000000 --- a/3rdparty/rapidyaml/include/c4/export.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/format.hpp b/3rdparty/rapidyaml/include/c4/format.hpp deleted file mode 100644 index 11da4992f6..0000000000 --- a/3rdparty/rapidyaml/include/c4/format.hpp +++ /dev/null @@ -1,1058 +0,0 @@ -#ifndef _C4_FORMAT_HPP_ -#define _C4_FORMAT_HPP_ - -/** @file format.hpp provides type-safe facilities for formatting arguments - * to string buffers */ - -#include "c4/charconv.hpp" -#include "c4/blob.hpp" - - -#if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(push) -# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017 -# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) -# endif -# pragma warning(disable: 4996) // snprintf/scanf: this function or variable may be unsafe -#elif defined(__clang__) -# pragma clang diagnostic push -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wuseless-cast" -#endif -// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast,*avoid-goto*) - -/** @defgroup doc_format_utils Format utilities - * - * @brief Provides generic and type-safe formatting/scanning utilities - * built on top of @ref doc_to_chars() and @ref doc_from_chars, - * forwarding the arguments to these functions, which in turn use the - * @ref doc_charconv utilities. Like @ref doc_charconv, the formatting - * facilities are very efficient and many times faster than printf(). - * - * @see [a formatting sample in rapidyaml's docs](https://rapidyaml.readthedocs.io/latest/doxygen/group__doc__quickstart.html#gac2425b515eb552589708cfff70c52b14) - * */ - -/** @defgroup doc_format_specifiers Format specifiers - * - * @brief Format specifiers are tag types and functions that are used - * together with @ref doc_to_chars and @ref doc_from_chars - * - * @see [a formatting sample in rapidyaml's docs](https://rapidyaml.readthedocs.io/latest/doxygen/group__doc__quickstart.html#gac2425b515eb552589708cfff70c52b14) - * @ingroup doc_format_utils */ - -namespace c4 { - -/** @addtogroup doc_format_utils - * @{ */ - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// formatting truthy types as booleans - -namespace fmt { - -/** @addtogroup doc_format_specifiers - * @{ */ - -/** @defgroup doc_boolean_specifiers boolean specifiers - * @{ */ - -/** write a variable as an alphabetic boolean, ie as either true or false - * @param strict_read */ -template -struct boolalpha_ -{ - boolalpha_(T val_, bool strict_read_=false) : val(val_ ? true : false), strict_read(strict_read_) {} - bool val; - bool strict_read; -}; - -template -boolalpha_ boolalpha(T const& val, bool strict_read=false) -{ - return boolalpha_(val, strict_read); -} - -/** @} */ - -/** @} */ - -} // namespace fmt - -/** write a variable as an alphabetic boolean, ie as either true or - * false - * @ingroup doc_to_chars */ -template -inline size_t to_chars(substr buf, fmt::boolalpha_ fmt) -{ - return to_chars(buf, fmt.val ? "true" : "false"); -} - - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// formatting integral types - -namespace fmt { - -/** @addtogroup doc_format_specifiers - * @{ */ - -/** @defgroup doc_integer_specifiers Integer specifiers - * @{ */ - -/** format an integral type with a custom radix */ -template -struct integral_ -{ - C4_STATIC_ASSERT(std::is_integral::value); - T val; - T radix; - C4_ALWAYS_INLINE integral_(T val_, T radix_) : val(val_), radix(radix_) {} -}; - -/** format an integral type with a custom radix, and pad with zeroes on the left */ -template -struct integral_padded_ -{ - C4_STATIC_ASSERT(std::is_integral::value); - T val; - T radix; - size_t num_digits; - C4_ALWAYS_INLINE integral_padded_(T val_, T radix_, size_t nd) : val(val_), radix(radix_), num_digits(nd) {} -}; - - -/** format an integral type with a custom radix */ -template -C4_ALWAYS_INLINE integral_ integral(T val, T radix=10) -{ - return integral_(val, radix); -} -/** format an integral type with a custom radix */ -template -C4_ALWAYS_INLINE integral_ integral(T const* val, T radix=10) -{ - return integral_(reinterpret_cast(val), static_cast(radix)); -} -/** format an integral type with a custom radix */ -template -C4_ALWAYS_INLINE integral_ integral(std::nullptr_t, T radix=10) -{ - return integral_(intptr_t(0), static_cast(radix)); -} - - -/** format the pointer as an hexadecimal value */ -template -inline integral_ hex(T * v) -{ - return integral_(reinterpret_cast(v), intptr_t(16)); -} -/** format the pointer as an hexadecimal value */ -template -inline integral_ hex(T const* v) -{ - return integral_(reinterpret_cast(v), intptr_t(16)); -} -/** format null as an hexadecimal value - * @overload hex */ -inline integral_ hex(std::nullptr_t) -{ - return integral_(0, intptr_t(16)); -} -/** format the integral_ argument as an hexadecimal value - * @overload hex */ -template -inline integral_ hex(T v) -{ - return integral_(v, T(16)); -} - -/** format the pointer as an octal value */ -template -inline integral_ oct(T const* v) -{ - return integral_(reinterpret_cast(v), intptr_t(8)); -} -/** format the pointer as an octal value */ -template -inline integral_ oct(T * v) -{ - return integral_(reinterpret_cast(v), intptr_t(8)); -} -/** format null as an octal value */ -inline integral_ oct(std::nullptr_t) -{ - return integral_(intptr_t(0), intptr_t(8)); -} -/** format the integral_ argument as an octal value */ -template -inline integral_ oct(T v) -{ - return integral_(v, T(8)); -} - -/** format the pointer as a binary 0-1 value - * @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */ -template -inline integral_ bin(T const* v) -{ - return integral_(reinterpret_cast(v), intptr_t(2)); -} -/** format the pointer as a binary 0-1 value - * @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */ -template -inline integral_ bin(T * v) -{ - return integral_(reinterpret_cast(v), intptr_t(2)); -} -/** format null as a binary 0-1 value - * @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */ -inline integral_ bin(std::nullptr_t) -{ - return integral_(intptr_t(0), intptr_t(2)); -} -/** format the integral_ argument as a binary 0-1 value - * @see c4::raw() if you want to use a raw memcpy-based binary dump instead of 0-1 formatting */ -template -inline integral_ bin(T v) -{ - return integral_(v, T(2)); -} - -/** @} */ // integer_specifiers - - -/** @defgroup doc_zpad Pad the number with zeroes on the left - * @{ */ - -/** pad the argument with zeroes on the left, with decimal radix */ -template -C4_ALWAYS_INLINE integral_padded_ zpad(T val, size_t num_digits) -{ - return integral_padded_(val, T(10), num_digits); -} -/** pad the argument with zeroes on the left */ -template -C4_ALWAYS_INLINE integral_padded_ zpad(integral_ val, size_t num_digits) -{ - return integral_padded_(val.val, val.radix, num_digits); -} -/** pad the argument with zeroes on the left */ -C4_ALWAYS_INLINE integral_padded_ zpad(std::nullptr_t, size_t num_digits) -{ - return integral_padded_(0, 16, num_digits); -} -/** pad the argument with zeroes on the left */ -template -C4_ALWAYS_INLINE integral_padded_ zpad(T const* val, size_t num_digits) -{ - return integral_padded_(reinterpret_cast(val), 16, num_digits); -} -template -C4_ALWAYS_INLINE integral_padded_ zpad(T * val, size_t num_digits) -{ - return integral_padded_(reinterpret_cast(val), 16, num_digits); -} - -/** @} */ // zpad - - -/** @defgroup doc_overflow_checked Check read for overflow - * @{ */ - -template -struct overflow_checked_ -{ - static_assert(std::is_integral::value, "range checking only for integral types"); - C4_ALWAYS_INLINE overflow_checked_(T &val_) : val(&val_) {} - T *val; -}; -template -C4_ALWAYS_INLINE overflow_checked_ overflow_checked(T &val) -{ - return overflow_checked_(val); -} - -/** @} */ // overflow_checked - -/** @} */ // format_specifiers - - -} // namespace fmt - -/** format an integer signed type - * @ingroup doc_to_chars */ -template -C4_ALWAYS_INLINE -typename std::enable_if::value, size_t>::type -to_chars(substr buf, fmt::integral_ fmt) -{ - return itoa(buf, fmt.val, fmt.radix); -} -/** format an integer signed type, pad with zeroes - * @ingroup doc_to_chars */ -template -C4_ALWAYS_INLINE -typename std::enable_if::value, size_t>::type -to_chars(substr buf, fmt::integral_padded_ fmt) -{ - return itoa(buf, fmt.val, fmt.radix, fmt.num_digits); -} - -/** format an integer unsigned type - * @ingroup doc_to_chars */ -template -C4_ALWAYS_INLINE -typename std::enable_if::value, size_t>::type -to_chars(substr buf, fmt::integral_ fmt) -{ - return utoa(buf, fmt.val, fmt.radix); -} -/** format an integer unsigned type, pad with zeroes - * @ingroup doc_to_chars */ -template -C4_ALWAYS_INLINE -typename std::enable_if::value, size_t>::type -to_chars(substr buf, fmt::integral_padded_ fmt) -{ - return utoa(buf, fmt.val, fmt.radix, fmt.num_digits); -} - -/** read an integer type, detecting overflow (returns false on overflow) - * @ingroup doc_from_chars */ -template -C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_ wrapper) -{ - if(C4_LIKELY(!overflows(s))) - return atox(s, wrapper.val); - return false; -} -/** read an integer type, detecting overflow (returns false on overflow) - * @ingroup doc_from_chars */ -template -C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_ *wrapper) -{ - if(C4_LIKELY(!overflows(s))) - return atox(s, wrapper->val); - return false; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// formatting real types - -namespace fmt { - -/** @addtogroup doc_format_specifiers - * @{ */ - -/** @defgroup doc_real_specifiers Real specifiers - * @{ */ - -template -struct real_ -{ - T val; - int precision; - RealFormat_e fmt; - real_(T v, int prec=-1, RealFormat_e f=FTOA_FLOAT) : val(v), precision(prec), fmt(f) {} -}; - -template -real_ real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT) -{ - return real_(val, precision, fmt); -} - -/** @} */ // real_specifiers - -/** @} */ // format_specifiers - -} // namespace fmt - -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, fmt::real_< float> fmt) { return ftoa(buf, fmt.val, fmt.precision, fmt.fmt); } -/** @ingroup doc_to_chars */ -inline size_t to_chars(substr buf, fmt::real_ fmt) { return dtoa(buf, fmt.val, fmt.precision, fmt.fmt); } - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// writing raw binary data - -namespace fmt { - -/** @addtogroup doc_format_specifiers - * @{ */ - -/** @defgroup doc_raw_binary_specifiers Raw binary data - * @{ */ - -/** @see blob_ */ -template -struct raw_wrapper_ : public blob_ -{ - size_t alignment; - - C4_ALWAYS_INLINE raw_wrapper_(blob_ data, size_t alignment_) noexcept - : - blob_(data), - alignment(alignment_) - { - C4_ASSERT_MSG(alignment > 0 && (alignment & (alignment - 1)) == 0, "alignment must be a power of two"); - } -}; - -using const_raw_wrapper = raw_wrapper_; -using raw_wrapper = raw_wrapper_; - -/** mark a variable to be written in raw binary format, using memcpy - * @see blob_ */ -inline const_raw_wrapper craw(cblob data, size_t alignment=alignof(max_align_t)) -{ - return const_raw_wrapper(data, alignment); -} -/** mark a variable to be written in raw binary format, using memcpy - * @see blob_ */ -inline const_raw_wrapper raw(cblob data, size_t alignment=alignof(max_align_t)) -{ - return const_raw_wrapper(data, alignment); -} -/** mark a variable to be written in raw binary format, using memcpy - * @see blob_ */ -template -inline const_raw_wrapper craw(T const& C4_RESTRICT data, size_t alignment=alignof(T)) -{ - return const_raw_wrapper(cblob(data), alignment); -} -/** mark a variable to be written in raw binary format, using memcpy - * @see blob_ */ -template -inline const_raw_wrapper raw(T const& C4_RESTRICT data, size_t alignment=alignof(T)) -{ - return const_raw_wrapper(cblob(data), alignment); -} - -/** mark a variable to be read in raw binary format, using memcpy */ -inline raw_wrapper raw(blob data, size_t alignment=alignof(max_align_t)) -{ - return raw_wrapper(data, alignment); -} -/** mark a variable to be read in raw binary format, using memcpy */ -template -inline raw_wrapper raw(T & C4_RESTRICT data, size_t alignment=alignof(T)) -{ - return raw_wrapper(blob(data), alignment); -} - -/** @} */ // raw_binary_specifiers - -/** @} */ // format_specifiers - -} // namespace fmt - - -/** write a variable in raw binary format, using memcpy - * @ingroup doc_to_chars */ -C4CORE_EXPORT size_t to_chars(substr buf, fmt::const_raw_wrapper r); - -/** read a variable in raw binary format, using memcpy - * @ingroup doc_from_chars */ -C4CORE_EXPORT bool from_chars(csubstr buf, fmt::raw_wrapper *r); -/** read a variable in raw binary format, using memcpy - * @ingroup doc_from_chars */ -inline bool from_chars(csubstr buf, fmt::raw_wrapper r) -{ - return from_chars(buf, &r); -} - -/** read a variable in raw binary format, using memcpy - * @ingroup doc_from_chars_first */ -inline size_t from_chars_first(csubstr buf, fmt::raw_wrapper *r) -{ - return from_chars(buf, r); -} -/** read a variable in raw binary format, using memcpy - * @ingroup doc_from_chars_first */ -inline size_t from_chars_first(csubstr buf, fmt::raw_wrapper r) -{ - return from_chars(buf, &r); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// formatting aligned to left/right - -namespace fmt { - -/** @addtogroup doc_format_specifiers - * @{ */ - -/** @defgroup doc_alignment_specifiers Alignment specifiers - * @{ */ - -template -struct left_ -{ - T val; - size_t width; - char pad; - left_(T v, size_t w, char p) : val(v), width(w), pad(p) {} -}; - -template -struct right_ -{ - T val; - size_t width; - char pad; - right_(T v, size_t w, char p) : val(v), width(w), pad(p) {} -}; - -/** mark an argument to be aligned left */ -template -left_ left(T val, size_t width, char padchar=' ') -{ - return left_(val, width, padchar); -} - -/** mark an argument to be aligned right */ -template -right_ right(T val, size_t width, char padchar=' ') -{ - return right_(val, width, padchar); -} - -/** @} */ // alignment_specifiers - -/** @} */ // format_specifiers - -} // namespace fmt - - -/** @ingroup doc_to_chars */ -template -size_t to_chars(substr buf, fmt::left_ const& C4_RESTRICT align) -{ - size_t ret = to_chars(buf, align.val); - if(ret >= buf.len || ret >= align.width) - return ret > align.width ? ret : align.width; - buf.first(align.width).sub(ret).fill(align.pad); - to_chars(buf, align.val); - return align.width; -} - -/** @ingroup doc_to_chars */ -template -size_t to_chars(substr buf, fmt::right_ const& C4_RESTRICT align) -{ - size_t ret = to_chars(buf, align.val); - if(ret >= buf.len || ret >= align.width) - return ret > align.width ? ret : align.width; - size_t rem = static_cast(align.width - ret); - buf.first(rem).fill(align.pad); - to_chars(buf.sub(rem), align.val); - return align.width; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_cat cat: concatenate arguments to string - * @{ */ - -/** @cond dev */ -// terminates the variadic recursion -inline size_t cat(substr /*buf*/) -{ - return 0; -} -/** @endcond */ - - -/** serialize the arguments, concatenating them to the given fixed-size buffer. - * The buffer size is strictly respected: no writes will occur beyond its end. - * @return the number of characters needed to write all the arguments into the buffer. - * @see c4::catrs() if instead of a fixed-size buffer, a resizeable container is desired - * @see c4::uncat() for the inverse function - * @see c4::catsep() if a separator between each argument is to be used - * @see c4::format() if a format string is desired */ -template -size_t cat(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more) -{ - size_t num = to_chars(buf, a); - buf = buf.len >= num ? buf.sub(num) : substr{}; - num += cat(buf, more...); - return num; -} - -/** like c4::cat() but return a substr instead of a size */ -template -substr cat_sub(substr buf, Args && ...args) -{ - size_t sz = cat(buf, std::forward(args)...); - C4_CHECK(sz <= buf.len); - return {buf.str, sz <= buf.len ? sz : buf.len}; -} - -/** @} */ - - -//----------------------------------------------------------------------------- - - -/** @defgroup doc_uncat uncat: read concatenated arguments from string - * @{ */ - -/** @cond dev */ -// terminates the variadic recursion -inline size_t uncat(csubstr /*buf*/) -{ - return 0; -} -/** @endcond */ - - -/** deserialize the arguments from the given buffer. - * - * @return the number of characters read from the buffer, or csubstr::npos - * if a conversion was not successful. - * @see c4::cat(). c4::uncat() is the inverse of c4::cat(). */ -template -size_t uncat(csubstr buf, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more) -{ - size_t out = from_chars_first(buf, &a); - if(C4_UNLIKELY(out == csubstr::npos)) - return csubstr::npos; - buf = buf.len >= out ? buf.sub(out) : substr{}; - size_t num = uncat(buf, more...); - if(C4_UNLIKELY(num == csubstr::npos)) - return csubstr::npos; - return out + num; -} - -/** @} */ - - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/** @defgroup doc_catsep catsep: cat arguments to string with separator - * @{ */ - -/** @cond dev */ -namespace detail { -template -C4_ALWAYS_INLINE size_t catsep_more(substr /*buf*/, Sep const& C4_RESTRICT /*sep*/) -{ - return 0; -} - -template -size_t catsep_more(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more) -{ - size_t ret = to_chars(buf, sep); - size_t num = ret; - buf = buf.len >= ret ? buf.sub(ret) : substr{}; - ret = to_chars(buf, a); - num += ret; - buf = buf.len >= ret ? buf.sub(ret) : substr{}; - ret = catsep_more(buf, sep, more...); - num += ret; - return num; -} - - -template -inline size_t uncatsep_more(csubstr /*buf*/, Sep & /*sep*/) -{ - return 0; -} - -template -size_t uncatsep_more(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more) -{ - size_t ret = from_chars_first(buf, &sep); - size_t num = ret; - if(C4_UNLIKELY(ret == csubstr::npos)) - return csubstr::npos; - buf = buf.len >= ret ? buf.sub(ret) : substr{}; - ret = from_chars_first(buf, &a); - if(C4_UNLIKELY(ret == csubstr::npos)) - return csubstr::npos; - num += ret; - buf = buf.len >= ret ? buf.sub(ret) : substr{}; - ret = uncatsep_more(buf, sep, more...); - if(C4_UNLIKELY(ret == csubstr::npos)) - return csubstr::npos; - num += ret; - return num; -} - -} // namespace detail - -template -size_t catsep(substr /*buf*/, Sep const& C4_RESTRICT /*sep*/) -{ - return 0; -} -/** @endcond */ - - -/** serialize the arguments, concatenating them to the given fixed-size - * buffer, using a separator between each argument. - * The buffer size is strictly respected: no writes will occur beyond its end. - * @return the number of characters needed to write all the arguments into the buffer. - * @see c4::catseprs() if instead of a fixed-size buffer, a resizeable container is desired - * @see c4::uncatsep() for the inverse function (ie, reading instead of writing) - * @see c4::cat() if no separator is needed - * @see c4::format() if a format string is desired */ -template -size_t catsep(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more) -{ - size_t num = to_chars(buf, a); - buf = buf.len >= num ? buf.sub(num) : substr{}; - num += detail::catsep_more(buf, sep, more...); - return num; -} - -/** like c4::catsep() but return a substr instead of a size - * @see c4::catsep(). c4::uncatsep() is the inverse of c4::catsep(). */ -template -substr catsep_sub(substr buf, Args && ...args) -{ - size_t sz = catsep(buf, std::forward(args)...); - C4_CHECK(sz <= buf.len); - return {buf.str, sz <= buf.len ? sz : buf.len}; -} - -/** @} */ - - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_uncatsep uncatsep: deserialize the separated arguments from a string - * @{ */ - -/** deserialize the arguments from the given buffer. - * - * @return the number of characters read from the buffer, or csubstr::npos - * if a conversion was not successful. - * @see c4::cat(). c4::uncat() is the inverse of c4::cat(). */ - -/** deserialize the arguments from the given buffer, using a separator. - * - * @return the number of characters read from the buffer, or csubstr::npos - * if a conversion was not successful - * @see c4::catsep(). c4::uncatsep() is the inverse of c4::catsep(). */ -template -size_t uncatsep(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more) -{ - size_t ret = from_chars_first(buf, &a), num = ret; - if(C4_UNLIKELY(ret == csubstr::npos)) - return csubstr::npos; - buf = buf.len >= ret ? buf.sub(ret) : substr{}; - ret = detail::uncatsep_more(buf, sep, more...); - if(C4_UNLIKELY(ret == csubstr::npos)) - return csubstr::npos; - num += ret; - return num; -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_format format: formatted string interpolation - * @{ */ - -/// @cond dev -// terminates the variadic recursion -inline size_t format(substr buf, csubstr fmt) -{ - return to_chars(buf, fmt); -} -/// @endcond - - -/** using a format string, serialize the arguments into the given - * fixed-size buffer. - * The buffer size is strictly respected: no writes will occur beyond its end. - * In the format string, each argument is marked with a compact - * curly-bracket pair: {}. Arguments beyond the last curly bracket pair - * are silently ignored. For example: - * @code{.cpp} - * c4::format(buf, "the {} drank {} {}", "partier", 5, "beers"); // the partier drank 5 beers - * c4::format(buf, "the {} drank {} {}", "programmer", 6, "coffees"); // the programmer drank 6 coffees - * @endcode - * @return the number of characters needed to write into the buffer. - * @see c4::formatrs() if instead of a fixed-size buffer, a resizeable container is desired - * @see c4::unformat() for the inverse function - * @see c4::cat() if no format or separator is needed - * @see c4::catsep() if no format is needed, but a separator must be used */ -template -size_t format(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more) -{ - size_t pos = fmt.find("{}"); // @todo use _find_fmt() - if(C4_UNLIKELY(pos == csubstr::npos)) - return to_chars(buf, fmt); - 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, a); - out += num; - buf = buf.len >= num ? buf.sub(num) : substr{}; - num = format(buf, fmt.sub(pos + 2), more...); - out += num; - return out; -} - -/** like c4::format() but return a substr instead of a size - * @see c4::format() - * @see c4::catsep(). uncatsep() is the inverse of catsep(). */ -template -substr format_sub(substr buf, csubstr fmt, Args const& C4_RESTRICT ...args) -{ - size_t sz = c4::format(buf, fmt, args...); - C4_CHECK(sz <= buf.len); - return {buf.str, sz <= buf.len ? sz : buf.len}; -} - -/** @} */ - - -//----------------------------------------------------------------------------- - -/** @defgroup doc_unformat unformat: formatted read from string - * @{ */ - -/// @cond dev -// terminates the variadic recursion -inline size_t unformat(csubstr /*buf*/, csubstr fmt) -{ - return fmt.len; -} -/// @endcond - - -/** using a format string, deserialize the arguments from the given - * buffer. - * @return the number of characters read from the buffer, or npos if a conversion failed. - * @see c4::format(). c4::unformat() is the inverse function to format(). */ -template -size_t unformat(csubstr buf, csubstr fmt, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more) -{ - const size_t pos = fmt.find("{}"); - if(C4_UNLIKELY(pos == csubstr::npos)) - return unformat(buf, fmt); - size_t num = pos; - size_t out = num; - buf = buf.len >= num ? buf.sub(num) : substr{}; - num = from_chars_first(buf, &a); - if(C4_UNLIKELY(num == csubstr::npos)) - return csubstr::npos; - out += num; - buf = buf.len >= num ? buf.sub(num) : substr{}; - num = unformat(buf, fmt.sub(pos + 2), more...); - if(C4_UNLIKELY(num == csubstr::npos)) - return csubstr::npos; - out += num; - return out; -} - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** cat+resize: like c4::cat(), but receives a container, and resizes - * it as needed to contain the result. The container is - * overwritten. To append to it, use the append overload. - * @see c4::cat() - * @ingroup doc_cat */ -template -inline void catrs(CharOwningContainer * C4_RESTRICT cont, Args const& C4_RESTRICT ...args) -{ -retry: - substr buf = to_substr(*cont); - size_t ret = cat(buf, args...); - cont->resize(ret); - if(ret > buf.len) - goto retry; -} - -/** cat+resize: like c4::cat(), but creates and returns a new - * container sized as needed to contain the result. - * @see c4::cat() - * @ingroup doc_cat */ -template -inline CharOwningContainer catrs(Args const& C4_RESTRICT ...args) -{ - CharOwningContainer cont; - catrs(&cont, args...); - return cont; -} - -/** cat+resize+append: like c4::cat(), but receives a container, and - * appends to it instead of overwriting it. The container is resized - * as needed to contain the result. - * - * @return the region newly appended to the original container - * @see c4::cat() - * @see c4::catrs() - * @ingroup doc_cat */ -template -inline csubstr catrs_append(CharOwningContainer * C4_RESTRICT cont, Args const& C4_RESTRICT ...args) -{ - const size_t pos = cont->size(); -retry: - substr buf = to_substr(*cont).sub(pos); - size_t ret = cat(buf, args...); - cont->resize(pos + ret); - if(ret > buf.len) - goto retry; - return to_csubstr(*cont).range(pos, cont->size()); -} - - -//----------------------------------------------------------------------------- - -/** catsep+resize: like c4::catsep(), but receives a container, and - * resizes it as needed to contain the result. The container is - * overwritten. To append to the container use the append overload. - * - * @see c4::catsep() - * @ingroup doc_catsep */ -template -inline void catseprs(CharOwningContainer * C4_RESTRICT cont, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args) -{ -retry: - substr buf = to_substr(*cont); - size_t ret = catsep(buf, sep, args...); - cont->resize(ret); - if(ret > buf.len) - goto retry; -} - -/** catsep+resize: like c4::catsep(), but create a new container with - * the result. - * - * @return the requested container - * @ingroup doc_catsep */ -template -inline CharOwningContainer catseprs(Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args) -{ - CharOwningContainer cont; - catseprs(&cont, sep, args...); - return cont; -} - - -/** catsep+resize+append: like catsep(), but receives a container, and - * appends the arguments, resizing the container as needed to contain - * the result. The buffer is appended to. - * - * @return a csubstr of the appended part - * @ingroup doc_catsep */ -template -inline csubstr catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args) -{ - const size_t pos = cont->size(); -retry: - substr buf = to_substr(*cont).sub(pos); - size_t ret = catsep(buf, sep, args...); - cont->resize(pos + ret); - if(ret > buf.len) - goto retry; - return to_csubstr(*cont).range(pos, cont->size()); -} - - -//----------------------------------------------------------------------------- - -/** format+resize: like c4::format(), but receives a container, and - * resizes it as needed to contain the result. The container is - * overwritten. To append to the container use the append overload. - * - * @see c4::format() - * @ingroup doc_format */ -template -inline void formatrs(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args const& C4_RESTRICT ...args) -{ -retry: - substr buf = to_substr(*cont); - size_t ret = format(buf, fmt, args...); - cont->resize(ret); - if(ret > buf.len) - goto retry; -} - -/** format+resize: like c4::format(), but create a new container with - * the result. - * - * @return the requested container - * @ingroup doc_format */ -template -inline CharOwningContainer formatrs(csubstr fmt, Args const& C4_RESTRICT ...args) -{ - CharOwningContainer cont; - formatrs(&cont, fmt, args...); - return cont; -} - -/** format+resize+append: like format(), but receives a container, and appends the - * arguments, resizing the container as needed to contain the - * result. The buffer is appended to. - * @return the region newly appended to the original container - * @ingroup doc_format */ -template -inline csubstr formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args const& C4_RESTRICT ...args) -{ - const size_t pos = cont->size(); -retry: - substr buf = to_substr(*cont).sub(pos); - size_t ret = format(buf, fmt, args...); - cont->resize(pos + ret); - if(ret > buf.len) - goto retry; - return to_csubstr(*cont).range(pos, cont->size()); -} - -/** @} */ - -} // namespace c4 - -// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast,*avoid-goto*) -#ifdef _MSC_VER -# pragma warning(pop) -#elif defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -#endif /* _C4_FORMAT_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/language.hpp b/3rdparty/rapidyaml/include/c4/language.hpp deleted file mode 100644 index 9bf6ccc465..0000000000 --- a/3rdparty/rapidyaml/include/c4/language.hpp +++ /dev/null @@ -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 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/memory_util.hpp b/3rdparty/rapidyaml/include/c4/memory_util.hpp deleted file mode 100644 index 4907b2264f..0000000000 --- a/3rdparty/rapidyaml/include/c4/memory_util.hpp +++ /dev/null @@ -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 -#endif -#include - -#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 -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 -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 -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 -C4_CONSTEXPR14 -auto lsb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto lsb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto lsb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto lsb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto lsb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 struct _lsb11; -template -struct _lsb11 -{ - enum : unsigned { num = _lsb11>1), num_bits+I(1), (((val>>1)&I(1))!=I(0))>::num }; -}; -template -struct _lsb11 -{ - 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 -struct lsb11 -{ - static_assert(number != 0, "lsb: number must be nonzero"); - enum : unsigned { value = detail::_lsb11::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 -C4_CONSTEXPR14 -auto msb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto msb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto msb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto msb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 -C4_CONSTEXPR14 -auto msb(I v) noexcept - -> typename std::enable_if::type -{ - C4_STATIC_ASSERT(std::is_unsigned::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 struct _msb11; -template -struct _msb11< I, val, num_bits, false> -{ - enum : unsigned { num = _msb11>1), num_bits+I(1), ((val>>1)==I(0))>::num }; -}; -template -struct _msb11 -{ - 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 -struct msb11 -{ - enum : unsigned { value = detail::_msb11::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 -C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if::value, B>::type -{ - C4_STATIC_ASSERT(std::is_integral::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 -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 -struct _ctgmsk11; - -template -struct _ctgmsk11< I, val, first, last, true> -{ - enum : I { value = _ctgmsk11::value }; -}; - -template -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 -struct contiguous_mask11 -{ - enum : I { value = detail::_ctgmsk11::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 -constexpr TightPairCase_e tpc_which_case() -{ - return std::is_same::value ? - std::is_empty::value ? - tpc_same_empty - : - tpc_same - : - std::is_empty::value && std::is_empty::value ? - tpc_both_empty - : - std::is_empty::value ? - tpc_first_empty - : - std::is_empty::value ? - tpc_second_empty - : - tpc_general - ; -} - -template -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 -struct tight_pair : public First -{ - static_assert(std::is_same::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(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast(*this); } // NOLINT - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast(*this); } // NOLINT -}; - -template -struct tight_pair : 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(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast(*this); } -}; - -template -struct tight_pair : 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(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; } -}; - -template -struct tight_pair : 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(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; } -}; - -template -struct tight_pair : 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(*this); } - C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast(*this); } -}; - -} // namespace detail - -template -using tight_pair = detail::tight_pair()>; - -C4_SUPPRESS_WARNING_GCC_CLANG_POP - -} // namespace c4 - -// NOLINTEND(google-runtime-int) - -#endif /* _C4_MEMORY_UTIL_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/platform.hpp b/3rdparty/rapidyaml/include/c4/platform.hpp deleted file mode 100644 index d7c56d71ca..0000000000 --- a/3rdparty/rapidyaml/include/c4/platform.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/preprocessor.hpp b/3rdparty/rapidyaml/include/c4/preprocessor.hpp deleted file mode 100644 index a554825402..0000000000 --- a/3rdparty/rapidyaml/include/c4/preprocessor.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/std/std.hpp b/3rdparty/rapidyaml/include/c4/std/std.hpp deleted file mode 100644 index f500db0bde..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/std.hpp +++ /dev/null @@ -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_ diff --git a/3rdparty/rapidyaml/include/c4/std/std_fwd.hpp b/3rdparty/rapidyaml/include/c4/std/std_fwd.hpp deleted file mode 100644 index 8c42ce7118..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/std_fwd.hpp +++ /dev/null @@ -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_ diff --git a/3rdparty/rapidyaml/include/c4/std/string.hpp b/3rdparty/rapidyaml/include/c4/std/string.hpp deleted file mode 100644 index bc69347f17..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/string.hpp +++ /dev/null @@ -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 - -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_ diff --git a/3rdparty/rapidyaml/include/c4/std/string_fwd.hpp b/3rdparty/rapidyaml/include/c4/std/string_fwd.hpp deleted file mode 100644 index bf9459de89..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/string_fwd.hpp +++ /dev/null @@ -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 - -// forward declarations for std::string -#if defined(__GLIBCXX__) || defined(__GLIBCPP__) -#include // use the fwd header in glibcxx -#elif defined(_LIBCPP_VERSION) || defined(__APPLE_CC__) -#include // 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 struct char_traits; -template class allocator; -template class basic_string; -using string = basic_string, allocator>; -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_ diff --git a/3rdparty/rapidyaml/include/c4/std/string_view.hpp b/3rdparty/rapidyaml/include/c4/std/string_view.hpp deleted file mode 100644 index 61f8e561be..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/string_view.hpp +++ /dev/null @@ -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 - - -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_ diff --git a/3rdparty/rapidyaml/include/c4/std/tuple.hpp b/3rdparty/rapidyaml/include/c4/std/tuple.hpp deleted file mode 100644 index 5edcd63da1..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/tuple.hpp +++ /dev/null @@ -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 - -/** 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(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(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(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(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(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(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 const& /*tp*/) { return 0; } - static size_t do_uncat(csubstr /*buf*/, std::tuple & /*tp*/) { return 0; } - - template< class Sep > static size_t do_catsep_more(substr /*buf*/, Sep const& /*sep*/, std::tuple const& /*tp*/) { return 0; } - template< class Sep > static size_t do_uncatsep_more(csubstr /*buf*/, Sep & /*sep*/, std::tuple & /*tp*/) { return 0; } - - static size_t do_format(substr buf, csubstr fmt, std::tuple const& /*tp*/) - { - return to_chars(buf, fmt); - } - - static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/std/vector.hpp b/3rdparty/rapidyaml/include/c4/std/vector.hpp deleted file mode 100644 index 43f4f82e47..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/vector.hpp +++ /dev/null @@ -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 to c4::substr and c4::csubstr. - * @todo add to_span() and friends - */ - -#ifndef C4CORE_SINGLE_HEADER -#include "c4/substr.hpp" -#endif - -#include - -namespace c4 { - -//----------------------------------------------------------------------------- - -/** get a substr (writeable string view) of an existing std::vector */ -template -c4::substr to_substr(std::vector &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 */ -template -c4::csubstr to_csubstr(std::vector 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 - -template C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::vector const& s) { return ss != to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::vector const& s) { return ss == to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::vector const& s) { return ss >= to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::vector const& s) { return ss > to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::vector const& s) { return ss <= to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::vector const& s) { return ss < to_csubstr(s); } - -template C4_ALWAYS_INLINE bool operator!= (std::vector const& s, c4::csubstr ss) { return ss != to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator== (std::vector const& s, c4::csubstr ss) { return ss == to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator>= (std::vector const& s, c4::csubstr ss) { return ss <= to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator> (std::vector const& s, c4::csubstr ss) { return ss < to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator<= (std::vector const& s, c4::csubstr ss) { return ss >= to_csubstr(s); } -template C4_ALWAYS_INLINE bool operator< (std::vector const& s, c4::csubstr ss) { return ss > to_csubstr(s); } - -//----------------------------------------------------------------------------- - -/** copy a std::vector to a writeable string view */ -template -inline size_t to_chars(c4::substr buf, std::vector 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 */ -template -inline bool from_chars(c4::csubstr buf, std::vector * 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_ diff --git a/3rdparty/rapidyaml/include/c4/std/vector_fwd.hpp b/3rdparty/rapidyaml/include/c4/std/vector_fwd.hpp deleted file mode 100644 index 791e0feeea..0000000000 --- a/3rdparty/rapidyaml/include/c4/std/vector_fwd.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _C4_STD_VECTOR_FWD_HPP_ -#define _C4_STD_VECTOR_FWD_HPP_ - -/** @file vector_fwd.hpp */ - -#include - -// 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 class allocator; -#ifdef _GLIBCXX_DEBUG -inline namespace __debug { -template class vector; -} -#else -template 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 class allocator; -template 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 c4::substr to_substr(std::vector &vec); -template c4::csubstr to_csubstr(std::vector const& vec); - -template bool operator!= (c4::csubstr ss, std::vector const& s); -template bool operator== (c4::csubstr ss, std::vector const& s); -template bool operator>= (c4::csubstr ss, std::vector const& s); -template bool operator> (c4::csubstr ss, std::vector const& s); -template bool operator<= (c4::csubstr ss, std::vector const& s); -template bool operator< (c4::csubstr ss, std::vector const& s); - -template bool operator!= (std::vector const& s, c4::csubstr ss); -template bool operator== (std::vector const& s, c4::csubstr ss); -template bool operator>= (std::vector const& s, c4::csubstr ss); -template bool operator> (std::vector const& s, c4::csubstr ss); -template bool operator<= (std::vector const& s, c4::csubstr ss); -template bool operator< (std::vector const& s, c4::csubstr ss); - -template size_t to_chars(c4::substr buf, std::vector const& s); -template bool from_chars(c4::csubstr buf, std::vector * s); - -} // namespace c4 - -// NOLINTEND(cert-dcl58-cpp) - -#endif // _C4_STD_VECTOR_FWD_HPP_ diff --git a/3rdparty/rapidyaml/include/c4/substr.hpp b/3rdparty/rapidyaml/include/c4/substr.hpp deleted file mode 100644 index 4d28bdf0c3..0000000000 --- a/3rdparty/rapidyaml/include/c4/substr.hpp +++ /dev/null @@ -1,2290 +0,0 @@ -#ifndef _C4_SUBSTR_HPP_ -#define _C4_SUBSTR_HPP_ - -/** @file substr.hpp read+write string views */ - -#include -#include -#include - -#include "c4/config.hpp" -#include "c4/error.hpp" -#include "c4/substr_fwd.hpp" - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wold-style-cast" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" // disable warnings on size_t>=0, used heavily in assertions below. These assertions are a preparation step for providing the index type as a template parameter. -# pragma GCC diagnostic ignored "-Wuseless-cast" -# pragma GCC diagnostic ignored "-Wold-style-cast" -#endif - - -namespace c4 { - -/** @defgroup doc_substr Substring: read/write string views - * @{ */ - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -namespace detail { -template -static inline void _do_reverse(C *C4_RESTRICT first, C *C4_RESTRICT last) -{ - while(last > first) - { - C tmp = *last; - *last-- = *first; - *first++ = tmp; - } -} -} // namespace detail -/** @endcond */ - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -// utility macros to deuglify SFINAE code; undefined after the class. -// https://stackoverflow.com/questions/43051882/how-to-disable-a-class-member-funrtion-for-certain-template-types -#define C4_REQUIRE_RW(ret_type) \ - template \ - typename std::enable_if< ! std::is_const::value, ret_type>::type -/** @endcond */ - - -/** a non-owning string-view, consisting of a character pointer - * and a length. - * - * @note The pointer is explicitly restricted. - * - * @see a [quickstart - * sample](https://rapidyaml.readthedocs.io/latest/doxygen/group__doc__quickstart.html#ga43e253da0692c13967019446809c1113) - * in rapidyaml's documentation. - */ -template -struct C4CORE_EXPORT basic_substring // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) -{ -public: - - /** a restricted pointer to the first character of the substring */ - C * C4_RESTRICT str; - /** the length of the substring */ - size_t len; - -public: - - /** @name Types */ - /** @{ */ - - using CC = typename std::add_const::type; //!< CC=const char - using NCC_ = typename std::remove_const::type; //!< NCC_=non const char - - using ro_substr = basic_substring; - using rw_substr = basic_substring; - - using char_type = C; - using size_type = size_t; - - using iterator = C*; - using const_iterator = CC*; - - enum : size_t { npos = (size_t)-1, NONE = (size_t)-1 }; - - /// convert automatically to substring of const C - template - C4_ALWAYS_INLINE operator typename std::enable_if::value, ro_substr const&>::type () const noexcept - { - return *(ro_substr const*)this; // don't call the str+len ctor because it does a check - } - - /** @} */ - -public: - - /** @name Default construction and assignment */ - /** @{ */ - - C4_ALWAYS_INLINE constexpr basic_substring() noexcept : str(), len() {} - - C4_ALWAYS_INLINE basic_substring(basic_substring const&) noexcept = default; - C4_ALWAYS_INLINE basic_substring(basic_substring &&) noexcept = default; - C4_ALWAYS_INLINE basic_substring(std::nullptr_t) noexcept : str(nullptr), len(0) {} - - C4_ALWAYS_INLINE basic_substring& operator= (basic_substring const&) noexcept = default; - C4_ALWAYS_INLINE basic_substring& operator= (basic_substring &&) noexcept = default; - C4_ALWAYS_INLINE basic_substring& operator= (std::nullptr_t) noexcept { str = nullptr; len = 0; return *this; } - - C4_ALWAYS_INLINE void clear() noexcept { str = nullptr; len = 0; } - - /** @} */ - -public: - - /** @name Construction and assignment from characters with the same type */ - /** @{ */ - - /** Construct from an array. - * @warning the input string need not be zero terminated, but the - * length is taken as if the string was zero terminated */ - template - C4_ALWAYS_INLINE constexpr basic_substring(C (&s_)[N]) noexcept : str(s_), len(N-1) {} - /** Construct from a pointer and length. - * @warning the input string need not be zero terminated. */ - C4_ALWAYS_INLINE basic_substring(C *s_, size_t len_) noexcept : str(s_), len(len_) { C4_ASSERT(str || !len_); } - /** Construct from two pointers. - * @warning the end pointer MUST BE larger than or equal to the begin pointer - * @warning the input string need not be zero terminated */ - C4_ALWAYS_INLINE basic_substring(C *beg_, C *end_) noexcept : str(beg_), len(static_cast(end_ - beg_)) { C4_ASSERT(end_ >= beg_); } - /** Construct from a C-string (zero-terminated string) - * @warning the input string MUST BE zero terminated. - * @warning will call strlen() - * @note this overload uses SFINAE to prevent it from overriding the array ctor - * @see For a more detailed explanation on why the plain overloads cannot - * coexist, see http://cplusplus.bordoon.com/specializeForCharacterArrays.html */ - template::value || std::is_same::value, int>::type=0> - C4_ALWAYS_INLINE basic_substring(U s_) noexcept : str(s_), len(s_ ? strlen(s_) : 0) {} - - /** Assign from an array. - * @warning the input string need not be zero terminated, but the - * length is taken as if the string was zero terminated */ - template - C4_ALWAYS_INLINE void assign(C (&s_)[N]) noexcept { str = (s_); len = (N-1); } - /** Assign from a pointer and length. - * @warning the input string need not be zero terminated. */ - C4_ALWAYS_INLINE void assign(C *s_, size_t len_) noexcept { str = s_; len = len_; C4_ASSERT(str || !len_); } - /** Assign from two pointers. - * @warning the end pointer MUST BE larger than or equal to the begin pointer - * @warning the input string need not be zero terminated. */ - C4_ALWAYS_INLINE void assign(C *beg_, C *end_) noexcept { C4_ASSERT(end_ >= beg_); str = (beg_); len = static_cast(end_ - beg_); } - /** Assign from a C-string (zero-terminated string) - * @warning the input string must be zero terminated. - * @warning will call strlen() - * @note this overload uses SFINAE to prevent it from overriding the array ctor - * @see For a more detailed explanation on why the plain overloads cannot - * coexist, see http://cplusplus.bordoon.com/specializeForCharacterArrays.html */ - template::value || std::is_same::value, int>::type=0> - C4_ALWAYS_INLINE void assign(U s_) noexcept { str = (s_); len = (s_ ? strlen(s_) : 0); } - - /** Assign from an array. - * @warning the input string need not be zero terminated. */ - template - C4_ALWAYS_INLINE basic_substring& operator= (C (&s_)[N]) noexcept { str = (s_); len = (N-1); return *this; } - /** Assign from a C-string (zero-terminated string) - * @warning the input string MUST BE zero terminated. - * @warning will call strlen() - * @note this overload uses SFINAE to prevent it from overriding the array ctor - * @see For a more detailed explanation on why the plain overloads cannot - * coexist, see http://cplusplus.bordoon.com/specializeForCharacterArrays.html */ - template::value || std::is_same::value, int>::type=0> - C4_ALWAYS_INLINE basic_substring& operator= (U s_) noexcept { str = s_; len = s_ ? strlen(s_) : 0; return *this; } - - /** @} */ - -public: - - /** @name Standard accessor methods */ - /** @{ */ - - C4_ALWAYS_INLINE C4_PURE bool has_str() const noexcept { return ! empty() && str[0] != C(0); } - C4_ALWAYS_INLINE C4_PURE bool empty() const noexcept { return (len == 0 || str == nullptr); } - C4_ALWAYS_INLINE C4_PURE bool not_empty() const noexcept { return (len != 0 && str != nullptr); } - C4_ALWAYS_INLINE C4_PURE size_t size() const noexcept { return len; } - - C4_ALWAYS_INLINE C4_PURE iterator begin() noexcept { return str; } - C4_ALWAYS_INLINE C4_PURE iterator end () noexcept { return str + len; } - - C4_ALWAYS_INLINE C4_PURE const_iterator begin() const noexcept { return str; } - C4_ALWAYS_INLINE C4_PURE const_iterator end () const noexcept { return str + len; } - - C4_ALWAYS_INLINE C4_PURE C * data() noexcept { return str; } - C4_ALWAYS_INLINE C4_PURE C const* data() const noexcept { return str; } - - C4_ALWAYS_INLINE C4_PURE C & operator[] (size_t i) noexcept { C4_ASSERT(i >= 0 && i < len); return str[i]; } - C4_ALWAYS_INLINE C4_PURE C const& operator[] (size_t i) const noexcept { C4_ASSERT(i >= 0 && i < len); return str[i]; } - - C4_ALWAYS_INLINE C4_PURE C & front() noexcept { C4_ASSERT(len > 0 && str != nullptr); return *str; } - C4_ALWAYS_INLINE C4_PURE C const& front() const noexcept { C4_ASSERT(len > 0 && str != nullptr); return *str; } - - C4_ALWAYS_INLINE C4_PURE C & back() noexcept { C4_ASSERT(len > 0 && str != nullptr); return *(str + len - 1); } - C4_ALWAYS_INLINE C4_PURE C const& back() const noexcept { C4_ASSERT(len > 0 && str != nullptr); return *(str + len - 1); } - - /** @} */ - -public: - - /** @name Comparison methods */ - /** @{ */ - - C4_PURE int compare(C const c) const noexcept - { - C4_XASSERT((str != nullptr) || len == 0); - if(C4_LIKELY(str != nullptr && len > 0)) - return (*str != c) ? *str - c : (static_cast(len) - 1); - else - return -1; - } - - C4_PURE int compare(const char *C4_RESTRICT that, size_t sz) const noexcept - { - C4_XASSERT(that || sz == 0); - C4_XASSERT(str || len == 0); - if(C4_LIKELY(str && that)) - { - { - const size_t min = len < sz ? len : sz; - for(size_t i = 0; i < min; ++i) - if(str[i] != that[i]) - return str[i] < that[i] ? -1 : 1; - } - if(len < sz) - return -1; - else if(len == sz) - return 0; - else - return 1; - } - else if(len == sz) - { - C4_XASSERT(len == 0 && sz == 0); - return 0; - } - return len < sz ? -1 : 1; - } - - C4_ALWAYS_INLINE C4_PURE int compare(ro_substr const that) const noexcept { return this->compare(that.str, that.len); } - - C4_ALWAYS_INLINE C4_PURE bool operator== (std::nullptr_t) const noexcept { return str == nullptr; } - C4_ALWAYS_INLINE C4_PURE bool operator!= (std::nullptr_t) const noexcept { return str != nullptr; } - - C4_ALWAYS_INLINE C4_PURE bool operator== (C const c) const noexcept { return this->compare(c) == 0; } - C4_ALWAYS_INLINE C4_PURE bool operator!= (C const c) const noexcept { return this->compare(c) != 0; } - C4_ALWAYS_INLINE C4_PURE bool operator< (C const c) const noexcept { return this->compare(c) < 0; } - C4_ALWAYS_INLINE C4_PURE bool operator> (C const c) const noexcept { return this->compare(c) > 0; } - C4_ALWAYS_INLINE C4_PURE bool operator<= (C const c) const noexcept { return this->compare(c) <= 0; } - C4_ALWAYS_INLINE C4_PURE bool operator>= (C const c) const noexcept { return this->compare(c) >= 0; } - - template C4_ALWAYS_INLINE C4_PURE bool operator== (basic_substring const that) const noexcept { return this->compare(that) == 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator!= (basic_substring const that) const noexcept { return this->compare(that) != 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator< (basic_substring const that) const noexcept { return this->compare(that) < 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator> (basic_substring const that) const noexcept { return this->compare(that) > 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator<= (basic_substring const that) const noexcept { return this->compare(that) <= 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator>= (basic_substring const that) const noexcept { return this->compare(that) >= 0; } - - template C4_ALWAYS_INLINE C4_PURE bool operator== (const char (&that)[N]) const noexcept { return this->compare(that, N-1) == 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator!= (const char (&that)[N]) const noexcept { return this->compare(that, N-1) != 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator< (const char (&that)[N]) const noexcept { return this->compare(that, N-1) < 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator> (const char (&that)[N]) const noexcept { return this->compare(that, N-1) > 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator<= (const char (&that)[N]) const noexcept { return this->compare(that, N-1) <= 0; } - template C4_ALWAYS_INLINE C4_PURE bool operator>= (const char (&that)[N]) const noexcept { return this->compare(that, N-1) >= 0; } - - /** @} */ - -public: - - /** @name Sub-selection methods */ - /** @{ */ - - /** true if *this is a substring of that (ie, from the same buffer) */ - C4_ALWAYS_INLINE C4_PURE bool is_sub(ro_substr const that) const noexcept - { - return that.is_super(*this); - } - - /** true if that is a substring of *this (ie, from the same buffer) */ - C4_ALWAYS_INLINE C4_PURE bool is_super(ro_substr const that) const noexcept - { - if(C4_LIKELY(len > 0)) - return that.str >= str && that.str+that.len <= str+len; - else - return that.len == 0 && that.str == str && str != nullptr; - } - - /** true if there is overlap of at least one element between that and *this */ - C4_ALWAYS_INLINE C4_PURE bool overlaps(ro_substr const that) const noexcept - { - // thanks @timwynants - return that.str+that.len > str && that.str < str+len; - } - -public: - - /** return [first,len[ */ - C4_ALWAYS_INLINE C4_PURE basic_substring sub(size_t first) const noexcept - { - C4_ASSERT(first >= 0 && first <= len); - return basic_substring(str + first, len - first); - } - - /** return [first,first+num[. If num==npos, return [first,len[ */ - C4_ALWAYS_INLINE C4_PURE basic_substring sub(size_t first, size_t num) const noexcept - { - C4_ASSERT(first >= 0 && first <= len); - C4_ASSERT((num >= 0 && num <= len) || (num == npos)); - size_t rnum = num != npos ? num : len - first; - C4_ASSERT((first >= 0 && first + rnum <= len) || (num == 0)); - return basic_substring(str + first, rnum); - } - - /** return [first,last[. If last==npos, return [first,len[ */ - C4_ALWAYS_INLINE C4_PURE basic_substring range(size_t first, size_t last=npos) const noexcept - { - C4_ASSERT(first >= 0 && first <= len); - last = last != npos ? last : len; - C4_ASSERT(first <= last); - C4_ASSERT(last >= 0 && last <= len); - return basic_substring(str + first, last - first); - } - - /** return the first @p num elements: [0,num[*/ - C4_ALWAYS_INLINE C4_PURE basic_substring first(size_t num) const noexcept - { - C4_ASSERT(num <= len || num == npos); - return basic_substring(str, num != npos ? num : len); - } - - /** return the last @p num elements: [len-num,len[*/ - C4_ALWAYS_INLINE C4_PURE basic_substring last(size_t num) const noexcept - { - C4_ASSERT(num <= len || num == npos); - return num != npos ? - basic_substring(str + len - num, num) : - *this; - } - - /** offset from the ends: return [left,len-right[ ; ie, trim a - number of characters from the left and right. This is - equivalent to python's negative list indices. */ - C4_ALWAYS_INLINE C4_PURE basic_substring offs(size_t left, size_t right) const noexcept - { - C4_ASSERT(left >= 0 && left <= len); - C4_ASSERT(right >= 0 && right <= len); - C4_ASSERT(left <= len - right + 1); - return basic_substring(str + left, len - right - left); - } - - /** return [0, pos[ . Same as .first(pos), but provided for compatibility with .right_of() */ - C4_ALWAYS_INLINE C4_PURE basic_substring left_of(size_t pos) const noexcept - { - C4_ASSERT(pos <= len || pos == npos); - return (pos != npos) ? - basic_substring(str, pos) : - *this; - } - - /** return [0, pos+include_pos[ . Same as .first(pos+1), but provided for compatibility with .right_of() */ - C4_ALWAYS_INLINE C4_PURE basic_substring left_of(size_t pos, bool include_pos) const noexcept - { - C4_ASSERT(pos <= len || pos == npos); - return (pos != npos) ? - basic_substring(str, pos+include_pos) : - *this; - } - - /** return [pos+1, len[ */ - C4_ALWAYS_INLINE C4_PURE basic_substring right_of(size_t pos) const noexcept - { - C4_ASSERT(pos <= len || pos == npos); - return (pos != npos) ? - basic_substring(str + (pos + 1), len - (pos + 1)) : - basic_substring(str + len, size_t(0)); - } - - /** return [pos+!include_pos, len[ */ - C4_ALWAYS_INLINE C4_PURE basic_substring right_of(size_t pos, bool include_pos) const noexcept - { - C4_ASSERT(pos <= len || pos == npos); - return (pos != npos) ? - basic_substring(str + (pos + !include_pos), len - (pos + !include_pos)) : - basic_substring(str + len, size_t(0)); - } - -public: - - /** given @p subs a substring of the current string, get the - * portion of the current string to the left of it */ - C4_ALWAYS_INLINE C4_PURE basic_substring left_of(ro_substr const subs) const noexcept - { - C4_ASSERT(is_super(subs) || subs.empty()); - auto ssb = subs.begin(); - auto b = begin(); - auto e = end(); - if(ssb >= b && ssb <= e) - return sub(0, static_cast(ssb - b)); - else - return sub(0, 0); - } - - /** given @p subs a substring of the current string, get the - * portion of the current string to the right of it */ - C4_ALWAYS_INLINE C4_PURE basic_substring right_of(ro_substr const subs) const noexcept - { - C4_ASSERT(is_super(subs) || subs.empty()); - auto sse = subs.end(); - auto b = begin(); - auto e = end(); - if(sse >= b && sse <= e) - return sub(static_cast(sse - b), static_cast(e - sse)); - else - return sub(0, 0); - } - - /** @} */ - -public: - - /** @name Removing characters (trim()) / patterns (strip()) from the tips of the string */ - /** @{ */ - - /** trim left */ - basic_substring triml(const C c) const - { - if( ! empty()) - { - size_t pos = first_not_of(c); - if(pos != npos) - return sub(pos); - } - return sub(0, 0); - } - /** trim left ANY of the characters. - * @see stripl() to remove a pattern from the left */ - basic_substring triml(ro_substr chars) const - { - if( ! empty()) - { - size_t pos = first_not_of(chars); - if(pos != npos) - return sub(pos); - } - return sub(0, 0); - } - - /** trim the character c from the right */ - basic_substring trimr(const C c) const - { - if( ! empty()) - { - size_t pos = last_not_of(c, npos); - if(pos != npos) - return sub(0, pos+1); - } - return sub(0, 0); - } - /** trim right ANY of the characters - * @see stripr() to remove a pattern from the right */ - basic_substring trimr(ro_substr chars) const - { - if( ! empty()) - { - size_t pos = last_not_of(chars, npos); - if(pos != npos) - return sub(0, pos+1); - } - return sub(0, 0); - } - - /** trim the character c left and right */ - basic_substring trim(const C c) const - { - return triml(c).trimr(c); - } - /** trim left and right ANY of the characters - * @see strip() to remove a pattern from the left and right */ - basic_substring trim(ro_substr const chars) const - { - return triml(chars).trimr(chars); - } - - /** remove a pattern from the left - * @see triml() to remove characters*/ - basic_substring stripl(ro_substr pattern) const - { - if( ! begins_with(pattern)) - return *this; - return sub(pattern.len < len ? pattern.len : len); - } - - /** remove a pattern from the right - * @see trimr() to remove characters*/ - basic_substring stripr(ro_substr pattern) const - { - if( ! ends_with(pattern)) - return *this; - return left_of(len - (pattern.len < len ? pattern.len : len)); - } - - /** @} */ - -public: - - /** @name Lookup methods */ - /** @{ */ - - size_t find(const C c, size_t start_pos=0) const - { - return first_of(c, start_pos); - } - size_t find(ro_substr pattern, size_t start_pos=0) const - { - C4_ASSERT(start_pos == npos || (start_pos >= 0 && start_pos <= len)); - if(len < pattern.len) return npos; - for(size_t i = start_pos, e = len - pattern.len + 1; i < e; ++i) - { - bool gotit = true; - for(size_t j = 0; j < pattern.len; ++j) - { - C4_ASSERT(i + j < len); - if(str[i + j] != pattern.str[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return i; - } - } - return npos; - } - -public: - - /** count the number of occurrences of c */ - size_t count(const C c, size_t pos=0) const - { - C4_ASSERT(pos >= 0 && pos <= len); - size_t num = 0; - pos = find(c, pos); - while(pos != npos) - { - ++num; - pos = find(c, pos + 1); - } - return num; - } - - /** count the number of occurrences of s */ - size_t count(ro_substr c, size_t pos=0) const - { - C4_ASSERT(pos >= 0 && pos <= len); - size_t num = 0; - pos = find(c, pos); - while(pos != npos) - { - ++num; - pos = find(c, pos + c.len); - } - return num; - } - - /** get the substr consisting of the first occurrence of @p c after @p pos, or an empty substr if none occurs */ - basic_substring select(const C c, size_t pos=0) const - { - pos = find(c, pos); - return pos != npos ? sub(pos, 1) : basic_substring(); - } - - /** get the substr consisting of the first occurrence of @p pattern after @p pos, or an empty substr if none occurs */ - basic_substring select(ro_substr pattern, size_t pos=0) const - { - pos = find(pattern, pos); - return pos != npos ? sub(pos, pattern.len) : basic_substring(); - } - -public: - - struct first_of_any_result - { - size_t which; - size_t pos; - operator bool() const { return which != NONE && pos != npos; } - }; - - first_of_any_result first_of_any(ro_substr s0, ro_substr s1) const - { - ro_substr s[2] = {s0, s1}; - return first_of_any_iter(&s[0], &s[0] + 2); - } - - first_of_any_result first_of_any(ro_substr s0, ro_substr s1, ro_substr s2) const - { - ro_substr s[3] = {s0, s1, s2}; - return first_of_any_iter(&s[0], &s[0] + 3); - } - - first_of_any_result first_of_any(ro_substr s0, ro_substr s1, ro_substr s2, ro_substr s3) const - { - ro_substr s[4] = {s0, s1, s2, s3}; - return first_of_any_iter(&s[0], &s[0] + 4); - } - - first_of_any_result first_of_any(ro_substr s0, ro_substr s1, ro_substr s2, ro_substr s3, ro_substr s4) const - { - ro_substr s[5] = {s0, s1, s2, s3, s4}; - return first_of_any_iter(&s[0], &s[0] + 5); - } - - template - first_of_any_result first_of_any_iter(It first_span, It last_span) const - { - for(size_t i = 0; i < len; ++i) - { - size_t curr = 0; - for(It it = first_span; it != last_span; ++curr, ++it) - { - auto const& chars = *it; - if((i + chars.len) > len) continue; - bool gotit = true; - for(size_t j = 0; j < chars.len; ++j) - { - C4_ASSERT(i + j < len); - if(str[i + j] != chars[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return {curr, i}; - } - } - } - return {NONE, npos}; - } - -public: - - /** true if the first character of the string is @p c */ - bool begins_with(const C c) const - { - return len > 0 ? str[0] == c : false; - } - - /** true if the first @p num characters of the string are @p c */ - bool begins_with(const C c, size_t num) const - { - if(len < num) - { - return false; - } - for(size_t i = 0; i < num; ++i) - { - if(str[i] != c) - { - return false; - } - } - return true; - } - - /** true if the string begins with the given @p pattern */ - bool begins_with(ro_substr pattern) const - { - if(len < pattern.len) - { - return false; - } - for(size_t i = 0; i < pattern.len; ++i) - { - if(str[i] != pattern[i]) - { - return false; - } - } - return true; - } - - /** true if the first character of the string is any of the given @p chars */ - bool begins_with_any(ro_substr chars) const - { - if(len == 0) - { - return false; - } - for(size_t i = 0; i < chars.len; ++i) - { - if(str[0] == chars.str[i]) - { - return true; - } - } - return false; - } - - /** true if the last character of the string is @p c */ - bool ends_with(const C c) const - { - return len > 0 ? str[len-1] == c : false; - } - - /** true if the last @p num characters of the string are @p c */ - bool ends_with(const C c, size_t num) const - { - if(len < num) - { - return false; - } - for(size_t i = len - num; i < len; ++i) - { - if(str[i] != c) - { - return false; - } - } - return true; - } - - /** true if the string ends with the given @p pattern */ - bool ends_with(ro_substr pattern) const - { - if(len < pattern.len) - { - return false; - } - for(size_t i = 0, s = len-pattern.len; i < pattern.len; ++i) - { - if(str[s+i] != pattern[i]) - { - return false; - } - } - return true; - } - - /** true if the last character of the string is any of the given @p chars */ - bool ends_with_any(ro_substr chars) const - { - if(len == 0) - { - return false; - } - for(size_t i = 0; i < chars.len; ++i) - { - if(str[len - 1] == chars[i]) - { - return true; - } - } - return false; - } - -public: - - /** @return the first position where c is found in the string, or npos if none is found */ - size_t first_of(const C c, size_t start=0) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - for(size_t i = start; i < len; ++i) - { - if(str[i] == c) - return i; - } - return npos; - } - - /** @return the last position where c is found in the string, or npos if none is found */ - size_t last_of(const C c, size_t start=npos) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - if(start == npos) - start = len; - for(size_t i = start-1; i != size_t(-1); --i) - { - if(str[i] == c) - return i; - } - return npos; - } - - /** @return the first position where ANY of the chars is found in the string, or npos if none is found */ - size_t first_of(ro_substr chars, size_t start=0) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - for(size_t i = start; i < len; ++i) - { - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars[j]) - return i; - } - } - return npos; - } - - /** @return the last position where ANY of the chars is found in the string, or npos if none is found */ - size_t last_of(ro_substr chars, size_t start=npos) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - if(start == npos) - start = len; - for(size_t i = start-1; i != size_t(-1); --i) - { - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars[j]) - return i; - } - } - return npos; - } - -public: - - size_t first_not_of(const C c) const - { - for(size_t i = 0; i < len; ++i) - { - if(str[i] != c) - return i; - } - return npos; - } - - size_t first_not_of(const C c, size_t start) const - { - C4_ASSERT((start >= 0 && start <= len) || (start == len && len == 0)); - for(size_t i = start; i < len; ++i) - { - if(str[i] != c) - return i; - } - return npos; - } - - size_t last_not_of(const C c) const - { - for(size_t i = len-1; i != size_t(-1); --i) - { - if(str[i] != c) - return i; - } - return npos; - } - - size_t last_not_of(const C c, size_t start) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - if(start == npos) - start = len; - for(size_t i = start-1; i != size_t(-1); --i) - { - if(str[i] != c) - return i; - } - return npos; - } - - size_t first_not_of(ro_substr chars) const - { - for(size_t i = 0; i < len; ++i) - { - bool gotit = true; - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars.str[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return i; - } - } - return npos; - } - - size_t first_not_of(ro_substr chars, size_t start) const - { - C4_ASSERT((start >= 0 && start <= len) || (start == len && len == 0)); - for(size_t i = start; i < len; ++i) - { - bool gotit = true; - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars.str[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return i; - } - } - return npos; - } - - size_t last_not_of(ro_substr chars) const - { - for(size_t i = len-1; i != size_t(-1); --i) - { - bool gotit = true; - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars.str[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return i; - } - } - return npos; - } - - size_t last_not_of(ro_substr chars, size_t start) const - { - C4_ASSERT(start == npos || (start >= 0 && start <= len)); - if(start == npos) - start = len; - for(size_t i = start-1; i != size_t(-1); --i) - { - bool gotit = true; - for(size_t j = 0; j < chars.len; ++j) - { - if(str[i] == chars.str[j]) - { - gotit = false; - break; - } - } - if(gotit) - { - return i; - } - } - return npos; - } - - /** @} */ - -public: - - /** @name Range lookup methods */ - /** @{ */ - - /** get the range delimited by an open-close pair of characters. - * @note There must be no nested pairs. - * @note No checks for escapes are performed. */ - basic_substring pair_range(CC open, CC close) const - { - size_t b = find(open); - if(b == npos) - return basic_substring(); - size_t e = find(close, b+1); - if(e == npos) - return basic_substring(); - basic_substring ret = range(b, e+1); - C4_ASSERT(ret.sub(1).find(open) == npos); - return ret; - } - - /** get the range delimited by a single open-close character (eg, quotes). - * @note The open-close character can be escaped. */ - basic_substring pair_range_esc(CC open_close, CC escape=CC('\\')) - { - size_t b = find(open_close); - if(b == npos) return basic_substring(); - for(size_t i = b+1; i < len; ++i) - { - CC c = str[i]; - if(c == open_close) - { - if(str[i-1] != escape) - { - return range(b, i+1); - } - } - } - return basic_substring(); - } - - /** get the range delimited by an open-close pair of characters, - * with possibly nested occurrences. No checks for escapes are - * performed. */ - basic_substring pair_range_nested(CC open, CC close) const - { - size_t b = find(open); - if(b == npos) return basic_substring(); - size_t e, curr = b+1, count = 0; - const char both[] = {open, close, '\0'}; - while((e = first_of(both, curr)) != npos) - { - if(str[e] == open) - { - ++count; - curr = e+1; - } - else if(str[e] == close) - { - if(count == 0) return range(b, e+1); - --count; - curr = e+1; - } - } - return basic_substring(); - } - - basic_substring unquoted() const - { - constexpr const C dq('"'), sq('\''); - if(len >= 2 && (str[len - 2] != C('\\')) && - ((begins_with(sq) && ends_with(sq)) - || - (begins_with(dq) && ends_with(dq)))) - { - return range(1, len -1); - } - return *this; - } - - /** @} */ - -public: - - /** @name Number-matching query methods */ - /** @{ */ - - /** @return true if the substring contents are a floating-point or integer number. - * @note any leading or trailing whitespace will return false. */ - bool is_number() const - { - if(empty() || (first_non_empty_span().empty())) - return false; - if(first_uint_span() == *this) - return true; - if(first_int_span() == *this) - return true; - if(first_real_span() == *this) - return true; - return false; - } - - /** @return true if the substring contents are a real number. - * @note any leading or trailing whitespace will return false. */ - bool is_real() const - { - if(empty() || (first_non_empty_span().empty())) - return false; - if(first_real_span() == *this) - return true; - return false; - } - - /** @return true if the substring contents are an integer number. - * @note any leading or trailing whitespace will return false. */ - bool is_integer() const - { - if(empty() || (first_non_empty_span().empty())) - return false; - if(first_uint_span() == *this) - return true; - if(first_int_span() == *this) - return true; - return false; - } - - /** @return true if the substring contents are an unsigned integer number. - * @note any leading or trailing whitespace will return false. */ - bool is_unsigned_integer() const - { - if(empty() || (first_non_empty_span().empty())) - return false; - if(first_uint_span() == *this) - return true; - return false; - } - - /** get the first span consisting exclusively of non-empty characters */ - basic_substring first_non_empty_span() const - { - constexpr const ro_substr empty_chars(" \n\r\t"); - size_t pos = first_not_of(empty_chars); - if(pos == npos) - return first(0); - auto ret = sub(pos); - pos = ret.first_of(empty_chars); - return ret.first(pos); - } - - /** get the first span which can be interpreted as an unsigned integer */ - basic_substring first_uint_span() const - { - basic_substring ne = first_non_empty_span(); - if(ne.empty()) - return ne; - if(ne.str[0] == '-') - return first(0); - size_t skip_start = size_t(ne.str[0] == '+'); - return ne._first_integral_span(skip_start); - } - - /** get the first span which can be interpreted as a signed integer */ - basic_substring first_int_span() const - { - basic_substring ne = first_non_empty_span(); - if(ne.empty()) - return ne; - size_t skip_start = size_t(ne.str[0] == '+' || ne.str[0] == '-'); - return ne._first_integral_span(skip_start); - } - - basic_substring _first_integral_span(size_t skip_start) const - { - C4_ASSERT(!empty()); - if(skip_start == len) - return first(0); - C4_ASSERT(skip_start < len); - if(len >= skip_start + 3) - { - if(str[skip_start] != '0') - { - for(size_t i = skip_start; i < len; ++i) - { - char c = str[i]; - if(c < '0' || c > '9') - return i > skip_start && _is_delim_char(c) ? first(i) : first(0); - } - } - else - { - char next = str[skip_start + 1]; - if(next == 'x' || next == 'X') - { - skip_start += 2; - for(size_t i = skip_start; i < len; ++i) - { - const char c = str[i]; - if( ! _is_hex_char(c)) - return i > skip_start && _is_delim_char(c) ? first(i) : first(0); - } - return *this; - } - else if(next == 'b' || next == 'B') - { - skip_start += 2; - for(size_t i = skip_start; i < len; ++i) - { - const char c = str[i]; - if(c != '0' && c != '1') - return i > skip_start && _is_delim_char(c) ? first(i) : first(0); - } - return *this; - } - else if(next == 'o' || next == 'O') - { - skip_start += 2; - for(size_t i = skip_start; i < len; ++i) - { - const char c = str[i]; - if(c < '0' || c > '7') - return i > skip_start && _is_delim_char(c) ? first(i) : first(0); - } - return *this; - } - } - } - // must be a decimal, or it is not a an number - for(size_t i = skip_start; i < len; ++i) - { - const char c = str[i]; - if(c < '0' || c > '9') - return i > skip_start && _is_delim_char(c) ? first(i) : first(0); - } - return *this; - } - - /** get the first span which can be interpreted as a real (floating-point) number */ - basic_substring first_real_span() const - { - basic_substring ne = first_non_empty_span(); - if(ne.empty()) - return ne; - const size_t skip_start = (ne.str[0] == '+' || ne.str[0] == '-'); - C4_ASSERT(skip_start == 0 || skip_start == 1); - // if we have at least three digits after the leading sign, it - // can be decimal, or hex, or bin or oct. Ex: - // non-decimal: 0x0, 0b0, 0o0 - // decimal: 1.0, 10., 1e1, 100, inf, nan, infinity - if(ne.len >= skip_start+3) - { - // if it does not have leading 0, it must be decimal, or it is not a real - if(ne.str[skip_start] != '0') - { - if(ne.str[skip_start] == 'i') // is it infinity or inf? - { - basic_substring word = ne._word_follows(skip_start + 1, "nfinity"); - if(word.len) - return word; - return ne._word_follows(skip_start + 1, "nf"); - } - else if(ne.str[skip_start] == 'n') // is it nan? - { - return ne._word_follows(skip_start + 1, "an"); - } - else // must be a decimal, or it is not a real - { - return ne._first_real_span_dec(skip_start); - } - } - else // starts with 0. is it 0x, 0b or 0o? - { - const char next = ne.str[skip_start + 1]; - // hexadecimal - if(next == 'x' || next == 'X') - return ne._first_real_span_hex(skip_start + 2); - // binary - else if(next == 'b' || next == 'B') - return ne._first_real_span_bin(skip_start + 2); - // octal - else if(next == 'o' || next == 'O') - return ne._first_real_span_oct(skip_start + 2); - // none of the above. may still be a decimal. - else - return ne._first_real_span_dec(skip_start); // do not skip the 0. - } - } - // less than 3 chars after the leading sign. It is either a - // decimal or it is not a real. (cannot be any of 0x0, etc). - return ne._first_real_span_dec(skip_start); - } - - /** true if the character is a delimiter character *at the end* */ - static constexpr C4_ALWAYS_INLINE C4_CONST bool _is_delim_char(char c) noexcept - { - return c == ' ' || c == '\n' - || c == ']' || c == ')' || c == '}' - || c == ',' || c == ';' || c == '\r' || c == '\t' || c == '\0'; - } - - /** true if the character is in [0-9a-fA-F] */ - static constexpr C4_ALWAYS_INLINE C4_CONST bool _is_hex_char(char c) noexcept - { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); - } - - C4_NO_INLINE C4_PURE basic_substring _word_follows(size_t pos, csubstr word) const noexcept - { - size_t posend = pos + word.len; - if(len >= posend && sub(pos, word.len) == word) - if(len == posend || _is_delim_char(str[posend])) - return first(posend); - return first(0); - } - - // this function is declared inside the class to avoid a VS error with __declspec(dllimport) - C4_NO_INLINE C4_PURE basic_substring _first_real_span_dec(size_t pos) const noexcept - { - bool intchars = false; - bool fracchars = false; - bool powchars; - // integral part - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - { - intchars = true; - } - else if(c == '.') - { - ++pos; - goto fractional_part_dec; // NOLINT - } - else if(c == 'e' || c == 'E') - { - ++pos; - goto power_part_dec; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - // no . or p were found; this is either an integral number - // or not a number at all - return intchars ? - *this : - first(0); - fractional_part_dec: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == '.'); - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - { - fracchars = true; - } - else if(c == 'e' || c == 'E') - { - ++pos; - goto power_part_dec; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars || fracchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - return intchars || fracchars ? - *this : - first(0); - power_part_dec: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == 'e' || str[pos - 1] == 'E'); - // either digits, or +, or - are expected here, followed by more digits. - if((len == pos) || ((!intchars) && (!fracchars))) - return first(0); - if(str[pos] == '-' || str[pos] == '+') - ++pos; // skip the sign - powchars = false; - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - powchars = true; - else if(powchars && _is_delim_char(c)) - return first(pos); - else - return first(0); - } - return powchars ? *this : first(0); - } - - // this function is declared inside the class to avoid a VS error with __declspec(dllimport) - C4_NO_INLINE C4_PURE basic_substring _first_real_span_hex(size_t pos) const noexcept - { - bool intchars = false; - bool fracchars = false; - bool powchars; - // integral part - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(_is_hex_char(c)) - { - intchars = true; - } - else if(c == '.') - { - ++pos; - goto fractional_part_hex; // NOLINT - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_hex; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - // no . or p were found; this is either an integral number - // or not a number at all - return intchars ? - *this : - first(0); - fractional_part_hex: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == '.'); - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(_is_hex_char(c)) - { - fracchars = true; - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_hex; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars || fracchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - return intchars || fracchars ? - *this : - first(0); - power_part_hex: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == 'p' || str[pos - 1] == 'P'); - // either a + or a - is expected here, followed by more chars. - // also, using (pos+1) in this check will cause an early - // return when no more chars follow the sign. - if(len <= (pos+1) || (str[pos] != '+' && str[pos] != '-') || ((!intchars) && (!fracchars))) - return first(0); - ++pos; // this was the sign. - // ... so the (pos+1) ensures that we enter the loop and - // hence that there exist chars in the power part - powchars = false; - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - powchars = true; - else if(powchars && _is_delim_char(c)) - return first(pos); - else - return first(0); - } - return *this; - } - - // this function is declared inside the class to avoid a VS error with __declspec(dllimport) - C4_NO_INLINE C4_PURE basic_substring _first_real_span_bin(size_t pos) const noexcept - { - bool intchars = false; - bool fracchars = false; - bool powchars; - // integral part - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c == '0' || c == '1') - { - intchars = true; - } - else if(c == '.') - { - ++pos; - goto fractional_part_bin; // NOLINT - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_bin; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - // no . or p were found; this is either an integral number - // or not a number at all - return intchars ? - *this : - first(0); - fractional_part_bin: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == '.'); - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c == '0' || c == '1') - { - fracchars = true; - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_bin; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars || fracchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - return intchars || fracchars ? - *this : - first(0); - power_part_bin: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == 'p' || str[pos - 1] == 'P'); - // either a + or a - is expected here, followed by more chars. - // also, using (pos+1) in this check will cause an early - // return when no more chars follow the sign. - if(len <= (pos+1) || (str[pos] != '+' && str[pos] != '-') || ((!intchars) && (!fracchars))) - return first(0); - ++pos; // this was the sign. - // ... so the (pos+1) ensures that we enter the loop and - // hence that there exist chars in the power part - powchars = false; - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - powchars = true; - else if(powchars && _is_delim_char(c)) - return first(pos); - else - return first(0); - } - return *this; - } - - // this function is declared inside the class to avoid a VS error with __declspec(dllimport) - C4_NO_INLINE C4_PURE basic_substring _first_real_span_oct(size_t pos) const noexcept - { - bool intchars = false; - bool fracchars = false; - bool powchars; - // integral part - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '7') - { - intchars = true; - } - else if(c == '.') - { - ++pos; - goto fractional_part_oct; // NOLINT - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_oct; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - // no . or p were found; this is either an integral number - // or not a number at all - return intchars ? - *this : - first(0); - fractional_part_oct: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == '.'); - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '7') - { - fracchars = true; - } - else if(c == 'p' || c == 'P') - { - ++pos; - goto power_part_oct; // NOLINT - } - else if(_is_delim_char(c)) - { - return intchars || fracchars ? first(pos) : first(0); - } - else - { - return first(0); - } - } - return intchars || fracchars ? - *this : - first(0); - power_part_oct: - C4_ASSERT(pos > 0); - C4_ASSERT(str[pos - 1] == 'p' || str[pos - 1] == 'P'); - // either a + or a - is expected here, followed by more chars. - // also, using (pos+1) in this check will cause an early - // return when no more chars follow the sign. - if(len <= (pos+1) || (str[pos] != '+' && str[pos] != '-') || ((!intchars) && (!fracchars))) - return first(0); - ++pos; // this was the sign. - // ... so the (pos+1) ensures that we enter the loop and - // hence that there exist chars in the power part - powchars = false; - for( ; pos < len; ++pos) - { - const char c = str[pos]; - if(c >= '0' && c <= '9') - powchars = true; - else if(powchars && _is_delim_char(c)) - return first(pos); - else - return first(0); - } - return *this; - } - - /** @} */ - -public: - - /** @name Splitting methods */ - /** @{ */ - - /** returns true if the string has not been exhausted yet, meaning - * it's ok to call next_split() again. When no instance of sep - * exists in the string, returns the full string. When the input - * is an empty string, the output string is the empty string. */ - bool next_split(C sep, size_t *C4_RESTRICT start_pos, basic_substring *C4_RESTRICT out) const - { - if(C4_LIKELY(*start_pos < len)) - { - for(size_t i = *start_pos; i < len; i++) - { - if(str[i] == sep) - { - out->assign(str + *start_pos, i - *start_pos); - *start_pos = i+1; - return true; - } - } - out->assign(str + *start_pos, len - *start_pos); - *start_pos = len + 1; - return true; - } - else - { - bool valid = len > 0 && (*start_pos == len); - if(valid && str && str[len-1] == sep) - { - out->assign(str + len, size_t(0)); // the cast is needed to prevent overload ambiguity - } - else - { - out->assign(str + len + 1, size_t(0)); // the cast is needed to prevent overload ambiguity - } - *start_pos = len + 1; - return valid; - } - } - -private: - - struct split_proxy_impl - { - struct split_iterator_impl - { - split_proxy_impl const* m_proxy; - basic_substring m_str; - size_t m_pos; - NCC_ m_sep; - - split_iterator_impl(split_proxy_impl const* proxy, size_t pos, C sep) - : m_proxy(proxy), m_pos(pos), m_sep(sep) - { - _tick(); - } - - void _tick() - { - m_proxy->m_str.next_split(m_sep, &m_pos, &m_str); - } - - split_iterator_impl& operator++ () { _tick(); return *this; } - split_iterator_impl operator++ (int) { split_iterator_impl it = *this; _tick(); return it; } // NOLINT - - basic_substring& operator* () { return m_str; } - basic_substring* operator-> () { return &m_str; } - - bool operator!= (split_iterator_impl const& that) const - { - return !(this->operator==(that)); - } - bool operator== (split_iterator_impl const& that) const - { - C4_XASSERT((m_sep == that.m_sep) && "cannot compare split iterators with different separators"); - if(m_str.size() != that.m_str.size()) - return false; - if(m_str.data() != that.m_str.data()) - return false; - return m_pos == that.m_pos; - } - }; - - basic_substring m_str; - size_t m_start_pos; - C m_sep; - - split_proxy_impl(basic_substring str_, size_t start_pos, C sep) - : m_str(str_), m_start_pos(start_pos), m_sep(sep) - { - } - - split_iterator_impl begin() const - { - auto it = split_iterator_impl(this, m_start_pos, m_sep); - return it; - } - split_iterator_impl end() const - { - size_t pos = m_str.size() + 1; - auto it = split_iterator_impl(this, pos, m_sep); - return it; - } - }; - -public: - - using split_proxy = split_proxy_impl; - - /** a view into the splits */ - split_proxy split(C sep, size_t start_pos=0) const - { - C4_XASSERT((start_pos >= 0 && start_pos < len) || empty()); - auto ss = sub(0, len); - auto it = split_proxy(ss, start_pos, sep); - return it; - } - -public: - - /** pop right: return the first split from the right. Use - * gpop_left() to get the reciprocal part. - */ - basic_substring pop_right(C sep=C('/'), bool skip_empty=false) const - { - if(C4_LIKELY(len > 1)) - { - auto pos = last_of(sep); - if(pos != npos) - { - if(pos + 1 < len) // does not end with sep - { - return sub(pos + 1); // return from sep to end - } - else // the string ends with sep - { - if( ! skip_empty) - { - return sub(pos + 1, 0); - } - auto ppos = last_not_of(sep); // skip repeated seps - if(ppos == npos) // the string is all made of seps - { - return sub(0, 0); - } - // find the previous sep - auto pos0 = last_of(sep, ppos); - if(pos0 == npos) // only the last sep exists - { - return sub(0); // return the full string (because skip_empty is true) - } - ++pos0; - return sub(pos0); - } - } - else // no sep was found, return the full string - { - return *this; - } - } - else if(len == 1) - { - if(begins_with(sep)) - { - return sub(0, 0); - } - return *this; - } - else // an empty string - { - return basic_substring(); - } - } - - /** return the first split from the left. Use gpop_right() to get - * the reciprocal part. */ - basic_substring pop_left(C sep = C('/'), bool skip_empty=false) const - { - if(C4_LIKELY(len > 1)) - { - auto pos = first_of(sep); - if(pos != npos) - { - if(pos > 0) // does not start with sep - { - return sub(0, pos); // return everything up to it - } - else // the string starts with sep - { - if( ! skip_empty) - { - return sub(0, 0); - } - auto ppos = first_not_of(sep); // skip repeated seps - if(ppos == npos) // the string is all made of seps - { - return sub(0, 0); - } - // find the next sep - auto pos0 = first_of(sep, ppos); - if(pos0 == npos) // only the first sep exists - { - return sub(0); // return the full string (because skip_empty is true) - } - C4_XASSERT(pos0 > 0); - // return everything up to the second sep - return sub(0, pos0); - } - } - else // no sep was found, return the full string - { - return sub(0); - } - } - else if(len == 1) - { - if(begins_with(sep)) - { - return sub(0, 0); - } - return sub(0); - } - else // an empty string - { - return basic_substring(); - } - } - -public: - - /** greedy pop left. eg, csubstr("a/b/c").gpop_left('/')="c" */ - basic_substring gpop_left(C sep = C('/'), bool skip_empty=false) const - { - auto ss = pop_right(sep, skip_empty); - ss = left_of(ss); - if(ss.find(sep) != npos) - { - if(ss.ends_with(sep)) - { - if(skip_empty) - { - ss = ss.trimr(sep); - } - else - { - ss = ss.sub(0, ss.len-1); // safe to subtract because ends_with(sep) is true - } - } - } - return ss; - } - - /** greedy pop right. eg, csubstr("a/b/c").gpop_right('/')="a" */ - basic_substring gpop_right(C sep = C('/'), bool skip_empty=false) const - { - auto ss = pop_left(sep, skip_empty); - ss = right_of(ss); - if(ss.find(sep) != npos) - { - if(ss.begins_with(sep)) - { - if(skip_empty) - { - ss = ss.triml(sep); - } - else - { - ss = ss.sub(1); - } - } - } - return ss; - } - - /** @} */ - -public: - - /** @name Path-like manipulation methods */ - /** @{ */ - - basic_substring basename(C sep=C('/')) const - { - auto ss = pop_right(sep, /*skip_empty*/true); - ss = ss.trimr(sep); - return ss; - } - - basic_substring dirname(C sep=C('/')) const - { - auto ss = basename(sep); - ss = ss.empty() ? *this : left_of(ss); - return ss; - } - - C4_ALWAYS_INLINE basic_substring name_wo_extshort() const - { - return gpop_left('.'); - } - - C4_ALWAYS_INLINE basic_substring name_wo_extlong() const - { - return pop_left('.'); - } - - C4_ALWAYS_INLINE basic_substring extshort() const - { - return pop_right('.'); - } - - C4_ALWAYS_INLINE basic_substring extlong() const - { - return gpop_right('.'); - } - - /** @} */ - -public: - - /** @name Content-modification methods (only for non-const C) */ - /** @{ */ - - /** convert the string to upper-case - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) toupper() - { - for(size_t i = 0; i < len; ++i) - { - str[i] = static_cast(::toupper(str[i])); - } - } - - /** convert the string to lower-case - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) tolower() - { - for(size_t i = 0; i < len; ++i) - { - str[i] = static_cast(::tolower(str[i])); - } - } - -public: - - /** fill the entire contents with the given @p val - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) fill(C val) - { - for(size_t i = 0; i < len; ++i) - { - str[i] = val; - } - } - -public: - - /** set the current substring to a copy of the given csubstr - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) copy_from(ro_substr that, size_t ifirst=0, size_t num=npos) - { - C4_ASSERT(ifirst >= 0 && ifirst <= len); - num = num != npos ? num : len - ifirst; - num = num < that.len ? num : that.len; - C4_ASSERT(ifirst + num >= 0 && ifirst + num <= len); - // 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(num) - memcpy(str + sizeof(C) * ifirst, that.str, sizeof(C) * num); - } - -public: - - /** reverse in place - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) reverse() - { - if(len == 0) return; - detail::_do_reverse(str, str + len - 1); - } - - /** revert a subpart in place - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) reverse_sub(size_t ifirst, size_t num) - { - C4_ASSERT(ifirst >= 0 && ifirst <= len); - C4_ASSERT(ifirst + num >= 0 && ifirst + num <= len); - if(num == 0) return; - detail::_do_reverse(str + ifirst, str + ifirst + num - 1); - } - - /** revert a range in place - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(void) reverse_range(size_t ifirst, size_t ilast) - { - C4_ASSERT(ifirst >= 0 && ifirst <= len); - C4_ASSERT(ilast >= 0 && ilast <= len); - if(ifirst == ilast) return; - detail::_do_reverse(str + ifirst, str + ilast - 1); - } - -public: - - /** erase part of the string. eg, with char s[] = "0123456789", - * substr(s).erase(3, 2) = "01256789", and s is now "01245678989" - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(basic_substring) erase(size_t pos, size_t num) - { - C4_ASSERT(pos >= 0 && pos+num <= len); - size_t num_to_move = len - pos - num; - memmove(str + pos, str + pos + num, sizeof(C) * num_to_move); - return basic_substring{str, len - num}; - } - - /** @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(basic_substring) erase_range(size_t first, size_t last) - { - C4_ASSERT(first <= last); - return erase(first, static_cast(last-first)); // NOLINT - } - - /** erase a part of the string. - * @note @p sub must be a substring of this string - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(basic_substring) erase(ro_substr sub) - { - C4_ASSERT(is_super(sub)); - C4_ASSERT(sub.str >= str); - return erase(static_cast(sub.str - str), sub.len); - } - -public: - - /** replace every occurrence of character @p value with the character @p repl - * @return the number of characters that were replaced - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(size_t) replace(C value, C repl, size_t pos=0) - { - C4_ASSERT((pos >= 0 && pos <= len) || pos == npos); - size_t did_it = 0; - while((pos = find(value, pos)) != npos) - { - str[pos++] = repl; - ++did_it; - } - return did_it; - } - - /** replace every occurrence of each character in @p value with - * the character @p repl. - * @return the number of characters that were replaced - * @note this method requires that the string memory is writeable and is SFINAEd out for const C */ - C4_REQUIRE_RW(size_t) replace(ro_substr chars, C repl, size_t pos=0) - { - C4_ASSERT((pos >= 0 && pos <= len) || pos == npos); - size_t did_it = 0; - while((pos = first_of(chars, pos)) != npos) - { - str[pos++] = repl; - ++did_it; - } - return did_it; - } - - /** replace @p pattern with @p repl, and write the result into - * @p dst. pattern and repl don't need equal sizes. - * - * @return the required size for dst. No overflow occurs if - * dst.len is smaller than the required size; this can be used to - * determine the required size for an existing container. */ - size_t replace_all(rw_substr dst, ro_substr pattern, ro_substr repl, size_t pos=0) const - { - C4_ASSERT( ! pattern.empty()); //!< @todo relax this precondition - C4_ASSERT( ! this ->overlaps(dst)); //!< @todo relax this precondition - C4_ASSERT( ! pattern.overlaps(dst)); - C4_ASSERT( ! repl .overlaps(dst)); - C4_ASSERT((pos >= 0 && pos <= len) || pos == npos); - C4_SUPPRESS_WARNING_GCC_PUSH - C4_SUPPRESS_WARNING_GCC("-Warray-bounds") // gcc11 has a false positive here - #if (!defined(__clang__)) && (defined(__GNUC__) && (__GNUC__ >= 7)) - C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow") // gcc11 has a false positive here - #endif - #define _c4append(first, last) \ - { \ - C4_ASSERT((last) >= (first)); \ - size_t num = static_cast((last) - (first)); \ - if(num > 0 && sz + num <= dst.len) \ - { \ - memcpy(dst.str + sz, first, num * sizeof(C)); \ - } \ - sz += num; \ - } - size_t sz = 0; - size_t b = pos; - _c4append(str, str + pos); - do { - size_t e = find(pattern, b); - if(e == npos) - { - _c4append(str + b, str + len); - break; - } - _c4append(str + b, str + e); - _c4append(repl.begin(), repl.end()); - b = e + pattern.size(); - } while(b < len && b != npos); - return sz; - #undef _c4append - C4_SUPPRESS_WARNING_GCC_POP - } - - /** @} */ - -}; // template class basic_substring - - -#undef C4_REQUIRE_RW - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/** @defgroup doc_substr_adapters substr adapters - * - * to_substr() and to_csubstr() is used in generic code like - * format(), and allow adding construction of substrings from new - * types like containers. - * @{ */ - - -/** neutral version for use in generic code */ -C4_ALWAYS_INLINE substr to_substr(substr s) noexcept { return s; } -/** neutral version for use in generic code */ -C4_ALWAYS_INLINE csubstr to_csubstr(substr s) noexcept { return s; } -/** neutral version for use in generic code */ -C4_ALWAYS_INLINE csubstr to_csubstr(csubstr s) noexcept { return s; } - - -template -C4_ALWAYS_INLINE substr -to_substr(char (&s)[N]) noexcept { substr ss(s, N-1); return ss; } -template -C4_ALWAYS_INLINE csubstr -to_csubstr(const char (&s)[N]) noexcept { csubstr ss(s, N-1); return ss; } - - -/** @note this overload uses SFINAE to prevent it from overriding the array overload - * @see For a more detailed explanation on why the plain overloads cannot - * coexist, see http://cplusplus.bordoon.com/specializeForCharacterArrays.html */ -template -C4_ALWAYS_INLINE typename std::enable_if::value, substr>::type -to_substr(U s) noexcept { substr ss(s); return ss; } -/** @note this overload uses SFINAE to prevent it from overriding the array overload - * @see For a more detailed explanation on why the plain overloads cannot - * coexist, see http://cplusplus.bordoon.com/specializeForCharacterArrays.html */ -template -C4_ALWAYS_INLINE typename std::enable_if::value || std::is_same::value, csubstr>::type -to_csubstr(U s) noexcept { csubstr ss(s); return ss; } - - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_substr_cmp substr comparison operators - * @{ */ - -template inline bool operator== (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) == 0; } -template inline bool operator!= (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) != 0; } -template inline bool operator< (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) > 0; } -template inline bool operator> (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) < 0; } -template inline bool operator<= (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) >= 0; } -template inline bool operator>= (const char (&s)[N], basic_substring const that) noexcept { return that.compare(s, N-1) <= 0; } - -template inline bool operator== (const char c, basic_substring const that) noexcept { return that.compare(c) == 0; } -template inline bool operator!= (const char c, basic_substring const that) noexcept { return that.compare(c) != 0; } -template inline bool operator< (const char c, basic_substring const that) noexcept { return that.compare(c) > 0; } -template inline bool operator> (const char c, basic_substring const that) noexcept { return that.compare(c) < 0; } -template inline bool operator<= (const char c, basic_substring const that) noexcept { return that.compare(c) >= 0; } -template inline bool operator>= (const char c, basic_substring const that) noexcept { return that.compare(c) <= 0; } - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/* C4_SUBSTR_NO_OSTREAM_LSHIFT doctest does not deal well with - * template operator<< - * @see https://github.com/onqtam/doctest/pull/431 */ -#ifndef C4_SUBSTR_NO_OSTREAM_LSHIFT -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wsign-conversion" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -/** output the string to a stream */ -template -inline OStream& operator<< (OStream& os, basic_substring s) -{ - os.write(s.str, s.len); - return os; -} - -// this causes ambiguity -///** this is used by google test */ -//template -//inline void PrintTo(basic_substring s, OStream* os) -//{ -// os->write(s.str, s.len); -//} - -#ifdef __clang__ -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif -#endif // !C4_SUBSTR_NO_OSTREAM_LSHIFT - -/** @} */ - -} // namespace c4 - - -#ifdef __clang__ -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -#endif /* _C4_SUBSTR_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/substr_fwd.hpp b/3rdparty/rapidyaml/include/c4/substr_fwd.hpp deleted file mode 100644 index 63d01b5950..0000000000 --- a/3rdparty/rapidyaml/include/c4/substr_fwd.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _C4_SUBSTR_FWD_HPP_ -#define _C4_SUBSTR_FWD_HPP_ - -#include "c4/export.hpp" - -namespace c4 { - -#ifndef DOXYGEN -template struct basic_substring; -using csubstr = C4CORE_EXPORT basic_substring; -using substr = C4CORE_EXPORT basic_substring; -#endif // !DOXYGEN - -} // namespace c4 - -#endif /* _C4_SUBSTR_FWD_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/szconv.hpp b/3rdparty/rapidyaml/include/c4/szconv.hpp deleted file mode 100644 index e571f9f3d0..0000000000 --- a/3rdparty/rapidyaml/include/c4/szconv.hpp +++ /dev/null @@ -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 - -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 -struct is_narrower_size : std::conditional -< - (std::is_signed::value == std::is_signed::value) - ? - (sizeof(SizeOut) < sizeof(SizeIn)) - : - ( - (sizeof(SizeOut) < sizeof(SizeIn)) - || - ( - (sizeof(SizeOut) == sizeof(SizeIn)) - && - (std::is_signed::value && std::is_unsigned::value) - ) - ), - std::true_type, - std::false_type ->::type -{ - static_assert(std::is_integral::value, "must be integral type"); - static_assert(std::is_integral::value, "must be integral type"); -}; - - -/** when SizeOut is wider than SizeIn, assignment can occur without reservations */ -template -C4_ALWAYS_INLINE -typename std::enable_if< ! is_narrower_size::value, SizeOut>::type -szconv(SizeIn sz) noexcept -{ - return static_cast(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 -C4_ALWAYS_INLINE -typename std::enable_if::value, SizeOut>::type -szconv(SizeIn sz) -{ - C4_XASSERT(sz >= 0); - C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits::max(), "size conversion overflow: in=%zu", (size_t)sz); - SizeOut szo = static_cast(sz); - return szo; -} - -C4_SUPPRESS_WARNING_GCC_CLANG_POP - -} // namespace c4 - -#endif /* _C4_SZCONV_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/types.hpp b/3rdparty/rapidyaml/include/c4/types.hpp deleted file mode 100644 index 77527996cf..0000000000 --- a/3rdparty/rapidyaml/include/c4/types.hpp +++ /dev/null @@ -1,507 +0,0 @@ -#ifndef _C4_TYPES_HPP_ -#define _C4_TYPES_HPP_ - -#include -#include -#include - -#if __cplusplus >= 201103L -#include // 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::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 -struct cref_uses_val -{ - enum { value = ( - std::is_scalar::value - || - ( -#if C4_CPP >= 20 - (std::is_trivially_copyable::value && std::is_standard_layout::value) -#else - std::is_pod::value -#endif - && - sizeof(T) <= sizeof(size_t))) }; -}; -/** utility macro to override the default behaviour for c4::fastcref - @see fastcref */ -#define C4_CREF_USES_VAL(T) \ -template<> \ -struct cref_uses_val \ -{ \ - enum { value = true }; \ -}; - -/** Whether to use pass-by-value or pass-by-const-reference in a function argument - * or return type. */ -template -using fastcref = typename std::conditional::value, T, T const&>::type; - -//-------------------------------------------------- - -/** Just what its name says. Useful sometimes as a default empty policy class. */ -struct EmptyStruct // NOLINT -{ - template 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 EmptyStructVirtual(T && ...){} // NOLINT -}; - - -/** */ -template -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 -struct Padded : public T -{ - using T::T; - using T::operator=; - Padded(T const& val) : T(val) {} - Padded(T && val) : T(std::forward(val)) {} // NOLINT - char ___c4padspace___[BytesToPadAtEnd]; -}; -#pragma pack(pop) -/** When the padding argument is 0, we cannot declare the char[] array. */ -template -struct Padded : public T -{ - using T::T; - using T::operator=; - Padded(T const& val) : T(val) {} - Padded(T && val) : T(std::forward(val)) {} // NOLINT -}; - -/** make T have a size which is at least Min bytes */ -template -using MinSized = Padded; - -/** make T have a size which is a multiple of Mult bytes */ -template -using MultSized = Padded; - -/** make T have a size which is simultaneously: - * -bigger or equal than Min - * -a multiple of Mult */ -template -using MinMultSized = MultSized, Mult>; - -/** make T be suitable for use as a uniform buffer. (at least with DirectX). */ -template -using UbufSized = MinMultSized; - - -//----------------------------------------------------------------------------- - -#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::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 class X, typename T> struct is_instance_of_tpl : std::false_type {}; -template class X, typename... Y> struct is_instance_of_tpl> : 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::value)> -void foo() { std::cout << "pod type\n"; } - -// define an overload for a non-pod type -template::value)> -void foo() { std::cout << "nonpod type\n"; } - -struct non_pod -{ - non_pod() : name("asdfkjhasdkjh") {} - const char *name; -}; - -int main() -{ - foo(); // prints "pod type" - foo(); // prints "nonpod type" -} -@endcode */ -#define C4_REQUIRE_T(cond) typename std::enable_if::type* = nullptr - -/** enable_if for a return type - * @see C4_REQUIRE_T */ -#define C4_REQUIRE_R(cond, type_) typename std::enable_if::type - -//----------------------------------------------------------------------------- -/** define a traits class reporting whether a type provides a member typedef */ -#define C4_DEFINE_HAS_TYPEDEF(member_typedef) \ -template \ -struct has_##stype \ -{ \ -private: \ - \ - typedef char yes; \ - typedef struct { char array[2]; } no; \ - \ - template \ - static yes _test(typename C::member_typedef*); \ - \ - template \ - static no _test(...); \ - \ -public: \ - \ - enum { value = (sizeof(_test(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::type; \ - using difference_type = typename std::make_signed::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::type; \ - using difference_type = typename std::make_signed::type; \ - \ - template using value_type = typename std::tuple_element< n, std::tuple>::type; \ - template using pointer = value_type*; \ - template using const_pointer = value_type const*; \ - template using reference = value_type&; \ - template using const_reference = value_type 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; \ - using const_reverse_iterator = std::reverse_iterator - - -#define _c4_DEFINE_TUPLE_ARRAY_TYPES(interior_types, I) \ - \ - _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I); \ - \ - template using iterator = value_type*; \ - template using const_iterator = value_type const*; \ - template using reverse_iterator = std::reverse_iterator< value_type*>; \ - template using const_reverse_iterator = std::reverse_iterator< value_type 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 -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 -using index_sequence = integer_sequence; - -/** @cond DONT_DOCUMENT_THIS */ -namespace __detail { - -template -struct __repeat; - -template -struct __repeat, _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 struct __parity; -template struct __make : __parity<_Np % 8>::template __pmake<_Np> {}; - -template<> struct __make<0> { using type = integer_sequence; }; -template<> struct __make<1> { using type = integer_sequence; }; -template<> struct __make<2> { using type = integer_sequence; }; -template<> struct __make<3> { using type = integer_sequence; }; -template<> struct __make<4> { using type = integer_sequence; }; -template<> struct __make<5> { using type = integer_sequence; }; -template<> struct __make<6> { using type = integer_sequence; }; -template<> struct __make<7> { using type = integer_sequence; }; - -template<> struct __parity<0> { template struct __pmake : __repeat::type> {}; }; -template<> struct __parity<1> { template struct __pmake : __repeat::type, _Np - 1> {}; }; -template<> struct __parity<2> { template struct __pmake : __repeat::type, _Np - 2, _Np - 1> {}; }; -template<> struct __parity<3> { template struct __pmake : __repeat::type, _Np - 3, _Np - 2, _Np - 1> {}; }; -template<> struct __parity<4> { template struct __pmake : __repeat::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; -template<> struct __parity<5> { template struct __pmake : __repeat::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; -template<> struct __parity<6> { template struct __pmake : __repeat::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; -template<> struct __parity<7> { template struct __pmake : __repeat::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; - -template -struct __convert -{ - template struct __result; - template<_Tp ..._Np> struct __result> - { - using type = integer_sequence<_Up, _Np...>; - }; -}; - -template -struct __convert<_Tp, _Tp> -{ - template struct __result - { - using type = _Up; - }; -}; - -template -using __make_integer_sequence_unchecked = typename __detail::__convert::template __result::type>::type; - -template -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 -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 -using make_index_sequence = make_integer_sequence; - -/** 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 -using index_sequence_for = make_index_sequence; -#endif - -/** @} */ - - -} // namespace c4 - -// NOLINTEND(bugprone-macro-parentheses) - -#endif /* _C4_TYPES_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/utf.hpp b/3rdparty/rapidyaml/include/c4/utf.hpp deleted file mode 100644 index 362e3dc85b..0000000000 --- a/3rdparty/rapidyaml/include/c4/utf.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef C4_UTF_HPP_ -#define C4_UTF_HPP_ - -#include "c4/language.hpp" -#include "c4/substr_fwd.hpp" -#include -#include - -/** @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_ diff --git a/3rdparty/rapidyaml/include/c4/windows.hpp b/3rdparty/rapidyaml/include/c4/windows.hpp deleted file mode 100644 index d94c66c55c..0000000000 --- a/3rdparty/rapidyaml/include/c4/windows.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _C4_WINDOWS_HPP_ -#define _C4_WINDOWS_HPP_ - -#if defined(_WIN64) || defined(_WIN32) -#include "c4/windows_push.hpp" -#include -#include "c4/windows_pop.hpp" -#endif - -#endif /* _C4_WINDOWS_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/windows_pop.hpp b/3rdparty/rapidyaml/include/c4/windows_pop.hpp deleted file mode 100644 index e055af6fad..0000000000 --- a/3rdparty/rapidyaml/include/c4/windows_pop.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/windows_push.hpp b/3rdparty/rapidyaml/include/c4/windows_push.hpp deleted file mode 100644 index 156fe2fb40..0000000000 --- a/3rdparty/rapidyaml/include/c4/windows_push.hpp +++ /dev/null @@ -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 - * - * @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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/common.hpp b/3rdparty/rapidyaml/include/c4/yml/common.hpp deleted file mode 100644 index c4afa6361e..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/common.hpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#if defined(C4_MSVC) || defined(C4_MINGW) || defined(_WIN32) || defined(C4_WIN) -#include -#else -#include -#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::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::value, "LineCol not trivially copyable"); -static_assert(std::is_trivially_default_constructible::value, "LineCol not trivially default constructible"); -static_assert(std::is_standard_layout::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(*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::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 -[[noreturn]] inline void error(const char (&msg)[N], Location loc) -{ - error(msg, N-1, loc); -} -template -[[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 -struct _charconstant_t - : public std::conditional::value, - std::integral_constant(unsignedval)>, - std::integral_constant>::type -{}; -#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t::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 -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), writebuf, fmt, std::forward(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(_alloca(bufsize)), bufsize}; - #else - substr largerbuf = {static_cast(alloca(bufsize)), bufsize}; - #endif - results = format_dump_resume(std::forward(dumpfn), results, largerbuf, fmt, std::forward(args)...); - } -} -template -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/detail/checks.hpp b/3rdparty/rapidyaml/include/c4/yml/detail/checks.hpp deleted file mode 100644 index dfc66d8a8e..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/detail/checks.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/detail/dbgprint.hpp b/3rdparty/rapidyaml/include/c4/yml/detail/dbgprint.hpp deleted file mode 100644 index 3423787a2b..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/detail/dbgprint.hpp +++ /dev/null @@ -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 -#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 -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 -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/detail/print.hpp b/3rdparty/rapidyaml/include/c4/yml/detail/print.hpp deleted file mode 100644 index dd10964ae2..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/detail/print.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/detail/stack.hpp b/3rdparty/rapidyaml/include/c4/yml/detail/stack.hpp deleted file mode 100644 index 1ae9f57bc4..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/detail/stack.hpp +++ /dev/null @@ -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 -#endif - -#include - -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 stack -{ - static_assert(std::is_trivially_copyable::value, "T must be trivially copyable"); - static_assert(std::is_trivially_destructible::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 -void stack::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 -void stack::_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 -void stack::_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 -void stack::_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 -void stack::_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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/emit.def.hpp b/3rdparty/rapidyaml/include/c4/yml/emit.def.hpp deleted file mode 100644 index 7257e82b34..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/emit.def.hpp +++ /dev/null @@ -1,1084 +0,0 @@ -#ifndef _C4_YML_EMIT_DEF_HPP_ -#define _C4_YML_EMIT_DEF_HPP_ - -#ifndef _C4_YML_EMIT_HPP_ -#include "c4/yml/emit.hpp" -#endif - -/** @file emit.def.hpp Definitions for emit functions. */ -#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_ -#include "c4/yml/detail/dbgprint.hpp" -#endif - -namespace c4 { -namespace yml { - -template -substr Emitter::emit_as(EmitType_e type, Tree const& t, id_type id, bool error_on_excess) -{ - if(t.empty()) - { - _RYML_CB_ASSERT(t.callbacks(), id == NONE); - return {}; - } - if(id == NONE) - id = t.root_id(); - _RYML_CB_CHECK(t.callbacks(), id < t.capacity()); - m_tree = &t; - m_flow = false; - if(type == EMIT_YAML) - _emit_yaml(id); - else if(type == EMIT_JSON) - _do_visit_json(id, 0); - else - _RYML_CB_ERR(m_tree->callbacks(), "unknown emit type"); - m_tree = nullptr; - return this->Writer::_get(error_on_excess); -} - - -//----------------------------------------------------------------------------- - -template -void Emitter::_emit_yaml(id_type id) -{ - // save branches in the visitor by doing the initial stream/doc - // logic here, sparing the need to check stream/val/keyval inside - // the visitor functions - auto dispatch = [this](id_type node){ - NodeType ty = m_tree->type(node); - if(ty.is_flow_sl()) - _do_visit_flow_sl(node, 0); - else if(ty.is_flow_ml()) - _do_visit_flow_ml(node, 0); - else - { - _do_visit_block(node, 0); - } - }; - if(!m_tree->is_root(id)) - { - if(m_tree->is_container(id) && !m_tree->type(id).is_flow()) - { - id_type ilevel = 0; - if(m_tree->has_key(id)) - { - this->Writer::_do_write(m_tree->key(id)); - this->Writer::_do_write(":\n"); - ++ilevel; - } - _do_visit_block_container(id, 0, ilevel, ilevel); - return; - } - } - - TagDirectiveRange tagds = m_tree->tag_directives(); - auto write_tag_directives = [&tagds, this](const id_type next_node){ - TagDirective const* C4_RESTRICT end = tagds.b; - while(end < tagds.e) - { - if(end->next_node_id > next_node) - break; - ++end; - } - const id_type parent = m_tree->parent(next_node); - for( ; tagds.b != end; ++tagds.b) - { - if(next_node != m_tree->first_child(parent)) - this->Writer::_do_write("...\n"); - this->Writer::_do_write("%TAG "); - this->Writer::_do_write(tagds.b->handle); - this->Writer::_do_write(' '); - this->Writer::_do_write(tagds.b->prefix); - this->Writer::_do_write('\n'); - } - }; - if(m_tree->is_stream(id)) - { - const id_type first_child = m_tree->first_child(id); - if(first_child != NONE) - write_tag_directives(first_child); - for(id_type child = first_child; child != NONE; child = m_tree->next_sibling(child)) - { - dispatch(child); - if(m_tree->is_doc(child) && m_tree->type(child).is_flow_sl()) - this->Writer::_do_write('\n'); - if(m_tree->next_sibling(child) != NONE) - write_tag_directives(m_tree->next_sibling(child)); - } - } - else if(m_tree->is_container(id)) - { - dispatch(id); - } - else if(m_tree->is_doc(id)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_container(id)); // checked above - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_val(id)); // so it must be a val - _write_doc(id); - } - else if(m_tree->is_keyval(id)) - { - _writek(id, 0); - this->Writer::_do_write(": "); - _writev(id, 0); - if(!m_tree->type(id).is_flow()) - this->Writer::_do_write('\n'); - } - else if(m_tree->is_val(id)) - { - //this->Writer::_do_write("- "); - _writev(id, 0); - if(!m_tree->type(id).is_flow()) - this->Writer::_do_write('\n'); - } - else if(m_tree->type(id) == NOTYPE) - { - ; - } - else - { - _RYML_CB_ERR(m_tree->callbacks(), "unknown type"); - } -} - -#define _rymlindent_nextline() this->_indent(ilevel + 1); - -template -void Emitter::_write_doc(id_type id) -{ - const NodeType ty = m_tree->type(id); - RYML_ASSERT(ty.is_doc()); - RYML_ASSERT(!ty.has_key()); - if(!m_tree->is_root(id)) - { - RYML_ASSERT(m_tree->is_stream(m_tree->parent(id))); - this->Writer::_do_write("---"); - } - // - if(!ty.has_val()) // this is more frequent - { - const bool tag = ty.has_val_tag(); - const bool anchor = ty.has_val_anchor(); - if(!tag && !anchor) - { - ; - } - else if(!tag && anchor) - { - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(id)); - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - if(m_tree->has_children(id) && m_tree->is_root(id)) - this->Writer::_do_write('\n'); - #endif - } - else if(tag && !anchor) - { - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(id)); - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - if(m_tree->has_children(id) && m_tree->is_root(id)) - this->Writer::_do_write('\n'); - #endif - } - else // tag && anchor - { - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(id)); - this->Writer::_do_write(" &"); - this->Writer::_do_write(m_tree->val_anchor(id)); - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - if(m_tree->has_children(id) && m_tree->is_root(id)) - this->Writer::_do_write('\n'); - #endif - } - } - else // docval - { - _RYML_CB_ASSERT(m_tree->callbacks(), ty.has_val()); - // some plain scalars such as '...' and '---' must not - // appear at 0-indentation - const csubstr val = m_tree->val(id); - const bool preceded_by_3_dashes = !m_tree->is_root(id); - const type_bits style_marks = ty & VAL_STYLE; - const bool is_plain = ty.is_val_plain(); - const bool is_ambiguous = (is_plain || !style_marks) - && ((val.begins_with("...") || val.begins_with("---")) - || - (val.find('\n') != npos)); - if(preceded_by_3_dashes) - { - if(is_plain && val.len == 0 && !ty.has_val_anchor() && !ty.has_val_tag()) - { - this->Writer::_do_write('\n'); - return; - } - else if(val.len && is_ambiguous) - { - this->Writer::_do_write('\n'); - } - else - { - this->Writer::_do_write(' '); - } - } - id_type ilevel = 0u; - if(is_ambiguous) - { - _rymlindent_nextline(); - ++ilevel; - } - _writev(id, ilevel); - if(val.len && m_tree->is_root(id)) - this->Writer::_do_write('\n'); - } - if(!m_tree->is_root(id)) - this->Writer::_do_write('\n'); -} - -template -void Emitter::_do_visit_flow_sl(id_type node, id_type depth, id_type ilevel) -{ - const bool prev_flow = m_flow; - m_flow = true; - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node)); - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node)); - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node))); - if(C4_UNLIKELY(depth > m_opts.max_depth())) - _RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded"); - - if(m_tree->is_doc(node)) - { - _write_doc(node); - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - if(!m_tree->has_children(node)) - return; - else - #endif - { - if(m_tree->is_map(node)) - { - this->Writer::_do_write('{'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node)); - this->Writer::_do_write('['); - } - } - } - else if(m_tree->is_container(node)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node)); - - bool spc = false; // write a space - - if(m_tree->has_key(node)) - { - _writek(node, ilevel); - this->Writer::_do_write(':'); - spc = true; - } - - if(m_tree->has_val_tag(node)) - { - if(spc) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(node)); - spc = true; - } - - if(m_tree->has_val_anchor(node)) - { - if(spc) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(node)); - spc = true; - } - - if(spc) - this->Writer::_do_write(' '); - - if(m_tree->is_map(node)) - { - this->Writer::_do_write('{'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node)); - this->Writer::_do_write('['); - } - } // container - - for(id_type child = m_tree->first_child(node), count = 0; child != NONE; child = m_tree->next_sibling(child)) - { - if(count++) - this->Writer::_do_write(','); - if(m_tree->is_keyval(child)) - { - _writek(child, ilevel); - this->Writer::_do_write(": "); - _writev(child, ilevel); - } - else if(m_tree->is_val(child)) - { - _writev(child, ilevel); - } - else - { - // with single-line flow, we can never go back to block - _do_visit_flow_sl(child, depth + 1, ilevel + 1); - } - } - - if(m_tree->is_map(node)) - { - this->Writer::_do_write('}'); - } - else if(m_tree->is_seq(node)) - { - this->Writer::_do_write(']'); - } - m_flow = prev_flow; -} - -C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable error, triggered by flow_ml not implemented - -template -void Emitter::_do_visit_flow_ml(id_type id, id_type depth, id_type ilevel, id_type do_indent) -{ - C4_UNUSED(id); - C4_UNUSED(depth); - C4_UNUSED(ilevel); - C4_UNUSED(do_indent); - c4::yml::error("not implemented"); - #ifdef THIS_IS_A_WORK_IN_PROGRESS - if(C4_UNLIKELY(depth > m_opts.max_depth())) - _RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded"); - const bool prev_flow = m_flow; - m_flow = true; - // do it... - m_flow = prev_flow; - #endif -} - -template -void Emitter::_do_visit_block_container(id_type node, id_type depth, id_type level, bool do_indent) -{ - if(m_tree->is_seq(node)) - { - for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child)); - if(m_tree->is_val(child)) - { - _indent(level, do_indent); - this->Writer::_do_write("- "); - _writev(child, level); - this->Writer::_do_write('\n'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child)); - NodeType ty = m_tree->type(child); - if(ty.is_flow_sl()) - { - _indent(level, do_indent); - this->Writer::_do_write("- "); - _do_visit_flow_sl(child, depth+1, 0u); - this->Writer::_do_write('\n'); - } - else if(ty.is_flow_ml()) - { - _indent(level, do_indent); - this->Writer::_do_write("- "); - _do_visit_flow_ml(child, depth+1, 0u, do_indent); - this->Writer::_do_write('\n'); - } - else - { - _do_visit_block(child, depth+1, level, do_indent); // same indentation level - } - } - do_indent = true; - } - } - else // map - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node)); - for(id_type ich = m_tree->first_child(node); ich != NONE; ich = m_tree->next_sibling(ich)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich)); - if(m_tree->is_keyval(ich)) - { - _indent(level, do_indent); - _writek(ich, level); - this->Writer::_do_write(": "); - _writev(ich, level); - this->Writer::_do_write('\n'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich)); - NodeType ty = m_tree->type(ich); - if(ty.is_flow_sl()) - { - _indent(level, do_indent); - _do_visit_flow_sl(ich, depth+1, 0u); - this->Writer::_do_write('\n'); - } - else if(ty.is_flow_ml()) - { - _indent(level, do_indent); - _do_visit_flow_ml(ich, depth+1, 0u); - this->Writer::_do_write('\n'); - } - else - { - _do_visit_block(ich, depth+1, level, do_indent); // same level! - } - } // keyval vs container - do_indent = true; - } // for children - } // seq vs map -} - -template -void Emitter::_do_visit_block(id_type node, id_type depth, id_type ilevel, id_type do_indent) -{ - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node)); - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node)); - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node))); - if(C4_UNLIKELY(depth > m_opts.max_depth())) - _RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded"); - if(m_tree->is_doc(node)) - { - _write_doc(node); - if(!m_tree->has_children(node)) - return; - } - else if(m_tree->is_container(node)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node)); - bool spc = false; // write a space - bool nl = false; // write a newline - if(m_tree->has_key(node)) - { - _indent(ilevel, do_indent); - _writek(node, ilevel); - this->Writer::_do_write(':'); - spc = true; - } - else if(!m_tree->is_root(node)) - { - _indent(ilevel, do_indent); - this->Writer::_do_write('-'); - spc = true; - } - - if(m_tree->has_val_tag(node)) - { - if(spc) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(node)); - spc = true; - nl = true; - } - - if(m_tree->has_val_anchor(node)) - { - if(spc) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(node)); - spc = true; - nl = true; - } - - if(m_tree->has_children(node)) - { - if(m_tree->has_key(node)) - nl = true; - else - if(!m_tree->is_root(node) && !nl) - spc = true; - } - else - { - if(m_tree->is_seq(node)) - this->Writer::_do_write(" []\n"); - else if(m_tree->is_map(node)) - this->Writer::_do_write(" {}\n"); - return; - } - - if(spc && !nl) - this->Writer::_do_write(' '); - - do_indent = 0; - if(nl) - { - this->Writer::_do_write('\n'); - do_indent = 1; - } - } // container - - id_type next_level = ilevel + 1; - if(m_tree->is_root(node) || m_tree->is_doc(node)) - next_level = ilevel; // do not indent at top level - - _do_visit_block_container(node, depth, next_level, do_indent); -} - -C4_SUPPRESS_WARNING_MSVC_POP - - -template -void Emitter::_do_visit_json(id_type id, id_type depth) -{ - _RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(id)); // JSON does not have streams - if(C4_UNLIKELY(depth > m_opts.max_depth())) - _RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded"); - if(m_tree->is_keyval(id)) - { - _writek_json(id); - this->Writer::_do_write(": "); - _writev_json(id); - } - else if(m_tree->is_val(id)) - { - _writev_json(id); - } - else if(m_tree->is_container(id)) - { - if(m_tree->has_key(id)) - { - _writek_json(id); - this->Writer::_do_write(": "); - } - if(m_tree->is_seq(id)) - this->Writer::_do_write('['); - else if(m_tree->is_map(id)) - this->Writer::_do_write('{'); - } // container - - for(id_type ich = m_tree->first_child(id); ich != NONE; ich = m_tree->next_sibling(ich)) - { - if(ich != m_tree->first_child(id)) - this->Writer::_do_write(','); - _do_visit_json(ich, depth+1); - } - - if(m_tree->is_seq(id)) - this->Writer::_do_write(']'); - else if(m_tree->is_map(id)) - this->Writer::_do_write('}'); -} - -template -void Emitter::_write(NodeScalar const& C4_RESTRICT sc, NodeType flags, id_type ilevel) -{ - if( ! sc.tag.empty()) - { - _write_tag(sc.tag); - this->Writer::_do_write(' '); - } - if(flags.has_anchor()) - { - RYML_ASSERT(flags.is_ref() != flags.has_anchor()); - RYML_ASSERT( ! sc.anchor.empty()); - this->Writer::_do_write('&'); - this->Writer::_do_write(sc.anchor); - this->Writer::_do_write(' '); - } - else if(flags.is_ref()) - { - if(sc.anchor != "<<") - this->Writer::_do_write('*'); - this->Writer::_do_write(sc.anchor); - if(flags.is_key_ref()) - this->Writer::_do_write(' '); - return; - } - - // ensure the style flags only have one of KEY or VAL - _RYML_CB_ASSERT(m_tree->callbacks(), ((flags & SCALAR_STYLE) == 0) || (((flags & KEY_STYLE) == 0) != ((flags & VAL_STYLE) == 0))); - type_bits style_marks = flags & SCALAR_STYLE; - if(!style_marks) - style_marks = scalar_style_choose(sc.scalar); - if(style_marks & (KEY_LITERAL|VAL_LITERAL)) - { - _write_scalar_literal(sc.scalar, ilevel, flags.has_key()); - } - else if(style_marks & (KEY_FOLDED|VAL_FOLDED)) - { - _write_scalar_folded(sc.scalar, ilevel, flags.has_key()); - } - else if(style_marks & (KEY_SQUO|VAL_SQUO)) - { - _write_scalar_squo(sc.scalar, ilevel); - } - else if(style_marks & (KEY_DQUO|VAL_DQUO)) - { - _write_scalar_dquo(sc.scalar, ilevel); - } - else if(style_marks & (KEY_PLAIN|VAL_PLAIN)) - { - if(C4_LIKELY(!(sc.scalar.begins_with(": ") || sc.scalar.begins_with(":\t")))) - _write_scalar_plain(sc.scalar, ilevel); - else - _write_scalar_squo(sc.scalar, ilevel); - } - else - { - _RYML_CB_ERR(m_tree->callbacks(), "not implemented"); - } -} - -template -void Emitter::_write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags) -{ - if(flags & (KEYTAG|VALTAG)) - if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG) - _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have tags"); - if(C4_UNLIKELY(flags.has_anchor())) - if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR) - _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have anchors"); - if(sc.scalar.len) - { - // use double quoted style... - // if it is a key (mandatory in JSON) - // if the style is marked quoted - bool dquoted = ((flags & (KEY|VALQUO)) - || (scalar_style_json_choose(sc.scalar) & SCALAR_DQUO)); // choose the style - if(dquoted) - _write_scalar_json_dquo(sc.scalar); - else - this->Writer::_do_write(sc.scalar); - } - else - { - if(sc.scalar.str || (flags & (KEY|VALQUO|KEYTAG|VALTAG))) - this->Writer::_do_write("\"\""); - else - this->Writer::_do_write("null"); - } -} - -template -size_t Emitter::_write_escaped_newlines(csubstr s, size_t i) -{ - RYML_ASSERT(s.len > i); - RYML_ASSERT(s.str[i] == '\n'); - //_c4dbgpf("nl@i={} rem=[{}]~~~{}~~~", i, s.sub(i).len, s.sub(i)); - // add an extra newline for each sequence of consecutive - // newline/whitespace - this->Writer::_do_write('\n'); - do - { - this->Writer::_do_write('\n'); // write the newline again - ++i; // increase the outer loop counter! - } while(i < s.len && s.str[i] == '\n'); - _RYML_CB_ASSERT(m_tree->callbacks(), i > 0); - --i; - _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] == '\n'); - return i; -} - -inline bool _is_indented_block(csubstr s, size_t prev, size_t i) noexcept -{ - if(prev == 0 && s.begins_with_any(" \t")) - return true; - const size_t pos = s.first_not_of('\n', i); - return (pos != npos) && (s.str[pos] == ' ' || s.str[pos] == '\t'); -} - -template -size_t Emitter::_write_indented_block(csubstr s, size_t i, id_type ilevel) -{ - //_c4dbgpf("indblock@i={} rem=[{}]~~~\n{}~~~", i, s.sub(i).len, s.sub(i)); - _RYML_CB_ASSERT(m_tree->callbacks(), i > 0); - _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i-1] == '\n'); - _RYML_CB_ASSERT(m_tree->callbacks(), i < s.len); - _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] == ' ' || s.str[i] == '\t' || s.str[i] == '\n'); -again: - size_t pos = s.find("\n ", i); - if(pos == npos) - pos = s.find("\n\t", i); - if(pos != npos) - { - ++pos; - //_c4dbgpf("indblock line@i={} rem=[{}]~~~\n{}~~~", i, s.range(i, pos).len, s.range(i, pos)); - _rymlindent_nextline(); - this->Writer::_do_write(s.range(i, pos)); - i = pos; - goto again; // NOLINT - } - // consume the newlines after the indented block - // to prevent them from being escaped - pos = s.find('\n', i); - if(pos != npos) - { - const size_t pos2 = s.first_not_of('\n', pos); - pos = (pos2 != npos) ? pos2 : pos; - //_c4dbgpf("indblock line@i={} rem=[{}]~~~\n{}~~~", i, s.range(i, pos).len, s.range(i, pos)); - _rymlindent_nextline(); - this->Writer::_do_write(s.range(i, pos)); - i = pos; - } - return i; -} - -template -void Emitter::_write_scalar_literal(csubstr s, id_type ilevel, bool explicit_key) -{ - _RYML_CB_ASSERT(m_tree->callbacks(), s.find("\r") == csubstr::npos); - if(explicit_key) - this->Writer::_do_write("? "); - csubstr trimmed = s.trimr('\n'); - const size_t numnewlines_at_end = s.len - trimmed.len; - const bool is_newline_only = (trimmed.len == 0 && (s.len > 0)); - const bool explicit_indentation = s.triml("\n\r").begins_with_any(" \t"); - // - this->Writer::_do_write('|'); - if(explicit_indentation) - this->Writer::_do_write('2'); - // - if(numnewlines_at_end > 1 || is_newline_only) - this->Writer::_do_write('+'); - else if(numnewlines_at_end == 0) - this->Writer::_do_write('-'); - // - if(trimmed.len) - { - this->Writer::_do_write('\n'); - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < trimmed.len; ++i) - { - if(trimmed[i] != '\n') - continue; - // write everything up to this point - csubstr since_pos = trimmed.range(pos, i+1); // include the newline - _rymlindent_nextline() - this->Writer::_do_write(since_pos); - pos = i+1; // already written - } - if(pos < trimmed.len) - { - _rymlindent_nextline() - this->Writer::_do_write(trimmed.sub(pos)); - } - } - for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i) - this->Writer::_do_write('\n'); - if(explicit_key) - { - this->Writer::_do_write('\n'); - this->_indent(ilevel); - } -} - -template -void Emitter::_write_scalar_folded(csubstr s, id_type ilevel, bool explicit_key) -{ - if(explicit_key) - this->Writer::_do_write("? "); - _RYML_CB_ASSERT(m_tree->callbacks(), s.find("\r") == csubstr::npos); - csubstr trimmed = s.trimr('\n'); - const size_t numnewlines_at_end = s.len - trimmed.len; - const bool is_newline_only = (trimmed.len == 0 && (s.len > 0)); - const bool explicit_indentation = s.triml("\n\r").begins_with_any(" \t"); - // - this->Writer::_do_write('>'); - if(explicit_indentation) - this->Writer::_do_write('2'); - // - if(numnewlines_at_end == 0) - this->Writer::_do_write('-'); - else if(numnewlines_at_end > 1 || is_newline_only) - this->Writer::_do_write('+'); - // - if(trimmed.len) - { - this->Writer::_do_write('\n'); - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < trimmed.len; ++i) - { - if(trimmed[i] != '\n') - continue; - // escape newline sequences - if( ! _is_indented_block(s, pos, i)) - { - if(pos < i) - { - _rymlindent_nextline() - this->Writer::_do_write(s.range(pos, i)); - i = _write_escaped_newlines(s, i); - pos = i+1; - } - else - { - if(i+1 < s.len) - { - if(s.str[i+1] == '\n') - { - ++i; - i = _write_escaped_newlines(s, i); - pos = i+1; - } - else - { - this->Writer::_do_write('\n'); - pos = i+1; - } - } - } - } - else // do not escape newlines in indented blocks - { - ++i; - _rymlindent_nextline() - this->Writer::_do_write(s.range(pos, i)); - if(pos > 0 || !s.begins_with_any(" \t")) - i = _write_indented_block(s, i, ilevel); - pos = i; - } - } - if(pos < trimmed.len) - { - _rymlindent_nextline() - this->Writer::_do_write(trimmed.sub(pos)); - } - } - for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i) - this->Writer::_do_write('\n'); - if(explicit_key) - { - this->Writer::_do_write('\n'); - this->_indent(ilevel); - } -} - -template -void Emitter::_write_scalar_squo(csubstr s, id_type ilevel) -{ - size_t pos = 0; // tracks the last character that was already written - this->Writer::_do_write('\''); - for(size_t i = 0; i < s.len; ++i) - { - if(s[i] == '\n') - { - this->Writer::_do_write(s.range(pos, i)); // write everything up to (excluding) this char - //_c4dbgpf("newline at {}. writing ~~~{}~~~", i, s.range(pos, i)); - i = _write_escaped_newlines(s, i); - //_c4dbgpf("newline --> {}", i); - if(i < s.len) - _rymlindent_nextline() - pos = i+1; - } - else if(s[i] == '\'') - { - csubstr sub = s.range(pos, i+1); - //_c4dbgpf("squote at {}. writing ~~~{}~~~", i, sub); - this->Writer::_do_write(sub); // write everything up to (including) this squote - this->Writer::_do_write('\''); // write the squote again - pos = i+1; - } - } - // write missing characters at the end of the string - if(pos < s.len) - this->Writer::_do_write(s.sub(pos)); - this->Writer::_do_write('\''); -} - -template -void Emitter::_write_scalar_dquo(csubstr s, id_type ilevel) -{ - size_t pos = 0; // tracks the last character that was already written - this->Writer::_do_write('"'); - for(size_t i = 0; i < s.len; ++i) - { - const char curr = s.str[i]; - switch(curr) // NOLINT - { - case '"': - case '\\': - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write('\\'); // write the escape - this->Writer::_do_write(curr); // write the char - pos = i+1; - break; - } -#ifndef prefer_writing_newlines_as_double_newlines - case '\n': - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write("\\n"); // write the escape - pos = i+1; - (void)ilevel; - break; - } -#else - case '\n': - { - // write everything up to (excluding) this newline - //_c4dbgpf("nl@i={} rem=[{}]~~~{}~~~", i, s.sub(i).len, s.sub(i)); - this->Writer::_do_write(s.range(pos, i)); - i = _write_escaped_newlines(s, i); - ++i; - pos = i; - // as for the next line... - if(i < s.len) - { - _rymlindent_nextline() // indent the next line - // escape leading whitespace, and flush it - size_t first = s.first_not_of(" \t", i); - _c4dbgpf("@i={} first={} rem=[{}]~~~{}~~~", i, first, s.sub(i).len, s.sub(i)); - if(first > i) - { - if(first == npos) - first = s.len; - this->Writer::_do_write('\\'); - this->Writer::_do_write(s.range(i, first)); - this->Writer::_do_write('\\'); - i = first-1; - pos = first; - } - } - break; - } - // escape trailing whitespace before a newline - case ' ': - case '\t': - { - const size_t next = s.first_not_of(" \t\r", i); - if(next != npos && s.str[next] == '\n') - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write('\\'); // escape the whitespace - pos = i; - } - break; - } -#endif - case '\r': - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write("\\r"); // write the escaped char - pos = i+1; - break; - } - case '\b': - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write("\\b"); // write the escaped char - pos = i+1; - break; - } - } - } - // write missing characters at the end of the string - if(pos < s.len) - this->Writer::_do_write(s.sub(pos)); - this->Writer::_do_write('"'); -} - -template -void Emitter::_write_scalar_plain(csubstr s, id_type ilevel) -{ - if(C4_UNLIKELY(ilevel == 0 && (s.begins_with("...") || s.begins_with("---")))) - { - _rymlindent_nextline() // indent the next line - ++ilevel; - } - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < s.len; ++i) - { - const char curr = s.str[i]; - if(curr == '\n') - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (including) this newline - i = _write_escaped_newlines(s, i); - pos = i+1; - if(pos < s.len) - _rymlindent_nextline() // indent the next line - } - } - // write missing characters at the end of the string - if(pos < s.len) - this->Writer::_do_write(s.sub(pos)); -} - -#undef _rymlindent_nextline - -template -void Emitter::_write_scalar_json_dquo(csubstr s) -{ - size_t pos = 0; - this->Writer::_do_write('"'); - for(size_t i = 0; i < s.len; ++i) - { - switch(s.str[i]) - { - case '"': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\\""); - pos = i + 1; - break; - case '\n': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\n"); - pos = i + 1; - break; - case '\t': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\t"); - pos = i + 1; - break; - case '\\': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\\\"); - pos = i + 1; - break; - case '\r': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\r"); - pos = i + 1; - break; - case '\b': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\b"); - pos = i + 1; - break; - case '\f': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\f"); - pos = i + 1; - break; - } - } - if(pos < s.len) - { - csubstr sub = s.sub(pos); - this->Writer::_do_write(sub); - } - this->Writer::_do_write('"'); -} - -} // namespace yml -} // namespace c4 - -#endif /* _C4_YML_EMIT_DEF_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/emit.hpp b/3rdparty/rapidyaml/include/c4/yml/emit.hpp deleted file mode 100644 index d77c32a4ed..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/emit.hpp +++ /dev/null @@ -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 Emitter; -template -using EmitterOStream = Emitter>; -using EmitterFile = Emitter; -using EmitterBuf = Emitter; - -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 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 - Emitter(Args &&...args) : Writer(std::forward(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 - Emitter(EmitOptions const& opts, Args &&...args) : Writer(std::forward(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 -inline OStream& operator<< (OStream& s, Tree const& t) -{ - EmitterOStream em(s); - em.emit_as(EMIT_YAML, t); - return s; -} - -/** emit YAML to an STL-like ostream - * @overload */ -template -inline OStream& operator<< (OStream& s, ConstNodeRef const& n) -{ - if(!detail::is_set_(n)) - return s; - EmitterOStream 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 -inline OStream& operator<< (OStream& s, as_json const& j) -{ - if(!j.tree || j.node == NONE) - return s; - EmitterOStream em(j.options, s); - em.emit_as(EMIT_JSON, *j.tree, j.node, true); - return s; -} - -/** emit yaml to an STL-like stream */ -template -inline OStream& operator<< (OStream& s, as_yaml const& y) -{ - if(!y.tree || y.node == NONE) - return s; - EmitterOStream 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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, id_type id, CharOwningContainer * cont) -{ - return emitrs_yaml(t, id, cont); -} -template -RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, id_type id) -{ - return emitrs_yaml(t, id); -} -template -RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont) -{ - return emitrs_yaml(t, cont); -} -template -RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t) -{ - return emitrs_yaml(t); -} -template -RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont) -{ - return emitrs_yaml(n, cont); -} -template -RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n) -{ - return emitrs_yaml(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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/event_handler_stack.hpp b/3rdparty/rapidyaml/include/c4/yml/event_handler_stack.hpp deleted file mode 100644 index 65960d3009..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/event_handler_stack.hpp +++ /dev/null @@ -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 -struct EventHandlerStack -{ - static_assert(std::is_base_of::value, - "ParserState must be a base of HandlerState"); - - using state = HandlerState; - using pfn_relocate_arena = detail::pfn_relocate_arena; - -public: - - detail::stack 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(this)->template _has_any__()) - - 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/event_handler_tree.hpp b/3rdparty/rapidyaml/include/c4/yml/event_handler_tree.hpp deleted file mode 100644 index 6b35adabb1..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/event_handler_tree.hpp +++ /dev/null @@ -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 -{ - - /** @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__(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits) - #define _disable_(bits) _disable__(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits) - #else - #define _enable_(bits) _enable__() - #define _disable_(bits) _disable__() - #endif - #define _has_any_(bits) _has_any__() - /** @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 C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept - { - m_curr->tr_data->m_type.type = static_cast(m_curr->tr_data->m_type.type | bits); - } - template C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept - { - m_curr->tr_data->m_type.type = static_cast(m_curr->tr_data->m_type.type & (~bits)); - } - template 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/export.hpp b/3rdparty/rapidyaml/include/c4/yml/export.hpp deleted file mode 100644 index 6b77f3f8dd..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/export.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/filter_processor.hpp b/3rdparty/rapidyaml/include/c4/yml/filter_processor.hpp deleted file mode 100644 index 2dc3810d35..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/filter_processor.hpp +++ /dev/null @@ -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={}{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos 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={}{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, 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={}{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/fwd.hpp b/3rdparty/rapidyaml/include/c4/yml/fwd.hpp deleted file mode 100644 index 7fa1f17699..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/fwd.hpp +++ /dev/null @@ -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 ParseEngine; -struct EventHandlerTree; -using Parser = ParseEngine; - -} // namespace c4 -} // namespace yml - -#endif /* _C4_YML_FWD_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/node.hpp b/3rdparty/rapidyaml/include/c4/yml/node.hpp deleted file mode 100644 index 4d74dd3d4f..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/node.hpp +++ /dev/null @@ -1,1679 +0,0 @@ -#ifndef _C4_YML_NODE_HPP_ -#define _C4_YML_NODE_HPP_ - -/** @file node.hpp Node classes */ - -#include - -#include "c4/yml/tree.hpp" -#include "c4/base64.hpp" - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtype-limits" -# pragma clang diagnostic ignored "-Wold-style-cast" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" -# pragma GCC diagnostic ignored "-Wold-style-cast" -# pragma GCC diagnostic ignored "-Wuseless-cast" -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/) -# pragma warning(disable: 4296/*expression is always 'boolean_value'*/) -#endif - -namespace c4 { -namespace yml { - -/** @addtogroup doc_node_classes - * - * @{ - */ - - -/** @defgroup doc_serialization_helpers Serialization helpers - * - * @{ - */ -template struct Key { K & k; }; // NOLINT -template<> struct Key { fmt::const_base64_wrapper wrapper; }; -template<> struct Key { fmt::base64_wrapper wrapper; }; - -template C4_ALWAYS_INLINE Key key(K & k) { return Key{k}; } -C4_ALWAYS_INLINE Key key(fmt::const_base64_wrapper w) { return {w}; } -C4_ALWAYS_INLINE Key key(fmt::base64_wrapper w) { return {w}; } - - -template void write(NodeRef *n, T const& v); - -template inline bool read(ConstNodeRef const& C4_RESTRICT n, T *v); -template inline bool read(NodeRef const& C4_RESTRICT n, T *v); -template inline bool readkey(ConstNodeRef const& C4_RESTRICT n, T *v); -template inline bool readkey(NodeRef const& C4_RESTRICT n, T *v); - -/** @} */ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -// forward decls -class NodeRef; -class ConstNodeRef; - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @cond dev */ -namespace detail { - -template -struct child_iterator -{ - using value_type = NodeRefType; - using tree_type = typename NodeRefType::tree_type; - - tree_type * C4_RESTRICT m_tree; - id_type m_child_id; - - child_iterator(tree_type * t, id_type id) : m_tree(t), m_child_id(id) {} - - child_iterator& operator++ () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; } - child_iterator& operator-- () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->prev_sibling(m_child_id); return *this; } - - NodeRefType operator* () const { return NodeRefType(m_tree, m_child_id); } - NodeRefType operator-> () const { return NodeRefType(m_tree, m_child_id); } - - bool operator!= (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id != that.m_child_id; } - bool operator== (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id == that.m_child_id; } -}; - -template -struct children_view_ -{ - using n_iterator = child_iterator; - - n_iterator b, e; - - children_view_(n_iterator const& C4_RESTRICT b_, - n_iterator const& C4_RESTRICT e_) : b(b_), e(e_) {} - - n_iterator begin() const { return b; } - n_iterator end () const { return e; } -}; - -template -bool _visit(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false) -{ - id_type increment = 0; - if( ! (node.is_root() && skip_root)) - { - if(fn(node, indentation_level)) - return true; - ++increment; - } - if(node.has_children()) - { - for(auto ch : node.children()) - { - if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root - { - return true; - } - } - } - return false; -} - -template -bool _visit_stacked(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false) -{ - id_type increment = 0; - if( ! (node.is_root() && skip_root)) - { - if(fn(node, indentation_level)) - { - return true; - } - ++increment; - } - if(node.has_children()) - { - fn.push(node, indentation_level); - for(auto ch : node.children()) - { - if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root - { - fn.pop(node, indentation_level); - return true; - } - } - fn.pop(node, indentation_level); - } - return false; -} - -template -struct RoNodeMethods; -} // detail -/** @endcond */ - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/** a CRTP base providing read-only methods for @ref ConstNodeRef and @ref NodeRef */ -namespace detail { -template -struct RoNodeMethods -{ - C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align") - /** @cond dev */ - // helper CRTP macros, undefined at the end - #define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree - #define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id - #define tree__ ((Impl const* C4_RESTRICT)this)->m_tree - #define id__ ((Impl const* C4_RESTRICT)this)->m_id - // require readable: this is a precondition for reading from the - // tree using this object. - #define _C4RR() \ - RYML_ASSERT(tree_ != nullptr); \ - _RYML_CB_ASSERT(tree_->m_callbacks, id_ != NONE); \ - _RYML_CB_ASSERT(tree_->m_callbacks, (((Impl const* C4_RESTRICT)this)->readable())) - // a SFINAE beautifier to enable a function only if the - // implementation is mutable - #define _C4_IF_MUTABLE(ty) typename std::enable_if::value, ty>::type - /** @endcond */ - -public: - - /** @name node property getters */ - /** @{ */ - - /** returns the data or null when the id is NONE */ - C4_ALWAYS_INLINE NodeData const* get() const RYML_NOEXCEPT { return ((Impl const*)this)->readable() ? tree_->get(id_) : nullptr; } - /** returns the data or null when the id is NONE */ - template - C4_ALWAYS_INLINE auto get() RYML_NOEXCEPT -> _C4_IF_MUTABLE(NodeData*) { return ((Impl const*)this)->readable() ? tree__->get(id__) : nullptr; } - - C4_ALWAYS_INLINE NodeType type() const RYML_NOEXCEPT { _C4RR(); return tree_->type(id_); } /**< Forward to @ref Tree::type_str(). Node must be readable. */ - C4_ALWAYS_INLINE const char* type_str() const RYML_NOEXCEPT { _C4RR(); return tree_->type_str(id_); } /**< Forward to @ref Tree::type_str(). Node must be readable. */ - - C4_ALWAYS_INLINE csubstr key() const RYML_NOEXCEPT { _C4RR(); return tree_->key(id_); } /**< Forward to @ref Tree::key(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->key_tag(id_); } /**< Forward to @ref Tree::key_tag(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->key_ref(id_); } /**< Forward to @ref Tree::key_ref(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->key_anchor(id_); } /**< Forward to @ref Tree::key_anchor(). Node must be readable. */ - - C4_ALWAYS_INLINE csubstr val() const RYML_NOEXCEPT { _C4RR(); return tree_->val(id_); } /**< Forward to @ref Tree::val(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->val_tag(id_); } /**< Forward to @ref Tree::val_tag(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->val_ref(id_); } /**< Forward to @ref Tree::val_ref(). Node must be readable. */ - C4_ALWAYS_INLINE csubstr val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->val_anchor(id_); } /**< Forward to @ref Tree::val_anchor(). Node must be readable. */ - - C4_ALWAYS_INLINE NodeScalar const& keysc() const RYML_NOEXCEPT { _C4RR(); return tree_->keysc(id_); } /**< Forward to @ref Tree::keysc(). Node must be readable. */ - C4_ALWAYS_INLINE NodeScalar const& valsc() const RYML_NOEXCEPT { _C4RR(); return tree_->valsc(id_); } /**< Forward to @ref Tree::valsc(). Node must be readable. */ - - C4_ALWAYS_INLINE bool key_is_null() const RYML_NOEXCEPT { _C4RR(); return tree_->key_is_null(id_); } /**< Forward to @ref Tree::key_is_null(). Node must be readable. */ - C4_ALWAYS_INLINE bool val_is_null() const RYML_NOEXCEPT { _C4RR(); return tree_->val_is_null(id_); } /**< Forward to @ref Tree::val_is_null(). Node must be readable. */ - - C4_ALWAYS_INLINE bool is_key_unfiltered() const noexcept { _C4RR(); return tree_->is_key_unfiltered(id_); } /**< Forward to @ref Tree::is_key_unfiltered(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_unfiltered() const noexcept { _C4RR(); return tree_->is_val_unfiltered(id_); } /**< Forward to @ref Tree::is_val_unfiltered(). Node must be readable. */ - - /** @} */ - -public: - - /** @name node type predicates */ - /** @{ */ - - C4_ALWAYS_INLINE bool empty() const RYML_NOEXCEPT { _C4RR(); return tree_->empty(id_); } /**< Forward to @ref Tree::empty(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_stream() const RYML_NOEXCEPT { _C4RR(); return tree_->is_stream(id_); } /**< Forward to @ref Tree::is_stream(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_doc() const RYML_NOEXCEPT { _C4RR(); return tree_->is_doc(id_); } /**< Forward to @ref Tree::is_doc(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_container() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container(id_); } /**< Forward to @ref Tree::is_container(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->is_map(id_); } /**< Forward to @ref Tree::is_map(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->is_seq(id_); } /**< Forward to @ref Tree::is_seq(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_val() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val(id_); } /**< Forward to @ref Tree::has_val(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_key() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key(id_); } /**< Forward to @ref Tree::has_key(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val(id_); } /**< Forward to @ref Tree::is_val(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_keyval() const RYML_NOEXCEPT { _C4RR(); return tree_->is_keyval(id_); } /**< Forward to @ref Tree::is_keyval(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_tag(id_); } /**< Forward to @ref Tree::has_key_tag(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_tag(id_); } /**< Forward to @ref Tree::has_val_tag(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_anchor(id_); } /**< Forward to @ref Tree::has_key_anchor(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_anchor(id_); } /**< Forward to @ref Tree::has_val_anchor(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_anchor(id_); } /**< Forward to @ref Tree::has_anchor(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_ref(id_); } /**< Forward to @ref Tree::is_key_ref(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_ref(id_); } /**< Forward to @ref Tree::is_val_ref(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_ref(id_); } /**< Forward to @ref Tree::is_ref(). Node must be readable. */ - C4_ALWAYS_INLINE bool parent_is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_seq(id_); } /**< Forward to @ref Tree::parent_is_seq(). Node must be readable. */ - C4_ALWAYS_INLINE bool parent_is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_map(id_); } /**< Forward to @ref Tree::parent_is_map(). Node must be readable. */ - - RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor() const noexcept { _C4RR(); return tree_->has_key_anchor(id_); } - RYML_DEPRECATED("use has_val_anchor()") bool is_val_hanchor() const noexcept { _C4RR(); return tree_->has_val_anchor(id_); } - RYML_DEPRECATED("use has_anchor()") bool is_anchor() const noexcept { _C4RR(); return tree_->has_anchor(id_); } - RYML_DEPRECATED("use has_anchor() || is_ref()") bool is_anchor_or_ref() const noexcept { _C4RR(); return tree_->is_anchor_or_ref(id_); } - - /** @} */ - -public: - - /** @name style predicates */ - /** @{ */ - - // documentation to the right --> - - C4_ALWAYS_INLINE bool type_has_any(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_any(id_, bits); } /**< Forward to @ref Tree::type_has_any(). Node must be readable. */ - C4_ALWAYS_INLINE bool type_has_all(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_all(id_, bits); } /**< Forward to @ref Tree::type_has_all(). Node must be readable. */ - C4_ALWAYS_INLINE bool type_has_none(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_none(id_, bits); } /**< Forward to @ref Tree::type_has_none(). Node must be readable. */ - - C4_ALWAYS_INLINE NodeType key_style() const RYML_NOEXCEPT { _C4RR(); return tree_->key_style(id_); } /**< Forward to @ref Tree::key_style(). Node must be readable. */ - C4_ALWAYS_INLINE NodeType val_style() const RYML_NOEXCEPT { _C4RR(); return tree_->val_style(id_); } /**< Forward to @ref Tree::val_style(). Node must be readable. */ - - C4_ALWAYS_INLINE bool is_container_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container_styled(id_); } /**< Forward to @ref Tree::is_container_styled(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_block() const RYML_NOEXCEPT { _C4RR(); return tree_->is_block(id_); } /**< Forward to @ref Tree::is_block(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_flow_sl() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow_sl(id_); } /**< Forward to @ref Tree::is_flow_sl(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_flow_ml() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow_ml(id_); } /**< Forward to @ref Tree::is_flow_ml(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_flow() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow(id_); } /**< Forward to @ref Tree::is_flow(). Node must be readable. */ - - C4_ALWAYS_INLINE bool is_key_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_styled(id_); } /**< Forward to @ref Tree::is_key_styled(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_styled(id_); } /**< Forward to @ref Tree::is_val_styled(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_literal() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_literal(id_); } /**< Forward to @ref Tree::is_key_literal(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_literal() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_literal(id_); } /**< Forward to @ref Tree::is_val_literal(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_folded() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_folded(id_); } /**< Forward to @ref Tree::is_key_folded(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_folded() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_folded(id_); } /**< Forward to @ref Tree::is_val_folded(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_squo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_squo(id_); } /**< Forward to @ref Tree::is_key_squo(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_squo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_squo(id_); } /**< Forward to @ref Tree::is_val_squo(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_dquo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_dquo(id_); } /**< Forward to @ref Tree::is_key_dquo(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_dquo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_dquo(id_); } /**< Forward to @ref Tree::is_val_dquo(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_plain() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_plain(id_); } /**< Forward to @ref Tree::is_key_plain(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_plain() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_plain(id_); } /**< Forward to @ref Tree::is_val_plain(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_key_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_quoted(id_); } /**< Forward to @ref Tree::is_key_quoted(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_val_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_quoted(id_); } /**< Forward to @ref Tree::is_val_quoted(). Node must be readable. */ - C4_ALWAYS_INLINE bool is_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_quoted(id_); } /**< Forward to @ref Tree::is_quoted(). Node must be readable. */ - - /** @} */ - -public: - - /** @name hierarchy predicates */ - /** @{ */ - - // documentation to the right --> - - C4_ALWAYS_INLINE bool is_root() const RYML_NOEXCEPT { _C4RR(); return tree_->is_root(id_); } /**< Forward to @ref Tree::is_root(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_parent() const RYML_NOEXCEPT { _C4RR(); return tree_->has_parent(id_); } /**< Forward to @ref Tree::has_parent() Node must be readable. */ - C4_ALWAYS_INLINE bool is_ancestor(ConstImpl const& ancestor) const RYML_NOEXCEPT { _C4RR(); return tree_->is_ancestor(id_, ancestor.m_id); } /**< Forward to @ref Tree::is_ancestor() Node must be readable. */ - - C4_ALWAYS_INLINE bool has_child(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_child(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_child(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_child(id_type node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, node); } /**< Forward to @ref Tree::has_child(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, name); } /**< Forward to @ref Tree::has_child(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_children() const RYML_NOEXCEPT { _C4RR(); return tree_->has_children(id_); } /**< Forward to @ref Tree::has_child(). Node must be readable. */ - - C4_ALWAYS_INLINE bool has_sibling(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_sibling(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_sibling(id_type node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, node); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, name); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE bool has_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->has_other_siblings(id_); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */ - - RYML_DEPRECATED("use has_other_siblings()") bool has_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->has_siblings(id_); } - - /** @} */ - -public: - - /** @name hierarchy getters */ - /** @{ */ - - // documentation to the right --> - - template - C4_ALWAYS_INLINE auto doc(id_type i) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { RYML_ASSERT(tree_); return {tree__, tree__->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl doc(id_type i) const RYML_NOEXCEPT { RYML_ASSERT(tree_); return {tree_, tree_->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. succeeds even when the node may have invalid or seed id */ - - template - C4_ALWAYS_INLINE auto parent() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->parent(id__)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl parent() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->parent(id_)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto first_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_child(id__)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl first_child() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_child(id_)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto last_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_child(id__)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl last_child () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_child (id_)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto child(id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->child(id__, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl child(id_type pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->child(id_, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto find_child(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_child(id__, name)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl find_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_child(id_, name)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto prev_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->prev_sibling(id__)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl prev_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->prev_sibling(id_)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto next_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->next_sibling(id__)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl next_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->next_sibling(id_)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto first_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_sibling(id__)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl first_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_sibling(id_)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto last_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_sibling(id__)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl last_sibling () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_sibling(id_)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto sibling(id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->sibling(id__, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl sibling(id_type pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->sibling(id_, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */ - - template - C4_ALWAYS_INLINE auto find_sibling(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_sibling(id__, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */ - C4_ALWAYS_INLINE ConstImpl find_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_sibling(id_, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */ - - C4_ALWAYS_INLINE id_type num_children() const RYML_NOEXCEPT { _C4RR(); return tree_->num_children(id_); } /**< O(num_children). Forward to @ref Tree::num_children(). */ - C4_ALWAYS_INLINE id_type num_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_siblings(id_); } /**< O(num_children). Forward to @ref Tree::num_siblings(). */ - C4_ALWAYS_INLINE id_type num_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_other_siblings(id_); } /**< O(num_siblings). Forward to @ref Tree::num_other_siblings(). */ - C4_ALWAYS_INLINE id_type child_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->m_callbacks, n.readable()); return tree_->child_pos(id_, n.m_id); } /**< O(num_children). Forward to @ref Tree::child_pos(). */ - C4_ALWAYS_INLINE id_type sibling_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->callbacks(), n.readable()); return tree_->child_pos(tree_->parent(id_), n.m_id); } /**< O(num_siblings). Forward to @ref Tree::sibling_pos(). */ - - C4_ALWAYS_INLINE id_type depth_asc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_asc(id_); } /** O(log(num_nodes)). Forward to Tree::depth_asc(). Node must be readable. */ - C4_ALWAYS_INLINE id_type depth_desc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_desc(id_); } /** O(num_nodes). Forward to Tree::depth_desc(). Node must be readable. */ - - /** @} */ - -public: - - /** @name square_brackets - * operator[] */ - /** @{ */ - - /** Find child by key; complexity is O(num_children). - * - * Returns the requested node, or an object in seed state if no - * such child is found (see @ref NodeRef for an explanation of - * what is seed state). When the object is in seed state, using it - * to read from the tree is UB. The seed node can be used to write - * to the tree provided that its create() method is called prior - * to writing, which happens in most modifying methods in - * NodeRef. It is the caller's responsibility to verify that the - * returned node is readable before subsequently using it to read - * from the tree. - * - * @warning the calling object must be readable. This precondition - * is asserted. The assertion is performed only if @ref - * RYML_USE_ASSERT is set to true. As with the non-const overload, - * it is UB to call this method if the node is not readable. - * - * @see https://github.com/biojppm/rapidyaml/issues/389 */ - template - C4_ALWAYS_INLINE auto operator[] (csubstr key) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) - { - _C4RR(); - id_type ch = tree__->find_child(id__, key); - return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, key); - } - - /** Find child by position; complexity is O(pos). - * - * Returns the requested node, or an object in seed state if no - * such child is found (see @ref NodeRef for an explanation of - * what is seed state). When the object is in seed state, using it - * to read from the tree is UB. The seed node can be used to write - * to the tree provided that its create() method is called prior - * to writing, which happens in most modifying methods in - * NodeRef. It is the caller's responsibility to verify that the - * returned node is readable before subsequently using it to read - * from the tree. - * - * @warning the calling object must be readable. This precondition - * is asserted. The assertion is performed only if @ref - * RYML_USE_ASSERT is set to true. As with the non-const overload, - * it is UB to call this method if the node is not readable. - * - * @see https://github.com/biojppm/rapidyaml/issues/389 */ - template - C4_ALWAYS_INLINE auto operator[] (id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) - { - _C4RR(); - id_type ch = tree__->child(id__, pos); - return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, pos); - } - - /** Find a child by key; complexity is O(num_children). - * - * Behaves similar to the non-const overload, but further asserts - * that the returned node is readable (because it can never be in - * a seed state). The assertion is performed only if @ref - * RYML_USE_ASSERT is set to true. As with the non-const overload, - * it is UB to use the return value if it is not valid. - * - * @see https://github.com/biojppm/rapidyaml/issues/389 */ - C4_ALWAYS_INLINE ConstImpl operator[] (csubstr key) const RYML_NOEXCEPT - { - _C4RR(); - id_type ch = tree_->find_child(id_, key); - _RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE); - return {tree_, ch}; - } - - /** Find a child by position; complexity is O(pos). - * - * Behaves similar to the non-const overload, but further asserts - * that the returned node is readable (because it can never be in - * a seed state). This assertion is performed only if @ref - * RYML_USE_ASSERT is set to true. As with the non-const overload, - * it is UB to use the return value if it is not valid. - * - * @see https://github.com/biojppm/rapidyaml/issues/389 */ - C4_ALWAYS_INLINE ConstImpl operator[] (id_type pos) const RYML_NOEXCEPT - { - _C4RR(); - id_type ch = tree_->child(id_, pos); - _RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE); - return {tree_, ch}; - } - - /** @} */ - -public: - - /** @name at - * - * These functions are the analogue to operator[], with the - * difference that they emit an error instead of an - * assertion. That is, if any of the pre or post conditions is - * violated, an error is always emitted (resulting in a call to - * the error callback). - * - * @{ */ - - /** Find child by key; complexity is O(num_children). - * - * Returns the requested node, or an object in seed state if no - * such child is found (see @ref NodeRef for an explanation of - * what is seed state). When the object is in seed state, using it - * to read from the tree is UB. The seed node can be subsequently - * used to write to the tree provided that its create() method is - * called prior to writing, which happens inside most mutating - * methods in NodeRef. It is the caller's responsibility to verify - * that the returned node is readable before subsequently using it - * to read from the tree. - * - * @warning This method will call the error callback (regardless - * of build type or of the value of RYML_USE_ASSERT) whenever any - * of the following preconditions is violated: a) the object is - * valid (points at a tree and a node), b) the calling object must - * be readable (must not be in seed state), c) the calling object - * must be pointing at a MAP node. The preconditions are similar - * to the non-const operator[](csubstr), but instead of using - * assertions, this function directly checks those conditions and - * calls the error callback if any of the checks fail. - * - * @note since it is valid behavior for the returned node to be in - * seed state, the error callback is not invoked when this - * happens. */ - template - C4_ALWAYS_INLINE auto at(csubstr key) -> _C4_IF_MUTABLE(Impl) - { - RYML_CHECK(tree_ != nullptr); - _RYML_CB_CHECK(tree_->m_callbacks, (id_ >= 0 && id_ < tree_->capacity())); - _RYML_CB_CHECK(tree_->m_callbacks, ((Impl const*)this)->readable()); - _RYML_CB_CHECK(tree_->m_callbacks, tree_->is_map(id_)); - id_type ch = tree__->find_child(id__, key); - return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, key); - } - - /** Find child by position; complexity is O(pos). - * - * Returns the requested node, or an object in seed state if no - * such child is found (see @ref NodeRef for an explanation of - * what is seed state). When the object is in seed state, using it - * to read from the tree is UB. The seed node can be used to write - * to the tree provided that its create() method is called prior - * to writing, which happens in most modifying methods in - * NodeRef. It is the caller's responsibility to verify that the - * returned node is readable before subsequently using it to read - * from the tree. - * - * @warning This method will call the error callback (regardless - * of build type or of the value of RYML_USE_ASSERT) whenever any - * of the following preconditions is violated: a) the object is - * valid (points at a tree and a node), b) the calling object must - * be readable (must not be in seed state), c) the calling object - * must be pointing at a MAP node. The preconditions are similar - * to the non-const operator[](id_type), but instead of using - * assertions, this function directly checks those conditions and - * calls the error callback if any of the checks fail. - * - * @note since it is valid behavior for the returned node to be in - * seed state, the error callback is not invoked when this - * happens. */ - template - C4_ALWAYS_INLINE auto at(id_type pos) -> _C4_IF_MUTABLE(Impl) - { - RYML_CHECK(tree_ != nullptr); - const id_type cap = tree_->capacity(); - _RYML_CB_CHECK(tree_->m_callbacks, (id_ >= 0 && id_ < cap)); - _RYML_CB_CHECK(tree_->m_callbacks, (pos >= 0 && pos < cap)); - _RYML_CB_CHECK(tree_->m_callbacks, ((Impl const*)this)->readable()); - _RYML_CB_CHECK(tree_->m_callbacks, tree_->is_container(id_)); - id_type ch = tree__->child(id__, pos); - return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, pos); - } - - /** Get a child by name, with error checking; complexity is - * O(num_children). - * - * Behaves as operator[](csubstr) const, but always raises an - * error (even when RYML_USE_ASSERT is set to false) when the - * returned node does not exist, or when this node is not - * readable, or when it is not a map. This behaviour is similar to - * std::vector::at(), but the error consists in calling the error - * callback instead of directly raising an exception. */ - ConstImpl at(csubstr key) const - { - RYML_CHECK(tree_ != nullptr); - _RYML_CB_CHECK(tree_->m_callbacks, (id_ >= 0 && id_ < tree_->capacity())); - _RYML_CB_CHECK(tree_->m_callbacks, ((Impl const*)this)->readable()); - _RYML_CB_CHECK(tree_->m_callbacks, tree_->is_map(id_)); - id_type ch = tree_->find_child(id_, key); - _RYML_CB_CHECK(tree_->m_callbacks, ch != NONE); - return {tree_, ch}; - } - - /** Get a child by position, with error checking; complexity is - * O(pos). - * - * Behaves as operator[](id_type) const, but always raises an error - * (even when RYML_USE_ASSERT is set to false) when the returned - * node does not exist, or when this node is not readable, or when - * it is not a container. This behaviour is similar to - * std::vector::at(), but the error consists in calling the error - * callback instead of directly raising an exception. */ - ConstImpl at(id_type pos) const - { - RYML_CHECK(tree_ != nullptr); - const id_type cap = tree_->capacity(); - _RYML_CB_CHECK(tree_->m_callbacks, (id_ >= 0 && id_ < cap)); - _RYML_CB_CHECK(tree_->m_callbacks, (pos >= 0 && pos < cap)); - _RYML_CB_CHECK(tree_->m_callbacks, ((Impl const*)this)->readable()); - _RYML_CB_CHECK(tree_->m_callbacks, tree_->is_container(id_)); - const id_type ch = tree_->child(id_, pos); - _RYML_CB_CHECK(tree_->m_callbacks, ch != NONE); - return {tree_, ch}; - } - - /** @} */ - -public: - - /** @name locations */ - /** @{ */ - - Location location(Parser const& parser) const - { - _C4RR(); - return tree_->location(parser, id_); - } - - /** @} */ - -public: - - /** @name deserialization */ - /** @{ */ - - /** deserialize the node's val to the given variable, forwarding - * to the user-overrideable @ref read() function. */ - template - ConstImpl const& operator>> (T &v) const - { - _C4RR(); - if( ! read((ConstImpl const&)*this, &v)) - _RYML_CB_ERR(tree_->m_callbacks, "could not deserialize value"); - return *((ConstImpl const*)this); - } - - /** deserialize the node's key to the given variable, forwarding - * to the user-overrideable @ref read() function; use @ref key() - * to disambiguate; for example: `node >> ryml::key(var)` */ - template - ConstImpl const& operator>> (Key v) const - { - _C4RR(); - if( ! readkey((ConstImpl const&)*this, &v.k)) - _RYML_CB_ERR(tree_->m_callbacks, "could not deserialize key"); - return *((ConstImpl const*)this); - } - - /** look for a child by name, if it exists assign to var. return - * true if the child existed. */ - template - bool get_if(csubstr name, T *var) const - { - _C4RR(); - ConstImpl ch = find_child(name); - if(!ch.readable()) - return false; - ch >> *var; - return true; - } - - /** look for a child by name, if it exists assign to var, - * otherwise default to fallback. return true if the child - * existed. */ - template - bool get_if(csubstr name, T *var, T const& fallback) const - { - _C4RR(); - ConstImpl ch = find_child(name); - if(ch.readable()) - { - ch >> *var; - return true; - } - else - { - *var = fallback; - return false; - } - } - - /** @name deserialization_base64 */ - /** @{ */ - - /** deserialize the node's key as base64. lightweight wrapper over @ref deserialize_key() */ - ConstImpl const& operator>> (Key w) const - { - deserialize_key(w.wrapper); - return *((ConstImpl const*)this); - } - - /** deserialize the node's val as base64. lightweight wrapper over @ref deserialize_val() */ - ConstImpl const& operator>> (fmt::base64_wrapper w) const - { - deserialize_val(w); - return *((ConstImpl const*)this); - } - - /** decode the base64-encoded key and assign the - * decoded blob to the given buffer/ - * @return the size of base64-decoded blob */ - size_t deserialize_key(fmt::base64_wrapper v) const - { - _C4RR(); - return from_chars(key(), &v); - } - /** decode the base64-encoded key and assign the - * decoded blob to the given buffer/ - * @return the size of base64-decoded blob */ - size_t deserialize_val(fmt::base64_wrapper v) const - { - _C4RR(); - return from_chars(val(), &v); - }; - - /** @} */ - - /** @} */ - -public: - - #if defined(__clang__) - # pragma clang diagnostic push - # pragma clang diagnostic ignored "-Wnull-dereference" - #elif defined(__GNUC__) - # pragma GCC diagnostic push - # if __GNUC__ >= 6 - # pragma GCC diagnostic ignored "-Wnull-dereference" - # endif - #endif - - /** @name iteration */ - /** @{ */ - - using iterator = detail::child_iterator; - using const_iterator = detail::child_iterator; - using children_view = detail::children_view_; - using const_children_view = detail::children_view_; - - /** get an iterator to the first child */ - template - C4_ALWAYS_INLINE auto begin() RYML_NOEXCEPT -> _C4_IF_MUTABLE(iterator) { _C4RR(); return iterator(tree__, tree__->first_child(id__)); } - /** get an iterator to the first child */ - C4_ALWAYS_INLINE const_iterator begin() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, tree_->first_child(id_)); } - /** get an iterator to the first child */ - C4_ALWAYS_INLINE const_iterator cbegin() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, tree_->first_child(id_)); } - - /** get an iterator to after the last child */ - template - C4_ALWAYS_INLINE auto end() RYML_NOEXCEPT -> _C4_IF_MUTABLE(iterator) { _C4RR(); return iterator(tree__, NONE); } - /** get an iterator to after the last child */ - C4_ALWAYS_INLINE const_iterator end() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, NONE); } - /** get an iterator to after the last child */ - C4_ALWAYS_INLINE const_iterator cend() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, tree_->first_child(id_)); } - - /** get an iterable view over children */ - template - C4_ALWAYS_INLINE auto children() RYML_NOEXCEPT -> _C4_IF_MUTABLE(children_view) { _C4RR(); return children_view(begin(), end()); } - /** get an iterable view over children */ - C4_ALWAYS_INLINE const_children_view children() const RYML_NOEXCEPT { _C4RR(); return const_children_view(begin(), end()); } - /** get an iterable view over children */ - C4_ALWAYS_INLINE const_children_view cchildren() const RYML_NOEXCEPT { _C4RR(); return const_children_view(begin(), end()); } - - /** get an iterable view over all siblings (including the calling node) */ - template - C4_ALWAYS_INLINE auto siblings() RYML_NOEXCEPT -> _C4_IF_MUTABLE(children_view) - { - _C4RR(); - NodeData const *nd = tree__->get(id__); - return (nd->m_parent != NONE) ? // does it have a parent? - children_view(iterator(tree__, tree_->get(nd->m_parent)->m_first_child), iterator(tree__, NONE)) - : - children_view(end(), end()); - } - /** get an iterable view over all siblings (including the calling node) */ - C4_ALWAYS_INLINE const_children_view siblings() const RYML_NOEXCEPT - { - _C4RR(); - NodeData const *nd = tree_->get(id_); - return (nd->m_parent != NONE) ? // does it have a parent? - const_children_view(const_iterator(tree_, tree_->get(nd->m_parent)->m_first_child), const_iterator(tree_, NONE)) - : - const_children_view(end(), end()); - } - /** get an iterable view over all siblings (including the calling node) */ - C4_ALWAYS_INLINE const_children_view csiblings() const RYML_NOEXCEPT { return siblings(); } - - /** visit every child node calling fn(node) */ - template - bool visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT - { - _C4RR(); - return detail::_visit(*(ConstImpl const*)this, fn, indentation_level, skip_root); - } - /** visit every child node calling fn(node) */ - template - auto visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT - -> _C4_IF_MUTABLE(bool) - { - _C4RR(); - return detail::_visit(*(Impl*)this, fn, indentation_level, skip_root); - } - - /** visit every child node calling fn(node, level) */ - template - bool visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT - { - _C4RR(); - return detail::_visit_stacked(*(ConstImpl const*)this, fn, indentation_level, skip_root); - } - /** visit every child node calling fn(node, level) */ - template - auto visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT - -> _C4_IF_MUTABLE(bool) - { - _C4RR(); - return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root); - } - - /** @} */ - - #if defined(__clang__) - # pragma clang diagnostic pop - #elif defined(__GNUC__) - # pragma GCC diagnostic pop - #endif - - #undef _C4_IF_MUTABLE - #undef _C4RR - #undef tree_ - #undef tree__ - #undef id_ - #undef id__ - - C4_SUPPRESS_WARNING_GCC_CLANG_POP -}; -} // detail - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/** Holds a pointer to an existing tree, and a node id. It can be used - * only to read from the tree. - * - * @warning The lifetime of the tree must be larger than that of this - * object. It is up to the user to ensure that this happens. */ -class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods // NOLINT -{ -public: - - using tree_type = Tree const; - -public: - - Tree const* C4_RESTRICT m_tree; - id_type m_id; - - friend NodeRef; - friend struct detail::RoNodeMethods; - -public: - - /** @name construction */ - /** @{ */ - - ConstNodeRef() noexcept : m_tree(nullptr), m_id(NONE) {} - ConstNodeRef(Tree const &t) noexcept : m_tree(&t), m_id(t .root_id()) {} - ConstNodeRef(Tree const *t) noexcept : m_tree(t ), m_id(t->root_id()) {} - ConstNodeRef(Tree const *t, id_type id) noexcept : m_tree(t), m_id(id) {} - ConstNodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE) {} - - ConstNodeRef(ConstNodeRef const&) noexcept = default; - ConstNodeRef(ConstNodeRef &&) noexcept = default; - - inline ConstNodeRef(NodeRef const&) noexcept; - inline ConstNodeRef(NodeRef &&) noexcept; - - /** @} */ - -public: - - /** @name assignment */ - /** @{ */ - - ConstNodeRef& operator= (std::nullptr_t) noexcept { m_tree = nullptr; m_id = NONE; return *this; } - - ConstNodeRef& operator= (ConstNodeRef const&) noexcept = default; - ConstNodeRef& operator= (ConstNodeRef &&) noexcept = default; - - ConstNodeRef& operator= (NodeRef const&) noexcept; - ConstNodeRef& operator= (NodeRef &&) noexcept; - - /** @} */ - -public: - - /** @name state queries - * - * see @ref NodeRef for an explanation on what these states mean */ - /** @{ */ - - C4_ALWAYS_INLINE bool invalid() const noexcept { return (!m_tree) || (m_id == NONE); } - /** because a ConstNodeRef cannot be used to write to the tree, - * readable() has the same meaning as !invalid() */ - C4_ALWAYS_INLINE bool readable() const noexcept { return m_tree != nullptr && m_id != NONE; } - /** because a ConstNodeRef cannot be used to write to the tree, it can never be a seed. - * This method is provided for API equivalence between ConstNodeRef and NodeRef. */ - constexpr static C4_ALWAYS_INLINE bool is_seed() noexcept { return false; } - - RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; } - - /** @} */ - -public: - - /** @name member getters */ - /** @{ */ - - C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; } - C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; } - - /** @} */ - -public: - - /** @name comparisons */ - /** @{ */ - - C4_ALWAYS_INLINE bool operator== (ConstNodeRef const& that) const RYML_NOEXCEPT { return that.m_tree == m_tree && m_id == that.m_id; } - C4_ALWAYS_INLINE bool operator!= (ConstNodeRef const& that) const RYML_NOEXCEPT { return ! this->operator== (that); } - - /** @cond dev */ - RYML_DEPRECATED("use invalid()") bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; } - RYML_DEPRECATED("use !invalid()") bool operator!= (std::nullptr_t) const noexcept { return !(m_tree == nullptr || m_id == NONE); } - - RYML_DEPRECATED("use (this->val() == s)") bool operator== (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT(m_tree); _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE); return m_tree->val(m_id) == s; } - RYML_DEPRECATED("use (this->val() != s)") bool operator!= (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT(m_tree); _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE); return m_tree->val(m_id) != s; } - /** @endcond */ - - /** @} */ - -}; - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -// NOLINTBEGIN(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator) - -/** A reference to a node in an existing yaml tree, offering a more - * convenient API than the index-based API used in the tree. - * - * Unlike its imutable ConstNodeRef peer, a NodeRef can be used to - * mutate the tree, both by writing to existing nodes and by creating - * new nodes to subsequently write to. Semantically, a NodeRef - * object can be in one of three states: - * - * ```text - * invalid := not pointing at anything - * readable := points at an existing tree/node - * seed := points at an existing tree, and the node - * may come to exist, if we write to it. - * ``` - * - * So both `readable` and `seed` are states where the node is also `valid`. - * - * ```cpp - * Tree t = parse_in_arena("{a: b}"); - * NodeRef invalid; // not pointing at anything. - * NodeRef readable = t["a"]; // also valid, because "a" exists - * NodeRef seed = t["none"]; // also valid, but is seed because "none" is not in the map - * ``` - * - * When the object is in seed state, using it to read from the tree is - * UB. The seed node can be used to write to the tree, provided that - * its create() method is called prior to writing, which happens in - * most modifying methods in NodeRef. - * - * It is the owners's responsibility to verify that an existing - * node is readable before subsequently using it to read from the - * tree. - * - * @warning The lifetime of the tree must be larger than that of this - * object. It is up to the user to ensure that this happens. - */ -class RYML_EXPORT NodeRef : public detail::RoNodeMethods // NOLINT -{ -public: - - using tree_type = Tree; - using base_type = detail::RoNodeMethods; - -private: - - Tree *C4_RESTRICT m_tree; - id_type m_id; - - /** This member is used to enable lazy operator[] writing. When a child - * with a key or index is not found, m_id is set to the id of the parent - * and the asked-for key or index are stored in this member until a write - * does happen. Then it is given as key or index for creating the child. - * When a key is used, the csubstr stores it (so the csubstr's string is - * non-null and the csubstr's size is different from NONE). When an index is - * used instead, the csubstr's string is set to null, and only the csubstr's - * size is set to a value different from NONE. Otherwise, when operator[] - * does find the child then this member is empty: the string is null and - * the size is NONE. */ - csubstr m_seed; - - friend ConstNodeRef; - friend struct detail::RoNodeMethods; - - // require valid: a helper macro, undefined at the end - #define _C4RR() \ - RYML_ASSERT(m_tree != nullptr); \ - _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE && !is_seed()) - // require id: a helper macro, undefined at the end - #define _C4RID() \ - RYML_ASSERT(m_tree != nullptr); \ - _RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE) - -public: - - /** @name construction */ - /** @{ */ - - NodeRef() noexcept : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); } - NodeRef(Tree &t) noexcept : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); } - NodeRef(Tree *t) noexcept : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); } - NodeRef(Tree *t, id_type id) noexcept : m_tree(t), m_id(id), m_seed() { _clear_seed(); } - NodeRef(Tree *t, id_type id, id_type seed_pos) noexcept : m_tree(t), m_id(id), m_seed() { m_seed.str = nullptr; m_seed.len = (size_t)seed_pos; } - NodeRef(Tree *t, id_type id, csubstr seed_key) noexcept : m_tree(t), m_id(id), m_seed(seed_key) {} - NodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE), m_seed() {} - - void _clear_seed() noexcept { /*do the following manually or an assert is triggered: */ m_seed.str = nullptr; m_seed.len = npos; } - - /** @} */ - -public: - - /** @name assignment */ - /** @{ */ - - NodeRef(NodeRef const&) noexcept = default; - NodeRef(NodeRef &&) noexcept = default; - - NodeRef& operator= (NodeRef const&) noexcept = default; - NodeRef& operator= (NodeRef &&) noexcept = default; - - /** @} */ - -public: - - /** @name state_queries - * @{ */ - - /** true if the object is not referring to any existing or seed node. @see the doc for @ref NodeRef */ - bool invalid() const noexcept { return m_tree == nullptr || m_id == NONE; } - /** true if the object is not invalid and in seed state. @see the doc for @ref NodeRef */ - bool is_seed() const noexcept { return (m_tree != nullptr && m_id != NONE) && (m_seed.str != nullptr || m_seed.len != (size_t)NONE); } - /** true if the object is not invalid and not in seed state. @see the doc for @ref NodeRef */ - bool readable() const noexcept { return (m_tree != nullptr && m_id != NONE) && (m_seed.str == nullptr && m_seed.len == (size_t)NONE); } - - RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") inline bool valid() const { return m_tree != nullptr && m_id != NONE; } - - /** @} */ - -public: - - /** @name comparisons */ - /** @{ */ - - bool operator== (NodeRef const& that) const - { - if(m_tree == that.m_tree && m_id == that.m_id) - { - bool seed = is_seed(); - if(seed == that.is_seed()) - { - if(seed) - { - return (m_seed.len == that.m_seed.len) - && (m_seed.str == that.m_seed.str - || m_seed == that.m_seed); // do strcmp only in the last resort - } - return true; - } - } - return false; - } - bool operator!= (NodeRef const& that) const { return ! this->operator==(that); } - - bool operator== (ConstNodeRef const& that) const { return m_tree == that.m_tree && m_id == that.m_id && !is_seed(); } - bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); } - - /** @cond dev */ - RYML_DEPRECATED("use !readable()") bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); } - RYML_DEPRECATED("use readable()") bool operator!= (std::nullptr_t) const { return !(m_tree == nullptr || m_id == NONE || is_seed()); } - - RYML_DEPRECATED("use `this->val() == s`") bool operator== (csubstr s) const { _C4RR(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) == s; } - RYML_DEPRECATED("use `this->val() != s`") bool operator!= (csubstr s) const { _C4RR(); _RYML_CB_ASSERT(m_tree->m_callbacks, has_val()); return m_tree->val(m_id) != s; } - /** @endcond */ - -public: - - /** @name node_property_getters - * @{ */ - - C4_ALWAYS_INLINE Tree * tree() noexcept { return m_tree; } - C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; } - - C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; } - - /** @} */ - -public: - - /** @name node_modifiers */ - /** @{ */ - - void create() { _apply_seed(); } - - void change_type(NodeType t) { _C4RR(); m_tree->change_type(m_id, t); } - - void set_type(NodeType t) { _apply_seed(); m_tree->_set_flags(m_id, t); } - void set_key(csubstr key) { _apply_seed(); m_tree->_set_key(m_id, key); } - void set_val(csubstr val) { _apply_seed(); m_tree->_set_val(m_id, val); } - void set_key_tag(csubstr key_tag) { _apply_seed(); m_tree->set_key_tag(m_id, key_tag); } - void set_val_tag(csubstr val_tag) { _apply_seed(); m_tree->set_val_tag(m_id, val_tag); } - void set_key_anchor(csubstr key_anchor) { _apply_seed(); m_tree->set_key_anchor(m_id, key_anchor); } - void set_val_anchor(csubstr val_anchor) { _apply_seed(); m_tree->set_val_anchor(m_id, val_anchor); } - void set_key_ref(csubstr key_ref) { _apply_seed(); m_tree->set_key_ref(m_id, key_ref); } - void set_val_ref(csubstr val_ref) { _apply_seed(); m_tree->set_val_ref(m_id, val_ref); } - - void set_container_style(NodeType_e style) { _C4RR(); m_tree->set_container_style(m_id, style); } - void set_key_style(NodeType_e style) { _C4RR(); m_tree->set_key_style(m_id, style); } - void set_val_style(NodeType_e style) { _C4RR(); m_tree->set_val_style(m_id, style); } - void clear_style(bool recurse=false) { _C4RR(); m_tree->clear_style(m_id, recurse); } - void set_style_conditionally(NodeType type_mask, - NodeType rem_style_flags, - NodeType add_style_flags, - bool recurse=false) - { - _C4RR(); m_tree->set_style_conditionally(m_id, type_mask, rem_style_flags, add_style_flags, recurse); - } - -public: - - void clear() - { - if(is_seed()) - return; - m_tree->remove_children(m_id); - m_tree->_clear(m_id); - } - - void clear_key() - { - if(is_seed()) - return; - m_tree->_clear_key(m_id); - } - - void clear_val() - { - if(is_seed()) - return; - m_tree->_clear_val(m_id); - } - - void clear_children() - { - if(is_seed()) - return; - m_tree->remove_children(m_id); - } - - void operator= (NodeType_e t) - { - _apply_seed(); - m_tree->_add_flags(m_id, t); - } - - void operator|= (NodeType_e t) - { - _apply_seed(); - m_tree->_add_flags(m_id, t); - } - - void operator= (NodeInit const& v) - { - _apply_seed(); - _apply(v); - } - - void operator= (NodeScalar const& v) - { - _apply_seed(); - _apply(v); - } - - void operator= (std::nullptr_t) - { - _apply_seed(); - _apply(csubstr{}); - } - - void operator= (csubstr v) - { - _apply_seed(); - _apply(v); - } - - template - void operator= (const char (&v)[N]) - { - _apply_seed(); - csubstr sv; - sv.assign(v); - _apply(sv); - } - - /** @} */ - -public: - - /** @name serialization */ - /** @{ */ - - /** serialize a variable to the arena */ - template - csubstr to_arena(T const& C4_RESTRICT s) - { - RYML_ASSERT(m_tree); // no need for valid or readable - return m_tree->to_arena(s); - } - - template - size_t set_key_serialized(T const& C4_RESTRICT k) - { - _apply_seed(); - csubstr s = m_tree->to_arena(k); - m_tree->_set_key(m_id, s); - return s.len; - } - size_t set_key_serialized(std::nullptr_t) - { - _apply_seed(); - m_tree->_set_key(m_id, csubstr{}); - return 0; - } - - template - size_t set_val_serialized(T const& C4_RESTRICT v) - { - _apply_seed(); - csubstr s = m_tree->to_arena(v); - m_tree->_set_val(m_id, s); - return s.len; - } - size_t set_val_serialized(std::nullptr_t) - { - _apply_seed(); - m_tree->_set_val(m_id, csubstr{}); - return 0; - } - - /** encode a blob as base64 into the tree's arena, then assign the - * result to the node's key - * @return the size of base64-encoded blob */ - size_t set_key_serialized(fmt::const_base64_wrapper w); - /** encode a blob as base64 into the tree's arena, then assign the - * result to the node's val - * @return the size of base64-encoded blob */ - size_t set_val_serialized(fmt::const_base64_wrapper w); - - /** serialize a variable, then assign the result to the node's val */ - NodeRef& operator<< (csubstr s) - { - // this overload is needed to prevent ambiguity (there's also - // operator<< for writing a substr to a stream) - _apply_seed(); - write(this, s); - _RYML_CB_ASSERT(m_tree->m_callbacks, val() == s); - return *this; - } - - template - NodeRef& operator<< (T const& C4_RESTRICT v) - { - _apply_seed(); - write(this, v); - return *this; - } - - /** serialize a variable, then assign the result to the node's key */ - template - NodeRef& operator<< (Key const& C4_RESTRICT v) - { - _apply_seed(); - set_key_serialized(v.k); - return *this; - } - - /** serialize a variable, then assign the result to the node's key */ - template - NodeRef& operator<< (Key const& C4_RESTRICT v) - { - _apply_seed(); - set_key_serialized(v.k); - return *this; - } - - NodeRef& operator<< (Key w) - { - set_key_serialized(w.wrapper); - return *this; - } - - NodeRef& operator<< (fmt::const_base64_wrapper w) - { - set_val_serialized(w); - return *this; - } - - /** @} */ - -private: - - void _apply_seed() - { - _C4RID(); - if(m_seed.str) // we have a seed key: use it to create the new child - { - m_id = m_tree->append_child(m_id); - m_tree->_set_key(m_id, m_seed); - m_seed.str = nullptr; - m_seed.len = (size_t)NONE; - } - else if(m_seed.len != (size_t)NONE) // we have a seed index: create a child at that position - { - _RYML_CB_ASSERT(m_tree->m_callbacks, (size_t)m_tree->num_children(m_id) == m_seed.len); - m_id = m_tree->append_child(m_id); - m_seed.str = nullptr; - m_seed.len = (size_t)NONE; - } - else - { - _RYML_CB_ASSERT(m_tree->m_callbacks, readable()); - } - } - - void _apply(csubstr v) - { - m_tree->_set_val(m_id, v); - } - - void _apply(NodeScalar const& v) - { - m_tree->_set_val(m_id, v); - } - - void _apply(NodeInit const& i) - { - m_tree->_set(m_id, i); - } - -public: - - /** @name modification of hierarchy */ - /** @{ */ - - NodeRef insert_child(NodeRef after) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, after.m_tree == m_tree); - NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id)); - return r; - } - - NodeRef insert_child(NodeInit const& i, NodeRef after) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, after.m_tree == m_tree); - NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id)); - r._apply(i); - return r; - } - - NodeRef prepend_child() - { - _C4RR(); - NodeRef r(m_tree, m_tree->insert_child(m_id, NONE)); - return r; - } - - NodeRef prepend_child(NodeInit const& i) - { - _C4RR(); - NodeRef r(m_tree, m_tree->insert_child(m_id, NONE)); - r._apply(i); - return r; - } - - NodeRef append_child() - { - _C4RR(); - NodeRef r(m_tree, m_tree->append_child(m_id)); - return r; - } - - NodeRef append_child(NodeInit const& i) - { - _C4RR(); - NodeRef r(m_tree, m_tree->append_child(m_id)); - r._apply(i); - return r; - } - - NodeRef insert_sibling(ConstNodeRef const& after) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, after.m_tree == m_tree); - NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id)); - return r; - } - - NodeRef insert_sibling(NodeInit const& i, ConstNodeRef const& after) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, after.m_tree == m_tree); - NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id)); - r._apply(i); - return r; - } - - NodeRef prepend_sibling() - { - _C4RR(); - NodeRef r(m_tree, m_tree->prepend_sibling(m_id)); - return r; - } - - NodeRef prepend_sibling(NodeInit const& i) - { - _C4RR(); - NodeRef r(m_tree, m_tree->prepend_sibling(m_id)); - r._apply(i); - return r; - } - - NodeRef append_sibling() - { - _C4RR(); - NodeRef r(m_tree, m_tree->append_sibling(m_id)); - return r; - } - - NodeRef append_sibling(NodeInit const& i) - { - _C4RR(); - NodeRef r(m_tree, m_tree->append_sibling(m_id)); - r._apply(i); - return r; - } - -public: - - void remove_child(NodeRef & child) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, has_child(child)); - _RYML_CB_ASSERT(m_tree->m_callbacks, child.parent().id() == id()); - m_tree->remove(child.id()); - child.clear(); - } - - //! remove the nth child of this node - void remove_child(id_type pos) - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, pos >= 0 && pos < num_children()); - id_type child = m_tree->child(m_id, pos); - _RYML_CB_ASSERT(m_tree->m_callbacks, child != NONE); - m_tree->remove(child); - } - - //! remove a child by name - void remove_child(csubstr key) - { - _C4RR(); - id_type child = m_tree->find_child(m_id, key); - _RYML_CB_ASSERT(m_tree->m_callbacks, child != NONE); - m_tree->remove(child); - } - -public: - - /** change the node's position within its parent, placing it after - * @p after. To move to the first position in the parent, simply - * pass an empty or default-constructed reference like this: - * `n.move({})`. */ - void move(ConstNodeRef const& after) - { - _C4RR(); - m_tree->move(m_id, after.m_id); - } - - /** move the node to a different @p parent (which may belong to a - * different tree), placing it after @p after. When the - * destination parent is in a new tree, then this node's tree - * pointer is reset to the tree of the parent node. */ - void move(NodeRef const& parent, ConstNodeRef const& after) - { - _C4RR(); - if(parent.m_tree == m_tree) - { - m_tree->move(m_id, parent.m_id, after.m_id); - } - else - { - parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id); - m_tree = parent.m_tree; - } - } - - /** duplicate the current node somewhere within its parent, and - * place it after the node @p after. To place into the first - * position of the parent, simply pass an empty or - * default-constructed reference like this: `n.move({})`. */ - NodeRef duplicate(ConstNodeRef const& after) const - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree == after.m_tree || after.m_id == NONE); - id_type dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id); - NodeRef r(m_tree, dup); - return r; - } - - /** duplicate the current node somewhere into a different @p parent - * (possibly from a different tree), and place it after the node - * @p after. To place into the first position of the parent, - * simply pass an empty or default-constructed reference like - * this: `n.move({})`. */ - NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, parent.m_tree == after.m_tree || after.m_id == NONE); - if(parent.m_tree == m_tree) - { - id_type dup = m_tree->duplicate(m_id, parent.m_id, after.m_id); - NodeRef r(m_tree, dup); - return r; - } - else - { - id_type dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id); - NodeRef r(parent.m_tree, dup); - return r; - } - } - - void duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const - { - _C4RR(); - _RYML_CB_ASSERT(m_tree->m_callbacks, parent.m_tree == after.m_tree); - if(parent.m_tree == m_tree) - { - m_tree->duplicate_children(m_id, parent.m_id, after.m_id); - } - else - { - parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id); - } - } - - /** @} */ - -#undef _C4RR -#undef _C4RID -}; - -// NOLINTEND(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator) - - -//----------------------------------------------------------------------------- - -inline ConstNodeRef::ConstNodeRef(NodeRef const& that) noexcept - : m_tree(that.m_tree) - , m_id(!that.is_seed() ? that.id() : (id_type)NONE) -{ -} - -inline ConstNodeRef::ConstNodeRef(NodeRef && that) noexcept // NOLINT - : m_tree(that.m_tree) - , m_id(!that.is_seed() ? that.id() : (id_type)NONE) -{ -} - - -inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that) noexcept -{ - m_tree = (that.m_tree); - m_id = (!that.is_seed() ? that.id() : (id_type)NONE); - return *this; -} - -inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that) noexcept // NOLINT -{ - m_tree = (that.m_tree); - m_id = (!that.is_seed() ? that.id() : (id_type)NONE); - return *this; -} - - -//----------------------------------------------------------------------------- - -/** @addtogroup doc_serialization_helpers - * - * @{ - */ - -template -C4_ALWAYS_INLINE void write(NodeRef *n, T const& v) -{ - n->set_val_serialized(v); -} - -template -C4_ALWAYS_INLINE bool read(ConstNodeRef const& C4_RESTRICT n, T *v) -{ - return read(n.m_tree, n.m_id, v); -} - -template -C4_ALWAYS_INLINE bool read(NodeRef const& C4_RESTRICT n, T *v) -{ - return read(n.tree(), n.id(), v); -} - -template -C4_ALWAYS_INLINE bool readkey(ConstNodeRef const& C4_RESTRICT n, T *v) -{ - return readkey(n.m_tree, n.m_id, v); -} - -template -C4_ALWAYS_INLINE bool readkey(NodeRef const& C4_RESTRICT n, T *v) -{ - return readkey(n.tree(), n.id(), v); -} - -/** @} */ - -/** @} */ - - -} // 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_NODE_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/node_type.hpp b/3rdparty/rapidyaml/include/c4/yml/node_type.hpp deleted file mode 100644 index 4ee79fdfaa..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/node_type.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/parse.hpp b/3rdparty/rapidyaml/include/c4/yml/parse.hpp deleted file mode 100644 index 124defb3ec..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/parse.hpp +++ /dev/null @@ -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 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; - - -//----------------------------------------------------------------------------- - -/** @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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/parse_engine.def.hpp b/3rdparty/rapidyaml/include/c4/yml/parse_engine.def.hpp deleted file mode 100644 index 2aebaa3c7f..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/parse_engine.def.hpp +++ /dev/null @@ -1,8317 +0,0 @@ -#ifndef _C4_YML_PARSE_ENGINE_DEF_HPP_ -#define _C4_YML_PARSE_ENGINE_DEF_HPP_ - -#include "c4/yml/parse_engine.hpp" -#include "c4/error.hpp" -#include "c4/charconv.hpp" -#include "c4/utf.hpp" - -#include - -#include "c4/yml/detail/dbgprint.hpp" -#include "c4/yml/filter_processor.hpp" -#ifdef RYML_DBG -#include -#include "c4/yml/detail/print.hpp" -#define _c4err_(fmt, ...) do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, __VA_ARGS__); } while(0) -#define _c4err(fmt) do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__); } while(0) -#else -#define _c4err_(fmt, ...) this->_err("ERROR: " fmt, __VA_ARGS__) -#define _c4err(fmt) this->_err("ERROR: {}", fmt) -#endif - - -#if defined(RYML_WITH_TAB_TOKENS) -#define _RYML_WITH_TAB_TOKENS(...) __VA_ARGS__ -#define _RYML_WITHOUT_TAB_TOKENS(...) -#define _RYML_WITH_OR_WITHOUT_TAB_TOKENS(with, without) with -#else -#define _RYML_WITH_TAB_TOKENS(...) -#define _RYML_WITHOUT_TAB_TOKENS(...) __VA_ARGS__ -#define _RYML_WITH_OR_WITHOUT_TAB_TOKENS(with, without) without -#endif - - -// scaffold: -#define _c4dbgnextline() \ - do { \ - _c4dbgq("\n-----------"); \ - _c4dbgt("handling line={}, offset={}B", \ - m_evt_handler->m_curr->pos.line, \ - m_evt_handler->m_curr->pos.offset); \ - } while(0) - - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable: 4296/*expression is always 'boolean_value'*/) -# pragma warning(disable: 4702/*unreachable code*/) -#elif defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtype-limits" // to remove a warning on an assertion that a size_t >= 0. Later on, this size_t will turn into a template argument, and then it can become < 0. -# pragma clang diagnostic ignored "-Wformat-nonliteral" -# pragma clang diagnostic ignored "-Wold-style-cast" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" // to remove a warning on an assertion that a size_t >= 0. Later on, this size_t will turn into a template argument, and then it can become < 0. -# pragma GCC diagnostic ignored "-Wformat-nonliteral" -# pragma GCC diagnostic ignored "-Wold-style-cast" -# if __GNUC__ >= 7 -# pragma GCC diagnostic ignored "-Wduplicated-branches" -# endif -#endif - -// NOLINTBEGIN(hicpp-signed-bitwise,cppcoreguidelines-avoid-goto,hicpp-avoid-goto,hicpp-multiway-paths-covered) - -namespace c4 { -namespace yml { - -namespace { // NOLINT - -C4_HOT C4_ALWAYS_INLINE bool _is_blck_token(csubstr s) noexcept -{ - RYML_ASSERT(s.len > 0); - RYML_ASSERT(s.str[0] == '-' || s.str[0] == ':' || s.str[0] == '?'); - return ((s.len == 1) || ((s.str[1] == ' ') _RYML_WITH_TAB_TOKENS( || (s.str[1] == '\t')))); -} - -inline bool _is_doc_begin_token(csubstr s) -{ - RYML_ASSERT(s.begins_with('-')); - RYML_ASSERT(!s.ends_with("\n")); - RYML_ASSERT(!s.ends_with("\r")); - return (s.len >= 3 && s.str[1] == '-' && s.str[2] == '-') - && (s.len == 3 || (s.str[3] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[3] == '\t'))); -} - -inline bool _is_doc_end_token(csubstr s) -{ - RYML_ASSERT(s.begins_with('.')); - RYML_ASSERT(!s.ends_with("\n")); - RYML_ASSERT(!s.ends_with("\r")); - return (s.len >= 3 && s.str[1] == '.' && s.str[2] == '.') - && (s.len == 3 || (s.str[3] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[3] == '\t'))); -} - -inline bool _is_doc_token(csubstr s) noexcept -{ - // - // NOTE: this function was failing under some scenarios when - // compiled with gcc -O2 (but not -O3 or -O1 or -O0), likely - // related to optimizer assumptions on the input string and - // possibly caused from UB around assignment to that string (the - // call site was in _scan_block()). For more details see: - // - // https://github.com/biojppm/rapidyaml/issues/440 - // - // The current version does not suffer this problem, but it may - // appear again. - // - // - // UPDATE. The problem appeared again in gcc12 and gcc13 with -Os - // (but not any other optimization level, nor any other compiler - // or version), because the assignment to s is being hoisted out - // of the loop which calls this function. Then the length doesn't - // enter the s.len >= 3 when it should. Adding a - // C4_DONT_OPTIMIZE(var) makes the problem go away. - // - if(s.len >= 3) - { - switch(s.str[0]) - { - case '-': - //return _is_doc_begin_token(s); // this was failing with gcc -O2 - return (s.str[1] == '-' && s.str[2] == '-') - && (s.len == 3 || (s.str[3] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[3] == '\t'))); - case '.': - //return _is_doc_end_token(s); // this was failing with gcc -O2 - return (s.str[1] == '.' && s.str[2] == '.') - && (s.len == 3 || (s.str[3] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[3] == '\t'))); - } - } - return false; -} - -inline size_t _is_special_json_scalar(csubstr s) -{ - RYML_ASSERT(s.len); - switch(s.str[0]) - { - case 'f': - if(s.len >= 5 && s.begins_with("false")) - return 5u; - break; - case 't': - if(s.len >= 4 && s.begins_with("true")) - return 4u; - break; - case 'n': - if(s.len >= 4 && s.begins_with("null")) - return 4u; - break; - } - return 0u; -} - - -//----------------------------------------------------------------------------- - -C4_ALWAYS_INLINE size_t _extend_from_combined_newline(char nl, char following) -{ - return (nl == '\n' && following == '\r') || (nl == '\r' && following == '\n'); -} - -//! look for the next newline chars, and jump to the right of those -inline substr from_next_line(substr rem) -{ - size_t nlpos = rem.first_of("\r\n"); - if(nlpos == csubstr::npos) - return {}; - const char nl = rem[nlpos]; - rem = rem.right_of(nlpos); - if(rem.empty()) - return {}; - if(_extend_from_combined_newline(nl, rem.front())) - rem = rem.sub(1); - return rem; -} - - -//----------------------------------------------------------------------------- - -inline size_t _count_following_newlines(csubstr r, size_t *C4_RESTRICT i) -{ - RYML_ASSERT(r[*i] == '\n'); - size_t numnl_following = 0; - ++(*i); - for( ; *i < r.len; ++(*i)) - { - if(r.str[*i] == '\n') - ++numnl_following; - // skip leading whitespace - else if(r.str[*i] == ' ' || r.str[*i] == '\t' || r.str[*i] == '\r') - ; - else - break; - } - return numnl_following; -} - -/** @p i is set to the first non whitespace character after the line - * @return the number of empty lines after the initial position */ -inline size_t _count_following_newlines(csubstr r, size_t *C4_RESTRICT i, size_t indentation) -{ - RYML_ASSERT(r[*i] == '\n'); - size_t numnl_following = 0; - ++(*i); - if(indentation == 0) - { - for( ; *i < r.len; ++(*i)) - { - if(r.str[*i] == '\n') - ++numnl_following; - // skip leading whitespace - else if(r.str[*i] == ' ' || r.str[*i] == '\t' || r.str[*i] == '\r') - ; - else - break; - } - } - else - { - for( ; *i < r.len; ++(*i)) - { - if(r.str[*i] == '\n') - { - ++numnl_following; - // skip the indentation after the newline - size_t stop = *i + indentation; - for( ; *i < r.len; ++(*i)) - { - if(r.str[*i] != ' ' && r.str[*i] != '\r') - break; - RYML_ASSERT(*i < stop); - } - C4_UNUSED(stop); - } - // skip leading whitespace - else if(r.str[*i] == ' ' || r.str[*i] == '\t' || r.str[*i] == '\r') - ; - else - break; - } - } - return numnl_following; -} - -} // anon namespace - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -template -ParseEngine::~ParseEngine() -{ - _free(); - _clr(); -} - -template -ParseEngine::ParseEngine(EventHandler *evt_handler, ParserOptions opts) - : m_options(opts) - , m_file() - , m_buf() - , m_evt_handler(evt_handler) - , m_pending_anchors() - , m_pending_tags() - , m_was_inside_qmrk(false) - , m_doc_empty(false) - , m_prev_colon(npos) - , m_encoding(NOBOM) - , m_newline_offsets() - , m_newline_offsets_size(0) - , m_newline_offsets_capacity(0) - , m_newline_offsets_buf() -{ - RYML_CHECK(evt_handler); -} - -template -ParseEngine::ParseEngine(ParseEngine &&that) noexcept - : m_options(that.m_options) - , m_file(that.m_file) - , m_buf(that.m_buf) - , m_evt_handler(that.m_evt_handler) - , m_pending_anchors(that.m_pending_anchors) - , m_pending_tags(that.m_pending_tags) - , m_was_inside_qmrk(false) - , m_doc_empty(false) - , m_prev_colon(npos) - , m_encoding(NOBOM) - , m_newline_offsets(that.m_newline_offsets) - , m_newline_offsets_size(that.m_newline_offsets_size) - , m_newline_offsets_capacity(that.m_newline_offsets_capacity) - , m_newline_offsets_buf(that.m_newline_offsets_buf) -{ - that._clr(); -} - -template -ParseEngine::ParseEngine(ParseEngine const& that) - : m_options(that.m_options) - , m_file(that.m_file) - , m_buf(that.m_buf) - , m_evt_handler(that.m_evt_handler) - , m_pending_anchors(that.m_pending_anchors) - , m_pending_tags(that.m_pending_tags) - , m_was_inside_qmrk(false) - , m_doc_empty(false) - , m_prev_colon(npos) - , m_encoding(NOBOM) - , m_newline_offsets() - , m_newline_offsets_size() - , m_newline_offsets_capacity() - , m_newline_offsets_buf() -{ - if(that.m_newline_offsets_capacity) - { - _resize_locations(that.m_newline_offsets_capacity); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_newline_offsets_capacity == that.m_newline_offsets_capacity); - memcpy(m_newline_offsets, that.m_newline_offsets, that.m_newline_offsets_size * sizeof(size_t)); - m_newline_offsets_size = that.m_newline_offsets_size; - } -} - -template -ParseEngine& ParseEngine::operator=(ParseEngine &&that) noexcept -{ - _free(); - m_options = (that.m_options); - m_file = (that.m_file); - m_buf = (that.m_buf); - m_evt_handler = that.m_evt_handler; - m_pending_anchors = that.m_pending_anchors; - m_pending_tags = that.m_pending_tags; - m_was_inside_qmrk = that.m_was_inside_qmrk; - m_doc_empty = that.m_doc_empty; - m_prev_colon = that.m_prev_colon; - m_encoding = that.m_encoding; - m_newline_offsets = (that.m_newline_offsets); - m_newline_offsets_size = (that.m_newline_offsets_size); - m_newline_offsets_capacity = (that.m_newline_offsets_capacity); - m_newline_offsets_buf = (that.m_newline_offsets_buf); - that._clr(); - return *this; -} - -template -ParseEngine& ParseEngine::operator=(ParseEngine const& that) -{ - if(&that != this) - { - _free(); - m_options = (that.m_options); - m_file = (that.m_file); - m_buf = (that.m_buf); - m_evt_handler = that.m_evt_handler; - m_pending_anchors = that.m_pending_anchors; - m_pending_tags = that.m_pending_tags; - m_was_inside_qmrk = that.m_was_inside_qmrk; - m_doc_empty = that.m_doc_empty; - m_prev_colon = that.m_prev_colon; - m_encoding = that.m_encoding; - if(that.m_newline_offsets_capacity > m_newline_offsets_capacity) - _resize_locations(that.m_newline_offsets_capacity); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_newline_offsets_capacity >= that.m_newline_offsets_capacity); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_newline_offsets_capacity >= that.m_newline_offsets_size); - memcpy(m_newline_offsets, that.m_newline_offsets, that.m_newline_offsets_size * sizeof(size_t)); - m_newline_offsets_size = that.m_newline_offsets_size; - m_newline_offsets_buf = that.m_newline_offsets_buf; - } - return *this; -} - -template -void ParseEngine::_clr() -{ - m_options = {}; - m_file = {}; - m_buf = {}; - m_evt_handler = {}; - m_pending_anchors = {}; - m_pending_tags = {}; - m_was_inside_qmrk = false; - m_doc_empty = true; - m_prev_colon = npos; - m_encoding = NOBOM; - m_newline_offsets = {}; - m_newline_offsets_size = {}; - m_newline_offsets_capacity = {}; - m_newline_offsets_buf = {}; -} - -template -void ParseEngine::_free() -{ - if(m_newline_offsets) - { - _RYML_CB_FREE(m_evt_handler->m_stack.m_callbacks, m_newline_offsets, size_t, m_newline_offsets_capacity); - m_newline_offsets = nullptr; - m_newline_offsets_size = 0u; - m_newline_offsets_capacity = 0u; - m_newline_offsets_buf = nullptr; - } -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_reset() -{ - m_pending_anchors = {}; - m_pending_tags = {}; - m_doc_empty = true; - m_was_inside_qmrk = false; - m_prev_colon = npos; - m_encoding = NOBOM; - if(m_options.locations()) - { - _prepare_locations(); - } -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_relocate_arena(csubstr prev_arena, substr next_arena) -{ - #define _ryml_relocate(s) \ - if((s).is_sub(prev_arena)) \ - { \ - (s).str = next_arena.str + ((s).str - prev_arena.str); \ - } - _ryml_relocate(m_buf); - _ryml_relocate(m_newline_offsets_buf); - for(size_t i = 0; i < m_pending_tags.num_entries; ++i) - _ryml_relocate(m_pending_tags.annotations[i].str); - for(size_t i = 0; i < m_pending_anchors.num_entries; ++i) - _ryml_relocate(m_pending_anchors.annotations[i].str); - #undef _ryml_relocate -} - -template -void ParseEngine::_s_relocate_arena(void* data, csubstr prev_arena, substr next_arena) -{ - ((ParseEngine*)data)->_relocate_arena(prev_arena, next_arena); -} - - -//----------------------------------------------------------------------------- - -template -template -void ParseEngine::_fmt_msg(DumpFn &&dumpfn) const -{ - auto const *const C4_RESTRICT st = m_evt_handler->m_curr; - auto const& lc = st->line_contents; - csubstr contents = lc.stripped; - if(contents.len) - { - // print the yaml src line - size_t offs = 3u + to_chars(substr{}, st->pos.line) + to_chars(substr{}, st->pos.col); - if(m_file.len) - { - detail::_dump(std::forward(dumpfn), "{}:", m_file); - offs += m_file.len + 1; - } - detail::_dump(std::forward(dumpfn), "{}:{}: ", st->pos.line, st->pos.col); - csubstr maybe_full_content = (contents.len < 80u ? contents : contents.first(80u)); - csubstr maybe_ellipsis = (contents.len < 80u ? csubstr{} : csubstr("...")); - detail::_dump(std::forward(dumpfn), "{}{} (size={})\n", maybe_full_content, maybe_ellipsis, contents.len); - // highlight the remaining portion of the previous line - size_t firstcol = (size_t)(lc.rem.begin() - lc.full.begin()); - size_t lastcol = firstcol + lc.rem.len; - for(size_t i = 0; i < offs + firstcol; ++i) - std::forward(dumpfn)(" "); - std::forward(dumpfn)("^"); - for(size_t i = 1, e = (lc.rem.len < 80u ? lc.rem.len : 80u); i < e; ++i) - std::forward(dumpfn)("~"); - detail::_dump(std::forward(dumpfn), "{} (cols {}-{})\n", maybe_ellipsis, firstcol+1, lastcol+1); - } - else - { - std::forward(dumpfn)("\n"); - } - -#ifdef RYML_DBG - // next line: print the state flags - { - char flagbuf_[128]; - detail::_dump(std::forward(dumpfn), "top state: {}\n", detail::_parser_flags_to_str(flagbuf_, m_evt_handler->m_curr->flags)); - } -#endif -} - - -//----------------------------------------------------------------------------- - -template -template -void ParseEngine::_err(csubstr fmt, Args const& C4_RESTRICT ...args) const -{ - char errmsg[RYML_ERRMSG_SIZE]; - detail::_SubstrWriter writer(errmsg); - auto dumpfn = [&writer](csubstr s){ writer.append(s); }; - detail::_dump(dumpfn, fmt, args...); - writer.append('\n'); - _fmt_msg(dumpfn); - size_t len = writer.pos < RYML_ERRMSG_SIZE ? writer.pos : RYML_ERRMSG_SIZE; - m_evt_handler->cancel_parse(); - m_evt_handler->m_stack.m_callbacks.m_error(errmsg, len, m_evt_handler->m_curr->pos, m_evt_handler->m_stack.m_callbacks.m_user_data); -} - - -//----------------------------------------------------------------------------- -#ifdef RYML_DBG -template -template -void ParseEngine::_dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const -{ - if(_dbg_enabled()) - { - auto dumpfn = [](csubstr s){ if(s.str) fwrite(s.str, 1, s.len, stdout); }; - detail::_dump(dumpfn, fmt, args...); - dumpfn("\n"); - _fmt_msg(dumpfn); - } -} -#endif - - -//----------------------------------------------------------------------------- -template -bool ParseEngine::_finished_file() const -{ - bool ret = m_evt_handler->m_curr->pos.offset >= m_buf.len; - if(ret) - { - _c4dbgp("finished file!!!"); - } - return ret; -} - -template -C4_HOT C4_ALWAYS_INLINE bool ParseEngine::_finished_line() const -{ - return m_evt_handler->m_curr->line_contents.rem.empty(); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_maybe_skip_whitespace_tokens() -{ - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(rem.len && (rem.str[0] == ' ' _RYML_WITH_TAB_TOKENS(|| rem.str[0] == '\t'))) - { - size_t pos = rem.first_not_of(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' ')); - if(pos == npos) - pos = rem.len; // maybe the line is just all whitespace - _c4dbgpf("skip {} whitespace characters", pos); - _line_progressed(pos); - } -} - -template -void ParseEngine::_maybe_skipchars(char c) -{ - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(rem.len && rem.str[0] == c) - { - size_t pos = rem.first_not_of(c); - if(pos == npos) - pos = rem.len; // maybe the line is just all c - _c4dbgpf("skip {}x'{}'", pos, c); - _line_progressed(pos); - } -} - -#ifdef RYML_NO_COVERAGE__TO_BE_DELETED -template -void ParseEngine::_maybe_skipchars_up_to(char c, size_t max_to_skip) -{ - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(rem.len && rem.str[0] == c) - { - size_t pos = rem.first_not_of(c); - if(pos == npos) - pos = rem.len; // maybe the line is just all c - if(pos > max_to_skip) - pos = max_to_skip; - _c4dbgpf("skip {}x'{}'", pos, c); - _line_progressed(pos); - } -} -#endif - -template -template -void ParseEngine::_skipchars(const char (&chars)[N]) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.begins_with_any(chars)); - size_t pos = m_evt_handler->m_curr->line_contents.rem.first_not_of(chars); - if(pos == npos) - pos = m_evt_handler->m_curr->line_contents.rem.len; // maybe the line is just whitespace - _c4dbgpf("skip {} characters", pos); - _line_progressed(pos); -} - -template -void ParseEngine::_skip_comment() -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.begins_with('#')); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.is_sub(m_evt_handler->m_curr->line_contents.full)); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - csubstr full = m_evt_handler->m_curr->line_contents.full; - // raise an error if the comment is not preceded by whitespace - if(!full.begins_with('#')) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.str > full.str); - const char c = full[(size_t)(rem.str - full.str - 1)]; - if(C4_UNLIKELY(c != ' ' && c != '\t')) - _RYML_CB_ERR(m_evt_handler->m_stack.m_callbacks, "comment not preceded by whitespace"); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.str == full.str); - } - _c4dbgpf("comment was '{}'", rem); - _line_progressed(rem.len); -} - -template -void ParseEngine::_maybe_skip_comment() -{ - csubstr s = m_evt_handler->m_curr->line_contents.rem.triml(' '); - if(s.begins_with('#')) - { - _line_progressed((size_t)(s.str - m_evt_handler->m_curr->line_contents.rem.str)); - _skip_comment(); - } -} - -template -bool ParseEngine::_maybe_scan_following_colon() noexcept -{ - if(m_evt_handler->m_curr->line_contents.rem.len) - { - if(m_evt_handler->m_curr->line_contents.rem.str[0] == ' ' || m_evt_handler->m_curr->line_contents.rem.str[0] == '\t') - { - size_t pos = m_evt_handler->m_curr->line_contents.rem.first_not_of(" \t"); - if(pos == npos) - pos = m_evt_handler->m_curr->line_contents.rem.len; // maybe the line has only spaces - _c4dbgpf("skip {}x'{}'", pos, ' '); - _line_progressed(pos); - } - if(m_evt_handler->m_curr->line_contents.rem.len && (m_evt_handler->m_curr->line_contents.rem.str[0] == ':')) - { - _c4dbgp("found ':' colon next"); - _line_progressed(1); - return true; - } - } - return false; -} - -template -bool ParseEngine::_maybe_scan_following_comma() noexcept -{ - if(m_evt_handler->m_curr->line_contents.rem.len) - { - if(m_evt_handler->m_curr->line_contents.rem.str[0] == ' ' || m_evt_handler->m_curr->line_contents.rem.str[0] == '\t') - { - size_t pos = m_evt_handler->m_curr->line_contents.rem.first_not_of(" \t"); - if(pos == npos) - pos = m_evt_handler->m_curr->line_contents.rem.len; // maybe the line has only spaces - _c4dbgpf("skip {}x'{}'", pos, ' '); - _line_progressed(pos); - } - if(m_evt_handler->m_curr->line_contents.rem.len && (m_evt_handler->m_curr->line_contents.rem.str[0] == ',')) - { - _c4dbgp("found ',' comma next"); - _line_progressed(1); - return true; - } - } - return false; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_scan_anchor() -{ - csubstr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('&')); - csubstr anchor = s.range(1, s.first_of(' ')); - _line_progressed(1u + anchor.len); - _maybe_skipchars(' '); - return anchor; -} - -template -csubstr ParseEngine::_scan_ref_seq() -{ - csubstr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('*')); - csubstr ref = s.first(s.first_of(",] :")); - _line_progressed(ref.len); - return ref; -} - -template -csubstr ParseEngine::_scan_ref_map() -{ - csubstr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('*')); - csubstr ref = s.first(s.first_of(",} ")); - _line_progressed(ref.len); - return ref; -} - -template -csubstr ParseEngine::_scan_tag() -{ - csubstr rem = m_evt_handler->m_curr->line_contents.rem.triml(' '); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.begins_with('!')); - csubstr t; - if(rem.begins_with("!!")) - { - _c4dbgp("begins with '!!'"); - if(has_any(FLOW)) - t = rem.left_of(rem.first_of(" ,")); - else - t = rem.left_of(rem.first_of(' ')); - } - else if(rem.begins_with("!<")) - { - _c4dbgp("begins with '!<'"); - t = rem.left_of(rem.first_of('>'), true); - } - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - else if(rem.begins_with("!h!")) - { - _c4dbgp("begins with '!h!'"); - t = rem.left_of(rem.first_of(' ')); - } - #endif - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.begins_with('!')); - _c4dbgp("begins with '!'"); - if(has_any(FLOW)) - t = rem.left_of(rem.first_of(" ,")); - else - t = rem.left_of(rem.first_of(' ')); - } - _line_progressed(t.len); - _maybe_skip_whitespace_tokens(); - return t; -} - - -//----------------------------------------------------------------------------- - -template -bool ParseEngine::_is_valid_start_scalar_plain_flow(csubstr s) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.empty()); - - // it's not a scalar if it starts with any of these characters: - switch(s.str[0]) - { - // these are all legal tokens which mean no scalar is starting: - case '[': - case ']': - case '{': - case '}': - case '!': - case '&': - case '*': - case '|': - case '>': - case '#': - _c4dbgpf("not a scalar: found non-scalar token '{}'", _c4prc(s.str[0])); - return false; - // '-' and ':' are illegal at the beginning if not followed by a scalar character - case '-': - case ':': - if(s.len > 1) - { - switch(s.str[1]) - { - case '\n': - case '\r': - case '{': - case '[': - //_RYML_WITHOUT_TAB_TOKENS(case '\t'): - _c4err_("invalid token \":{}\"", _c4prc(s.str[1])); - break; - case ' ': - case '}': - case ']': - if(s.str[0] == ':') - { - _c4dbgpf("not a scalar: found non-scalar token '{}{}'", s.str[0], s.str[1]); - return false; - } - break; - default: - break; - } - } - else - { - return false; - } - break; - case '?': - if(s.len > 1) - { - switch(s.str[1]) - { - case ' ': - case '\n': - case '\r': - _RYML_WITHOUT_TAB_TOKENS(case '\t':) - _c4dbgpf("not a scalar: found non-scalar token '?{}'", _c4prc(s.str[1])); - return false; - case '{': - case '}': - case '[': - case ']': - _c4err_("invalid token \"?{}\"", _c4prc(s.str[1])); - break; - default: - break; - } - } - else - { - return false; - } - break; - // everything else is a legal starting character - default: - break; - } - - return true; -} - -template -bool ParseEngine::_scan_scalar_plain_seq_flow(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RSEQ|RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL)); - - substr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with(' ')); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with('\n')); - - if(!s.len) - return false; - - if(!_is_valid_start_scalar_plain_flow(s)) - return false; - - _c4dbgp("scanning seqflow scalar..."); - - const size_t start_offset = m_evt_handler->m_curr->pos.offset; - bool needs_filter = false; - while(true) - { - _c4dbgpf("scanning scalar: curr line=[{}]~~~{}~~~", s.len, s); - for(size_t i = 0; i < s.len; ++i) - { - const char c = s.str[i]; - switch(c) - { - case ',': - _c4dbgpf("found terminating character at {}: '{}'", i, c); - _line_progressed(i); - if(m_evt_handler->m_curr->pos.offset + i > start_offset) - { - goto ended_scalar; - } - else - { - _c4dbgp("at the beginning. no scalar here."); - return false; - } - break; - case ']': - _c4dbgpf("found terminating character at {}: '{}'", i, c); - _line_progressed(i); - goto ended_scalar; - break; - case '#': - _c4dbgp("found suspicious '#'"); - if(!i || (s.str[i-1] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[i-1] == '\t'))) - { - _c4dbgpf("found terminating character at {}: '{}'", i, c); - _line_progressed(i); - goto ended_scalar; - } - break; - case ':': - _c4dbgp("found suspicious ':'"); - if(s.len > i+1) - { - const char next = s.str[i+1]; - _c4dbgpf("next char is '{}'", _c4prc(next)); - if(next == ' ' || next == ',' _RYML_WITH_TAB_TOKENS(|| next == '\t')) - { - _c4dbgp("map starting!"); - if(m_evt_handler->m_curr->pos.offset + i > start_offset) - { - _c4dbgp("scalar finished!"); - _line_progressed(i); - goto ended_scalar; - } - else - { - _c4dbgp("at the beginning. no scalar here."); - return false; - } - } - else - { - _c4dbgp("it's a scalar indeed."); - ++i; // skip the next char - } - } - else if(s.len == i+1) - { - _c4dbgp("':' at line end. map starting!"); - return false; - } - break; - case '[': - case '{': - case '}': - _line_progressed(i); - _c4err_("invalid character: '{}'", c); // noreturn - default: - ; - } - } - _line_progressed(s.len); - if(!_finished_file()) - { - _c4dbgp("next line!"); - _line_ended(); - _scan_line(); - } - else - { - _c4dbgp("file finished!"); - goto ended_scalar; - } - s = m_evt_handler->m_curr->line_contents.rem; - needs_filter = true; - } - -ended_scalar: - - sc->scalar = m_buf.range(start_offset, m_evt_handler->m_curr->pos.offset).trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \t", ' ')); - sc->needs_filter = needs_filter; - - _c4prscalar("scanned plain scalar", sc->scalar, /*keep_newlines*/true); - - return true; -} - -template -bool ParseEngine::_scan_scalar_plain_map_flow(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RSEQ) || has_any(RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RMAP|RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RVAL|QMRK)); - - substr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with(' ')); - - if(!s.len) - return false; - - if(!_is_valid_start_scalar_plain_flow(s)) - return false; - - _c4dbgp("scanning scalar..."); - - const size_t start_offset = m_evt_handler->m_curr->pos.offset; - bool needs_filter = false; - while(true) - { - for(size_t i = 0; i < s.len; ++i) - { - const char c = s.str[i]; - switch(c) - { - case ',': - case '}': - _line_progressed(i); - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - case ':': - if(s.len == i+1 || s.str[i+1] == ' ' || s.str[i+1] == ',' || s.str[i+1] == '}' _RYML_WITH_TAB_TOKENS(|| s.str[i+1] == '\t')) - { - _line_progressed(i); - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - } - break; - case '{': - case '[': - _line_progressed(i); - _c4err_("invalid character: '{}'", c); // noreturn - break; - case ']': - _line_progressed(i); - if(has_any(RSEQIMAP)) - goto ended_scalar; - else - _c4err_("invalid character: '{}'", c); // noreturn - break; - case '#': - if(!i || s.str[i-1] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[i-1] == '\t')) - { - _line_progressed(i); - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - } - break; - default: - ; - } - } - _c4dbgp("next line!"); - _line_progressed(s.len); - if(!_finished_file()) - { - _c4dbgp("next line!"); - _line_ended(); - _scan_line(); - } - else - { - _c4dbgp("file finished!"); - goto ended_scalar; - } - s = m_evt_handler->m_curr->line_contents.rem; - needs_filter = true; - } - -ended_scalar: - - sc->scalar = m_buf.range(start_offset, m_evt_handler->m_curr->pos.offset).trimr(_RYML_WITH_OR_WITHOUT_TAB_TOKENS(" \n\t\r", " \n\r")); - sc->needs_filter = needs_filter; - - _c4dbgpf("scalar was [{}]~~~{}~~~", sc->scalar.len, sc->scalar); - - return sc->scalar.len > 0u; -} - -template -bool ParseEngine::_scan_scalar_seq_json(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(FLOW)); - - substr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with(' ')); - - if(!s.len) - return false; - - _c4dbgp("scanning scalar..."); - - switch(s.str[0]) - { - case ']': - case '{': - case ',': - _c4dbgp("not a scalar."); - return false; - } - - { - const size_t len = _is_special_json_scalar(s); - if(len) - { - sc->scalar = s.first(len); - sc->needs_filter = false; - _c4dbgpf("special json scalar: '{}'", sc->scalar); - _line_progressed(len); - return true; - } - } - - // must be a number - size_t i = 0; - for( ; i < s.len; ++i) - { - const char c = s.str[i]; - switch(c) - { - case ',': - case ']': - case ' ': - case '\t': - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - case '#': - if(!i || s.str[i-1] == ' ') - { - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - } - break; - default: - ; - } - } - -ended_scalar: - - if(C4_LIKELY(i > 0)) - { - _line_progressed(i); - sc->scalar = s.first(i); - sc->needs_filter = false; - _c4dbgpf("scalar was [{}]~~~{}~~~", sc->scalar.len, sc->scalar); - return true; - } - - return false; -} - -template -bool ParseEngine::_scan_scalar_map_json(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RVAL)); - - substr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with(' ')); - - if(!s.len) - return false; - - _c4dbgp("scanning scalar..."); - - { - const size_t len = _is_special_json_scalar(s); - if(len) - { - sc->scalar = s.first(len); - sc->needs_filter = false; - _c4dbgpf("special json scalar: '{}'", sc->scalar); - _line_progressed(len); - return true; - } - } - - // must be a number - size_t i = 0; - for( ; i < s.len; ++i) - { - const char c = s.str[i]; - switch(c) - { - case ',': - case '}': - case ' ': - case '\t': - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - case '#': - if(!i || s.str[i-1] == ' ') - { - _c4dbgpf("found terminating character: '{}'", c); - goto ended_scalar; - } - break; - default: - ; - } - } - -ended_scalar: - - if(C4_LIKELY(i > 0)) - { - _line_progressed(i); - sc->scalar = s.first(i); - sc->needs_filter = false; - _c4dbgpf("scalar was [{}]~~~{}~~~", sc->scalar.len, sc->scalar); - return true; - } - - return false; -} - -template -bool ParseEngine::_is_doc_begin(csubstr s) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s[0] == '-'); - return (m_evt_handler->m_curr->line_contents.indentation == 0u && _at_line_begin() && _is_doc_begin_token(s)); -} - -template -bool ParseEngine::_is_doc_end(csubstr s) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s[0] == '.'); - return (m_evt_handler->m_curr->line_contents.indentation == 0u && _at_line_begin() && _is_doc_end_token(s)); -} - -template -bool ParseEngine::_scan_scalar_plain_blck(ScannedScalar *C4_RESTRICT sc, size_t indentation) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(BLCK|RUNK|USTY)); - - substr s = m_evt_handler->m_curr->line_contents.rem; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !s.begins_with(' ')); - - if(!s.len) - return false; - - switch(s.str[0]) - { - case '-': - if(_is_blck_token(s)) - { - return false; - } - else if(_is_doc_begin(s)) - { - _c4dbgp("token is doc start"); - return false; - } - break; - case ':': - case '?': - if(_is_blck_token(s)) - return false; - break; - case '[': - case '{': - case '&': - case '*': - case '!': - _RYML_WITH_TAB_TOKENS(case '\t':) - return false; - case '.': - if(_is_doc_end(s)) - { - _c4dbgp("token is doc end"); - return false; - } - break; - } - - _c4dbgpf("plain scalar! indentation={}", indentation); - - const size_t start_offset = m_evt_handler->m_curr->pos.offset; - const size_t start_line = m_evt_handler->m_curr->pos.line; - - bool needs_filter = false; - while(true) - { - _c4dbgpf("plain scalar line: [{}]~~~{}~~~", s.len, s); - for(size_t i = 0; i < s.len; ++i) - { - const char curr = s.str[i]; - //_c4dbgpf("[{}]='{}'", i, _c4prc(curr)); - switch(curr) - { - case ':': - _c4dbgpf("[{}]: got suspicious ':'", i); - // are there more characters? - if((i + 1 == s.len) || ((s.str[i+1] == ' ') _RYML_WITH_TAB_TOKENS( || (s.str[i+1] == '\t')))) - { - _c4dbgpf("followed by '{}'", i+1 == s.len ? csubstr("\\n") : _c4prc(s.str[i+1])); - _line_progressed(i); - // ': ' is accepted only on the first line - if(C4_LIKELY(m_evt_handler->m_curr->pos.line == start_line)) - { - _c4dbgp("start line. scalar ends here"); - goto ended_scalar; - } - else - { - _c4err("parse error"); - } - } - else - { - size_t j = i; - while(j + 1 < s.len && s.str[j+1] == ':') - { - _c4dbgp("skip colon"); - ++j; - } - i = j > i ? j-1 : i; - _c4dbgp("nothing to see here"); - } - break; - case '#': - _c4dbgp("got suspicious '#'"); - if(!i || (s.str[i-1] == ' ' || s.str[i-1] == '\t')) - { - _c4dbgp("comment! scalar ends here"); - _line_progressed(i); - goto ended_scalar; - } - else - { - _c4dbgp("nothing to see here"); - } - break; - } - } - _line_progressed(s.len); - csubstr next_peeked = _peek_next_line(m_evt_handler->m_curr->pos.offset); - next_peeked = next_peeked.trimr("\n\r"); - const size_t next_indentation = next_peeked.first_not_of(' '); - _c4dbgpf("indentation curr={} next={}", indentation, next_indentation); - if(next_indentation < indentation) - { - _c4dbgp("smaller indentation! scalar ended"); - goto ended_scalar; - } - else if(next_indentation == 0 && next_peeked.len > 0) - { - const char first = next_peeked.str[0]; - switch(first) - { - case '-': - next_peeked = next_peeked.trimr("\n\r"); - _c4dbgpf("doc begin? peeked=[{}]~~~{}{}~~~", next_peeked.len, next_peeked.len >= 3 ? next_peeked.first(3) : next_peeked, next_peeked.len > 3 ? "..." : ""); - if(_is_doc_begin_token(next_peeked)) - { - _c4dbgp("doc begin! scalar ended"); - goto ended_scalar; - } - break; - case '.': - next_peeked = next_peeked.trimr("\n\r"); - _c4dbgpf("doc end? peeked=[{}]~~~{}{}~~~", next_peeked.len, next_peeked.len >= 3 ? next_peeked.first(3) : next_peeked, next_peeked.len > 3 ? "..." : ""); - if(_is_doc_end_token(next_peeked)) - { - _c4dbgp("doc end! scalar ended"); - goto ended_scalar; - } - break; - } - } - // load with next line - _c4dbgp("next line!"); - if(!_finished_file()) - { - _c4dbgp("next line!"); - _line_ended(); - _scan_line(); - } - else - { - _c4dbgp("file finished!"); - goto ended_scalar; - } - s = m_evt_handler->m_curr->line_contents.rem; - needs_filter = true; - } - -ended_scalar: - - sc->scalar = m_buf.range(start_offset, m_evt_handler->m_curr->pos.offset).trimr(" \n\r\t"); - sc->needs_filter = needs_filter; - - _c4dbgpf("scalar was [{}]~~~{}~~~", sc->scalar.len, sc->scalar); - - return true; -} - -template -bool ParseEngine::_scan_scalar_plain_seq_blck(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL)); - return _scan_scalar_plain_blck(sc, m_evt_handler->m_curr->indref + 1u); -} - -template -bool ParseEngine::_scan_scalar_plain_map_blck(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RVAL|QMRK)); - return _scan_scalar_plain_blck(sc, m_evt_handler->m_curr->indref + 1u); -} - -template -bool ParseEngine::_scan_scalar_plain_unk(ScannedScalar *C4_RESTRICT sc) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RUNK|USTY)); - return _scan_scalar_plain_blck(sc, m_evt_handler->m_curr->indref); -} - - -//----------------------------------------------------------------------------- - -template -substr ParseEngine::_peek_next_line(size_t pos) const -{ - substr rem{}; // declare here because of the goto - size_t nlpos{}; // declare here because of the goto - pos = pos == npos ? m_evt_handler->m_curr->pos.offset : pos; - if(pos >= m_buf.len) - goto next_is_empty; - - // look for the next newline chars, and jump to the right of those - rem = from_next_line(m_buf.sub(pos)); - if(rem.empty()) - goto next_is_empty; - - // now get everything up to and including the following newline chars - nlpos = rem.first_of("\r\n"); - if((nlpos != csubstr::npos) && (nlpos + 1 < rem.len)) - nlpos += _extend_from_combined_newline(rem[nlpos], rem[nlpos+1]); - rem = rem.left_of(nlpos, /*include_pos*/true); - - _c4dbgpf("peek next line @ {}: (len={})'{}'", pos, rem.len, rem.trimr("\r\n")); - return rem; - -next_is_empty: - _c4dbgpf("peek next line @ {}: (len=0)''", pos); - return {}; -} - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_scan_line() -{ - if(C4_LIKELY(m_evt_handler->m_curr->pos.offset < m_buf.len)) - m_evt_handler->m_curr->line_contents.reset_with_next_line(m_buf, m_evt_handler->m_curr->pos.offset); - else - m_evt_handler->m_curr->line_contents.reset(m_buf.last(0), m_buf.last(0)); -} - -template -void ParseEngine::_line_progressed(size_t ahead) -{ - _c4dbgpf("line[{}] ({} cols) progressed by {}: col {}-->{} offset {}-->{}", m_evt_handler->m_curr->pos.line, m_evt_handler->m_curr->line_contents.full.len, ahead, m_evt_handler->m_curr->pos.col, m_evt_handler->m_curr->pos.col+ahead, m_evt_handler->m_curr->pos.offset, m_evt_handler->m_curr->pos.offset+ahead); - m_evt_handler->m_curr->pos.offset += ahead; - m_evt_handler->m_curr->pos.col += ahead; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.col <= m_evt_handler->m_curr->line_contents.stripped.len+1); - m_evt_handler->m_curr->line_contents.rem = m_evt_handler->m_curr->line_contents.rem.sub(ahead); -} - -template -void ParseEngine::_line_ended() -{ - _c4dbgpf("line[{}] ({} cols) ended! offset {}-->{} / col {}-->{}", - m_evt_handler->m_curr->pos.line, - m_evt_handler->m_curr->line_contents.full.len, - m_evt_handler->m_curr->pos.offset, m_evt_handler->m_curr->pos.offset + m_evt_handler->m_curr->line_contents.full.len - m_evt_handler->m_curr->line_contents.stripped.len, - m_evt_handler->m_curr->pos.col, 1); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.col == m_evt_handler->m_curr->line_contents.stripped.len + 1); - m_evt_handler->m_curr->pos.offset += m_evt_handler->m_curr->line_contents.full.len - m_evt_handler->m_curr->line_contents.stripped.len; - ++m_evt_handler->m_curr->pos.line; - m_evt_handler->m_curr->pos.col = 1; -} - -template -void ParseEngine::_line_ended_undo() -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.col == 1u); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.line > 0u); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.offset >= m_evt_handler->m_curr->line_contents.full.len - m_evt_handler->m_curr->line_contents.stripped.len); - const size_t delta = m_evt_handler->m_curr->line_contents.full.len - m_evt_handler->m_curr->line_contents.stripped.len; - _c4dbgpf("line[{}] undo ended! line {}-->{}, offset {}-->{}", m_evt_handler->m_curr->pos.line, m_evt_handler->m_curr->pos.line, m_evt_handler->m_curr->pos.line - 1, m_evt_handler->m_curr->pos.offset, m_evt_handler->m_curr->pos.offset - delta); - m_evt_handler->m_curr->pos.offset -= delta; - --m_evt_handler->m_curr->pos.line; - m_evt_handler->m_curr->pos.col = m_evt_handler->m_curr->line_contents.stripped.len + 1u; - // don't forget to undo also the changes to the remainder of the line - //_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.offset >= m_buf.len || m_buf[m_evt_handler->m_curr->pos.offset] == '\n' || m_buf[m_evt_handler->m_curr->pos.offset] == '\r'); - m_evt_handler->m_curr->line_contents.rem = m_buf.sub(m_evt_handler->m_curr->pos.offset, 0); -} - - -//----------------------------------------------------------------------------- -template -void ParseEngine::_set_indentation(size_t indentation) -{ - m_evt_handler->m_curr->indref = indentation; - _c4dbgpf("state[{}]: saving indentation: {}", m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); -} - -template -void ParseEngine::_save_indentation() -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.begin() >= m_evt_handler->m_curr->line_contents.full.begin()); - m_evt_handler->m_curr->indref = m_evt_handler->m_curr->line_contents.current_col(); - _c4dbgpf("state[{}]: saving indentation: {}", m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_end_map_blck() -{ - _c4dbgp("mapblck: end"); - if(has_any(RKCL|RVAL)) - { - _c4dbgp("mapblck: set missing val"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - } - else if(has_any(QMRK)) - { - _c4dbgp("mapblck: set missing keyval"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_plain_empty(); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - } - m_evt_handler->end_map(); -} - -template -void ParseEngine::_end_seq_blck() -{ - if(has_any(RVAL)) - { - _c4dbgp("seqblck: set missing val"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - } - m_evt_handler->end_seq(); -} - -template -void ParseEngine::_end2_map() -{ - _c4dbgp("map: end"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RMAP)); - if(has_any(BLCK)) - { - _end_map_blck(); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(USTY)); - m_evt_handler->_pop(); - } -} - -template -void ParseEngine::_end2_seq() -{ - _c4dbgp("seq: end"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RSEQ)); - if(has_any(BLCK)) - { - _end_seq_blck(); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(USTY)); - m_evt_handler->_pop(); - } -} - -template -void ParseEngine::_begin2_doc() -{ - m_doc_empty = true; - add_flags(RDOC); - m_evt_handler->begin_doc(); - m_evt_handler->m_curr->indref = 0; // ? -} - -template -void ParseEngine::_begin2_doc_expl() -{ - m_doc_empty = true; - add_flags(RDOC); - m_evt_handler->begin_doc_expl(); - m_evt_handler->m_curr->indref = 0; // ? -} - -template -void ParseEngine::_end2_doc() -{ - _c4dbgp("doc: end"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RDOC)); - if(m_doc_empty || (m_pending_tags.num_entries || m_pending_anchors.num_entries)) - { - _c4dbgp("doc was empty; add empty val"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - } - m_evt_handler->end_doc(); -} - -template -void ParseEngine::_end2_doc_expl() -{ - _c4dbgp("doc: end"); - if(m_doc_empty || (m_pending_tags.num_entries || m_pending_anchors.num_entries)) - { - _c4dbgp("doc: no children; add empty val"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - } - m_evt_handler->end_doc_expl(); -} - -template -void ParseEngine::_maybe_begin_doc() -{ - if(has_none(RDOC)) - { - _c4dbgp("doc must be started"); - _begin2_doc(); - } -} -template -void ParseEngine::_maybe_end_doc() -{ - if(has_any(RDOC)) - { - _c4dbgp("doc must be finished"); - _end2_doc(); - } - else if(m_doc_empty && (m_pending_tags.num_entries || m_pending_anchors.num_entries)) - { - _c4dbgp("no doc to finish, but pending annotations"); - m_evt_handler->begin_doc(); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_doc(); - } -} - -template -void ParseEngine::_end_doc_suddenly__pop() -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_stack.size() >= 1); - if(m_evt_handler->m_stack[0].flags & RDOC) - { - _c4dbgp("root is RDOC"); - if(m_evt_handler->m_curr->level != 0) - _handle_indentation_pop(&m_evt_handler->m_stack[0]); - } - else if((m_evt_handler->m_stack.size() > 1) && (m_evt_handler->m_stack[1].flags & RDOC)) - { - _c4dbgp("root is STREAM"); - if(m_evt_handler->m_curr->level != 1) - _handle_indentation_pop(&m_evt_handler->m_stack[1]); - } - else - { - _c4err("internal error"); - } - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RDOC)); -} - -template -void ParseEngine::_end_doc_suddenly() -{ - _c4dbgp("end doc suddenly"); - _end_doc_suddenly__pop(); - _end2_doc_expl(); - addrem_flags(RUNK|RTOP|NDOC, RMAP|RSEQ|RDOC); -} - -template -void ParseEngine::_start_doc_suddenly() -{ - _c4dbgp("start doc suddenly"); - _end_doc_suddenly__pop(); - _end2_doc(); - _begin2_doc_expl(); -} - -template -void ParseEngine::_end_stream() -{ - _c4dbgpf("end_stream, level={} node_id={}", m_evt_handler->m_curr->level, m_evt_handler->m_curr->node_id); - if(has_all(RSEQ|FLOW)) - _c4err("missing terminating ]"); - else if(has_all(RMAP|FLOW)) - _c4err("missing terminating }"); - if(m_evt_handler->m_stack.size() > 1) - _handle_indentation_pop(m_evt_handler->m_stack.begin()); - if(has_all(RDOC)) - { - _end2_doc(); - } - else if(has_all(RTOP|RUNK)) - { - if(m_pending_anchors.num_entries || m_pending_tags.num_entries) - { - if(m_doc_empty) - { - m_evt_handler->begin_doc(); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_doc(); - } - } - } - m_evt_handler->end_stream(); -} - - -template -void ParseEngine::_handle_indentation_pop(ParserState const* popto) -{ - _c4dbgpf("popping {} level{}: from level {}(@ind={}) to level {}(@ind={})", m_evt_handler->m_curr->level - popto->level, (((m_evt_handler->m_curr->level - popto->level) > 1) ? "s" : ""), m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref, popto->level, popto->indref); - while(m_evt_handler->m_curr != popto) - { - if(has_any(RSEQ)) - { - _c4dbgpf("popping seq at level {} (indentation={},addr={})", m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref, m_evt_handler->m_curr); - _end2_seq(); - } - else if(has_any(RMAP)) - { - _c4dbgpf("popping map at level {} (indentation={},addr={})", m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref, m_evt_handler->m_curr); - _end2_map(); - } - else - { - break; - } - } - _c4dbgpf("current level is {} (indentation={})", m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); -} - -template -void ParseEngine::_handle_indentation_pop_from_block_seq() -{ - // search the stack frame to jump to based on its indentation - using state_type = typename EventHandler::state; - state_type const* popto = nullptr; - auto &stack = m_evt_handler->m_stack; - _RYML_CB_ASSERT(stack.m_callbacks, stack.is_contiguous()); // this search relies on the stack being contiguous - _RYML_CB_ASSERT(stack.m_callbacks, m_evt_handler->m_curr >= stack.begin() && m_evt_handler->m_curr < stack.end()); - const size_t ind = m_evt_handler->m_curr->line_contents.indentation; - #ifdef RYML_DBG - if(_dbg_enabled()) - { - char flagbuf_[128]; - for(state_type const& s : stack) - _dbg_printf("state[{}]: ind={} node={} flags={}\n", s.level, s.indref, s.node_id, detail::_parser_flags_to_str(flagbuf_, s.flags)); - } - #endif - for(state_type const* s = m_evt_handler->m_curr-1; s >= stack.begin(); --s) - { - _c4dbgpf("searching for state with indentation {}. curr={} (level={},node={})", ind, s->indref, s->level, s->node_id); - if(s->indref == ind) - { - _c4dbgpf("gotit!!! level={} node={}", s->level, s->node_id); - popto = s; - break; - } - } - if(!popto || popto >= m_evt_handler->m_curr || popto->level >= m_evt_handler->m_curr->level) - { - _c4err("parse error: incorrect indentation?"); - } - _handle_indentation_pop(popto); -} - -template -void ParseEngine::_handle_indentation_pop_from_block_map() -{ - // search the stack frame to jump to based on its indentation - using state_type = typename EventHandler::state; - auto &stack = m_evt_handler->m_stack; - _RYML_CB_ASSERT(stack.m_callbacks, stack.is_contiguous()); // this search relies on the stack being contiguous - _RYML_CB_ASSERT(stack.m_callbacks, m_evt_handler->m_curr >= stack.begin() && m_evt_handler->m_curr < stack.end()); - const size_t ind = m_evt_handler->m_curr->line_contents.indentation; - state_type const* popto = nullptr; - #ifdef RYML_DBG - char flagbuf_[128]; - if(_dbg_enabled()) - { - for(state_type const& s : stack) - _dbg_printf("state[{}]: ind={} node={} flags={}\n", s.level, s.indref, s.node_id, detail::_parser_flags_to_str(flagbuf_, s.flags)); - } - #endif - for(state_type const* s = m_evt_handler->m_curr-1; s > stack.begin(); --s) // never go to the stack bottom. that's the root - { - _c4dbgpf("searching for state with indentation {}. current: ind={},level={},node={},flags={}", ind, s->indref, s->level, s->node_id, detail::_parser_flags_to_str(flagbuf_, s->flags)); - if(s->indref < ind) - { - break; - } - else if(s->indref == ind) - { - _c4dbgpf("same indentation!!! level={} node={}", s->level, s->node_id); - if(popto && has_any(RTOP, s) && has_none(RMAP|RSEQ, s)) - { - break; - } - popto = s; - if(has_all(RSEQ|BLCK, s)) - { - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - const size_t first = rem.first_not_of(' '); - _RYML_CB_ASSERT(stack.m_callbacks, first == ind || first == npos); - rem = rem.right_of(first, true); - _c4dbgpf("indentless? rem='{}' first={}", rem, first); - if(rem.begins_with('-') && _is_blck_token(rem)) - { - _c4dbgp("parent was indentless seq"); - break; - } - } - } - } - if(!popto || popto >= m_evt_handler->m_curr || popto->level >= m_evt_handler->m_curr->level) - { - _c4err("parse error: incorrect indentation?"); - } - _handle_indentation_pop(popto); -} - - -//----------------------------------------------------------------------------- -template -typename ParseEngine::ScannedScalar ParseEngine::_scan_scalar_squot() -{ - // quoted scalars can spread over multiple lines! - // nice explanation here: http://yaml-multiline.info/ - - // a span to the end of the file - size_t b = m_evt_handler->m_curr->pos.offset; - substr s = m_buf.sub(b); - if(s.begins_with(' ')) - { - s = s.triml(' '); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.sub(b).is_super(s)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begin() >= m_buf.sub(b).begin()); - _line_progressed((size_t)(s.begin() - m_buf.sub(b).begin())); - } - b = m_evt_handler->m_curr->pos.offset; // take this into account - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('\'')); - - // skip the opening quote - _line_progressed(1); - s = s.sub(1); - - bool needs_filter = false; - - size_t numlines = 1; // we already have one line - size_t pos = npos; // find the pos of the matching quote - while( ! _finished_file()) - { - const csubstr line = m_evt_handler->m_curr->line_contents.rem; - bool line_is_blank = true; - _c4dbgpf("scanning single quoted scalar @ line[{}]: ~~~{}~~~", m_evt_handler->m_curr->pos.line, line); - for(size_t i = 0; i < line.len; ++i) - { - const char curr = line.str[i]; - if(curr == '\'') // single quotes are escaped with two single quotes - { - const char next = i+1 < line.len ? line.str[i+1] : '~'; - if(next != '\'') // so just look for the first quote - { // without another after it - pos = i; - break; - } - else - { - needs_filter = true; // needs filter to remove escaped quotes - ++i; // skip the escaped quote - } - } - else if(curr != ' ') - { - line_is_blank = false; - } - } - - // leading whitespace also needs filtering - needs_filter = needs_filter - || (numlines > 1) - || line_is_blank - || (_at_line_begin() && line.begins_with(' ')); - - if(pos == npos) - { - _line_progressed(line.len); - ++numlines; - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, pos >= 0 && pos < m_buf.len); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf[m_evt_handler->m_curr->pos.offset + pos] == '\''); - _line_progressed(pos + 1); // progress beyond the quote - pos = m_evt_handler->m_curr->pos.offset - b - 1; // but we stop before it - break; - } - - _line_ended(); - _scan_line(); - } - - if(pos == npos) - { - _c4err("reached end of file while looking for closing quote"); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, pos > 0); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.end() >= m_buf.begin() && s.end() <= m_buf.end()); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.end() == m_buf.end() || *s.end() == '\''); - s = s.sub(0, pos-1); - } - - _c4prscalar("scanned squoted scalar", s, /*keep_newlines*/true); - - return ScannedScalar { s, needs_filter }; -} - - -//----------------------------------------------------------------------------- -template -typename ParseEngine::ScannedScalar ParseEngine::_scan_scalar_dquot() -{ - // quoted scalars can spread over multiple lines! - // nice explanation here: http://yaml-multiline.info/ - - // a span to the end of the file - size_t b = m_evt_handler->m_curr->pos.offset; - substr s = m_buf.sub(b); - if(s.begins_with(' ')) - { - s = s.triml(' '); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.sub(b).is_super(s)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begin() >= m_buf.sub(b).begin()); - _line_progressed((size_t)(s.begin() - m_buf.sub(b).begin())); - } - b = m_evt_handler->m_curr->pos.offset; // take this into account - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('"')); - - // skip the opening quote - _line_progressed(1); - s = s.sub(1); - - bool needs_filter = false; - - size_t numlines = 1; // we already have one line - size_t pos = npos; // find the pos of the matching quote - while( ! _finished_file()) - { - const csubstr line = m_evt_handler->m_curr->line_contents.rem; - #if defined(__GNUC__) && __GNUC__ == 11 - C4_DONT_OPTIMIZE(line); // prevent erroneous hoist of the assignment out of the loop - #endif - bool line_is_blank = true; - _c4dbgpf("scanning double quoted scalar @ line[{}]: line='{}'", m_evt_handler->m_curr->pos.line, line); - for(size_t i = 0; i < line.len; ++i) - { - const char curr = line.str[i]; - if(curr != ' ') - line_is_blank = false; - // every \ is an escape - if(curr == '\\') - { - const char next = i+1 < line.len ? line.str[i+1] : '~'; - needs_filter = true; - if(next == '"' || next == '\\') - ++i; - } - else if(curr == '"') - { - pos = i; - break; - } - } - - // leading whitespace also needs filtering - needs_filter = needs_filter - || (numlines > 1) - || line_is_blank - || (_at_line_begin() && line.begins_with(' ')); - - if(pos == npos) - { - _line_progressed(line.len); - ++numlines; - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, pos >= 0 && pos < m_buf.len); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf[m_evt_handler->m_curr->pos.offset + pos] == '"'); - _line_progressed(pos + 1); // progress beyond the quote - pos = m_evt_handler->m_curr->pos.offset - b - 1; // but we stop before it - break; - } - - _line_ended(); - _scan_line(); - } - - if(pos == npos) - { - _c4err("reached end of file looking for closing quote"); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, pos > 0); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.end() == m_buf.end() || *s.end() == '"'); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.end() >= m_buf.begin() && s.end() <= m_buf.end()); - s = s.sub(0, pos-1); - } - - _c4prscalar("scanned dquoted scalar", s, /*keep_newlines*/true); - - return ScannedScalar { s, needs_filter }; -} - - -//----------------------------------------------------------------------------- -template -void ParseEngine::_scan_block(ScannedBlock *C4_RESTRICT sb, size_t indref) -{ - _c4dbgpf("blck: indref={}", indref); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, indref != npos); - - // nice explanation here: http://yaml-multiline.info/ - csubstr s = m_evt_handler->m_curr->line_contents.rem; - csubstr trimmed = s.triml(' '); - if(trimmed.str > s.str) - { - _c4dbgp("skipping whitespace"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, trimmed.str >= s.str); - _line_progressed(static_cast(trimmed.str - s.str)); - s = trimmed; - } - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with('|') || s.begins_with('>')); - - _c4dbgpf("blck: specs=[{}]~~~{}~~~", s.len, s); - - // parse the spec - BlockChomp_e chomp = CHOMP_CLIP; // default to clip unless + or - are used - size_t indentation = npos; // have to find out if no spec is given - csubstr digits; - if(s.len > 1) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.begins_with_any("|>")); - csubstr t = s.sub(1); - _c4dbgpf("blck: spec is multichar: '{}'", t); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, t.len >= 1); - size_t pos = t.first_of("-+"); - _c4dbgpf("blck: spec chomp char at {}", pos); - if(pos != npos) - { - if(t[pos] == '-') - chomp = CHOMP_STRIP; - else if(t[pos] == '+') - chomp = CHOMP_KEEP; - if(pos == 0) - t = t.sub(1); - else - t = t.first(pos); - } - // from here to the end, only digits are considered - digits = t.left_of(t.first_not_of("0123456789")); - if( ! digits.empty()) - { - if(C4_UNLIKELY(digits.len > 1)) - _c4err("parse error: invalid indentation"); - _c4dbgpf("blck: parse indentation digits: [{}]~~~{}~~~", digits.len, digits); - if(C4_UNLIKELY( ! c4::atou(digits, &indentation))) - _c4err("parse error: could not read indentation as decimal"); - if(C4_UNLIKELY( ! indentation)) - _c4err("parse error: null indentation"); - _c4dbgpf("blck: indentation specified: {}. add {} from curr state -> {}", indentation, m_evt_handler->m_curr->indref, indentation+indref); - indentation += m_evt_handler->m_curr->indref; - } - } - - _c4dbgpf("blck: style={} chomp={} indentation={}", s.begins_with('>') ? "fold" : "literal", chomp==CHOMP_CLIP ? "clip" : (chomp==CHOMP_STRIP ? "strip" : "keep"), indentation); - - // finish the current line - _line_progressed(s.len); - _line_ended(); - _scan_line(); - - // start with a zero-length block, already pointing at the right place - substr raw_block(m_buf.data() + m_evt_handler->m_curr->pos.offset, size_t(0));// m_evt_handler->m_curr->line_contents.full.sub(0, 0); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, raw_block.begin() == m_evt_handler->m_curr->line_contents.full.begin()); - - // read every full line into a raw block, - // from which newlines are to be stripped as needed. - // - // If no explicit indentation was given, pick it from the first - // non-empty line. See - // https://yaml.org/spec/1.2.2/#8111-block-indentation-indicator - size_t num_lines = 0; - size_t first = m_evt_handler->m_curr->pos.line; - size_t provisional_indentation = npos; - LineContents lc; - while(( ! _finished_file())) - { - // peek next line, but do not advance immediately - lc.reset_with_next_line(m_buf, m_evt_handler->m_curr->pos.offset); - #if defined(__GNUC__) && (__GNUC__ == 12 || __GNUC__ == 13) - C4_DONT_OPTIMIZE(lc.rem); - #endif - _c4dbgpf("blck: peeking at [{}]~~~{}~~~", lc.stripped.len, lc.stripped); - // evaluate termination conditions - if(indentation != npos) - { - _c4dbgpf("blck: indentation={}", indentation); - // stop when the line is deindented and not empty - if(lc.indentation < indentation && ( ! lc.rem.trim(" \t").empty())) - { - if(raw_block.len) - { - _c4dbgpf("blck: indentation decreased ref={} thisline={}", indentation, lc.indentation); - } - else - { - _c4err("indentation decreased without any scalar"); - } - break; - } - else if(indentation == 0) - { - _c4dbgpf("blck: noindent. lc.rem=[{}]~~~{}~~~", lc.rem.len, lc.rem); - if(_is_doc_token(lc.rem)) - { - _c4dbgp("blck: stop. indentation=0 and doc ended"); - break; - } - } - } - else - { - const size_t fns = lc.stripped.first_not_of(' '); - _c4dbgpf("blck: indentation ref not set. firstnonws={}", fns); - if(fns != npos) // non-empty line - { - _RYML_WITH_TAB_TOKENS( - if(C4_UNLIKELY(lc.stripped.begins_with('\t'))) - _c4err("parse error"); - ) - _c4dbgpf("blck: line not empty. indref={} indprov={} indentation={}", indref, provisional_indentation, lc.indentation); - if(provisional_indentation == npos) - { - if(lc.indentation < indref) - { - _c4dbgpf("blck: block terminated indentation={} < indref={}", lc.indentation, indref); - if(raw_block.len == 0) - { - _c4dbgp("blck: was empty, undo next line"); - _line_ended_undo(); - } - break; - } - else if(lc.indentation == m_evt_handler->m_curr->indref) - { - if(has_any(RSEQ|RMAP)) - { - _c4dbgpf("blck: block terminated. reading container and indentation={}==indref={}", lc.indentation, m_evt_handler->m_curr->indref); - break; - } - } - _c4dbgpf("blck: set indentation ref from this line: ref={}", lc.indentation); - indentation = lc.indentation; - } - else - { - if(lc.indentation >= provisional_indentation) - { - _c4dbgpf("blck: set indentation ref from provisional indentation: provisional_ref={}, thisline={}", provisional_indentation, lc.indentation); - //indentation = provisional_indentation ? provisional_indentation : lc.indentation; - indentation = lc.indentation; - } - else - { - break; - //_c4err("parse error: first non-empty block line should have at least the original indentation"); - } - } - } - else // empty line - { - _c4dbgpf("blck: line empty or {} spaces. line_indentation={} prov_indentation={}", lc.stripped.len, lc.indentation, provisional_indentation); - if(provisional_indentation != npos) - { - if(lc.stripped.len >= provisional_indentation) - { - _c4dbgpf("blck: increase provisional_ref {} -> {}", provisional_indentation, lc.stripped.len); - provisional_indentation = lc.stripped.len; - } - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - else if(lc.indentation >= provisional_indentation && lc.indentation != npos) - { - _c4dbgpf("blck: increase provisional_ref {} -> {}", provisional_indentation, lc.indentation); - provisional_indentation = lc.indentation; - } - #endif - } - else - { - provisional_indentation = lc.indentation ? lc.indentation : has_any(RSEQ|RVAL); - _c4dbgpf("blck: initialize provisional_ref={}", provisional_indentation); - if(provisional_indentation == npos) - { - provisional_indentation = lc.stripped.len ? lc.stripped.len : has_any(RSEQ|RVAL); - _c4dbgpf("blck: initialize provisional_ref={}", provisional_indentation); - } - if(provisional_indentation < indref) - { - provisional_indentation = indref; - _c4dbgpf("blck: initialize provisional_ref={}", provisional_indentation); - } - } - } - } - // advance now that we know the folded scalar continues - m_evt_handler->m_curr->line_contents = lc; - _c4dbgpf("blck: append '{}'", m_evt_handler->m_curr->line_contents.rem); - raw_block.len += m_evt_handler->m_curr->line_contents.full.len; - _line_progressed(m_evt_handler->m_curr->line_contents.rem.len); - _line_ended(); - ++num_lines; - } - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->pos.line == (first + num_lines) || (raw_block.len == 0)); - C4_UNUSED(num_lines); - C4_UNUSED(first); - - if(indentation == npos) - { - _c4dbgpf("blck: set indentation from provisional: {}", provisional_indentation); - indentation = provisional_indentation; - } - - if(num_lines) - _line_ended_undo(); - - _c4prscalar("scanned block", raw_block, /*keep_newlines*/true); - - sb->scalar = raw_block; - sb->indentation = indentation; - sb->chomp = chomp; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/** @cond dev */ - -// a debugging scaffold: -#if 0 -#define _c4dbgfws(fmt, ...) _c4dbgpf("filt_ws[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfws(...) -#endif - -template -template -bool ParseEngine::_filter_ws_handle_to_first_non_space(FilterProcessor &proc) -{ - _c4dbgfws("found whitespace '{}'", _c4prc(proc.curr())); - _RYML_CB_ASSERT(this->callbacks(), proc.curr() == ' ' || proc.curr() == '\t'); - - const size_t first_pos = proc.rpos > 0 ? proc.src.first_not_of(" \t", proc.rpos) : proc.src.first_not_of(' ', proc.rpos); - if(first_pos != npos) - { - const char first_char = proc.src[first_pos]; - _c4dbgfws("firstnonws='{}'@{}", _c4prc(first_char), first_pos); - if(first_char == '\n' || first_char == '\r') // skip trailing whitespace - { - _c4dbgfws("whitespace is trailing on line", ""); - proc.skip(first_pos - proc.rpos); - } - else // a legit whitespace - { - proc.copy(); - _c4dbgfws("legit whitespace. sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar()); - } - return true; - } - _c4dbgfws("whitespace is trailing on line", ""); - return false; -} - -template -template -void ParseEngine::_filter_ws_copy_trailing(FilterProcessor &proc) -{ - if(!_filter_ws_handle_to_first_non_space(proc)) - { - _c4dbgfws("... everything else is trailing whitespace - copy {} chars", proc.src.len - proc.rpos); - proc.copy(proc.src.len - proc.rpos); - } -} - -template -template -void ParseEngine::_filter_ws_skip_trailing(FilterProcessor &proc) -{ - if(!_filter_ws_handle_to_first_non_space(proc)) - { - _c4dbgfws("... everything else is trailing whitespace - skip {} chars", proc.src.len - proc.rpos); - proc.skip(proc.src.len - proc.rpos); - } -} - -#undef _c4dbgfws - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/* plain scalars */ - -// a debugging scaffold: -#if 0 -#define _c4dbgfps(fmt, ...) _c4dbgpf("filt_plain[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfps(fmt, ...) -#endif - -template -template -void ParseEngine::_filter_nl_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation) -{ - _RYML_CB_ASSERT(this->callbacks(), proc.curr() == '\n'); - - _c4dbgfps("found newline. sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar()); - size_t ii = proc.rpos; - const size_t numnl_following = _count_following_newlines(proc.src, &ii, indentation); - if(numnl_following) - { - proc.set('\n', numnl_following); - _c4dbgfps("{} consecutive (empty) lines {}. totalws={}", 1+numnl_following, ii < proc.src.len ? "in the middle" : "at the end", proc.rpos-ii); - } - else - { - const size_t ret = proc.src.first_not_of(" \t", proc.rpos+1); - if(ret != npos) - { - proc.set(' '); - _c4dbgfps("single newline. convert to space. ret={}/{}. sofar=[{}]~~~{}~~~", ii, proc.src.len, proc.wpos, proc.sofar()); - } - else - { - _c4dbgfps("last newline, everything else is whitespace. ii={}/{}", ii, proc.src.len); - ii = proc.src.len; - } - } - proc.rpos = ii; -} - -template -template -auto ParseEngine::_filter_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation) -> decltype(proc.result()) -{ - _RYML_CB_ASSERT(this->callbacks(), indentation != npos); - _c4dbgfps("before=[{}]~~~{}~~~", proc.src.len, proc.src); - - while(proc.has_more_chars()) - { - const char curr = proc.curr(); - _c4dbgfps("'{}', sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case ' ': - _RYML_WITH_TAB_TOKENS(case '\t':) - _c4dbgfps("whitespace", curr); - _filter_ws_skip_trailing(proc); - break; - case '\n': - _c4dbgfps("newline", curr); - _filter_nl_plain(proc, /*indentation*/indentation); - break; - case '\r': // skip \r --- https://stackoverflow.com/questions/1885900 - _c4dbgfps("carriage return, ignore", curr); - proc.skip(); - break; - default: - proc.copy(); - break; - } - } - - _c4dbgfps("after[{}]=~~~{}~~~", proc.wpos, proc.sofar()); - - return proc.result(); -} - -#undef _c4dbgfps - - -template -FilterResult ParseEngine::filter_scalar_plain(csubstr scalar, substr dst, size_t indentation) -{ - FilterProcessorSrcDst proc(scalar, dst); - return _filter_plain(proc, indentation); -} - -template -FilterResult ParseEngine::filter_scalar_plain_in_place(substr dst, size_t cap, size_t indentation) -{ - FilterProcessorInplaceEndExtending proc(dst, cap); - return _filter_plain(proc, indentation); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/* single quoted */ - -// a debugging scaffold: -#if 0 -#define _c4dbgfsq(fmt, ...) _c4dbgpf("filt_squo[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfsq(fmt, ...) -#endif - -template -template -void ParseEngine::_filter_nl_squoted(FilterProcessor &C4_RESTRICT proc) -{ - _RYML_CB_ASSERT(this->callbacks(), proc.curr() == '\n'); - - _c4dbgfsq("found newline. sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar()); - size_t ii = proc.rpos; - const size_t numnl_following = _count_following_newlines(proc.src, &ii); - if(numnl_following) - { - proc.set('\n', numnl_following); - _c4dbgfsq("{} consecutive (empty) lines {}. totalws={}", 1+numnl_following, ii < proc.src.len ? "in the middle" : "at the end", proc.rpos-ii); - } - else - { - const size_t ret = proc.src.first_not_of(" \t", proc.rpos+1); - if(ret != npos) - { - proc.set(' '); - _c4dbgfsq("single newline. convert to space. ret={}/{}. sofar=[{}]~~~{}~~~", ii, proc.src.len, proc.wpos, proc.sofar()); - } - else - { - proc.set(' '); - _c4dbgfsq("single newline. convert to space. ii={}/{}. sofar=[{}]~~~{}~~~", ii, proc.src.len, proc.wpos, proc.sofar()); - } - } - proc.rpos = ii; -} - -template -template -auto ParseEngine::_filter_squoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result()) -{ - _c4dbgfsq("before=[{}]~~~{}~~~", proc.src.len, proc.src); - - // from the YAML spec for double-quoted scalars: - // https://yaml.org/spec/1.2-old/spec.html#style/flow/single-quoted - while(proc.has_more_chars()) - { - const char curr = proc.curr(); - _c4dbgfsq("'{}', sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case ' ': - case '\t': - _c4dbgfsq("whitespace", curr); - _filter_ws_copy_trailing(proc); - break; - case '\n': - _c4dbgfsq("newline", curr); - _filter_nl_squoted(proc); - break; - case '\r': // skip \r --- https://stackoverflow.com/questions/1885900 - _c4dbgfsq("skip cr", curr); - proc.skip(); - break; - case '\'': - _c4dbgfsq("squote", curr); - if(proc.next() == '\'') - { - _c4dbgfsq("two consecutive squotes", curr); - proc.skip(); - proc.copy(); - } - else - { - _c4err("filter error"); - } - break; - default: - proc.copy(); - break; - } - } - - _c4dbgfsq(": #filteredchars={} after=~~~[{}]{}~~~", proc.src.len-proc.sofar().len, proc.sofar().len, proc.sofar()); - - return proc.result(); -} - -#undef _c4dbgfsq - -template -FilterResult ParseEngine::filter_scalar_squoted(csubstr scalar, substr dst) -{ - FilterProcessorSrcDst proc(scalar, dst); - return _filter_squoted(proc); -} - -template -FilterResult ParseEngine::filter_scalar_squoted_in_place(substr dst, size_t cap) -{ - FilterProcessorInplaceEndExtending proc(dst, cap); - return _filter_squoted(proc); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/* double quoted */ - -// a debugging scaffold: -#if 0 -#define _c4dbgfdq(fmt, ...) _c4dbgpf("filt_dquo[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfdq(...) -#endif - -template -template -void ParseEngine::_filter_nl_dquoted(FilterProcessor &C4_RESTRICT proc) -{ - _RYML_CB_ASSERT(this->callbacks(), proc.curr() == '\n'); - - _c4dbgfdq("found newline. sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar()); - size_t ii = proc.rpos; - const size_t numnl_following = _count_following_newlines(proc.src, &ii); - if(numnl_following) - { - proc.set('\n', numnl_following); - _c4dbgfdq("{} consecutive (empty) lines {}. totalws={}", 1+numnl_following, ii < proc.src.len ? "in the middle" : "at the end", proc.rpos-ii); - } - else - { - const size_t ret = proc.src.first_not_of(" \t", proc.rpos+1); - if(ret != npos) - { - proc.set(' '); - _c4dbgfdq("single newline. convert to space. ret={}/{}. sofar=[{}]~~~{}~~~", ii, proc.src.len, proc.wpos, proc.sofar()); - } - else - { - proc.set(' '); - _c4dbgfdq("single newline. convert to space. ii={}/{}. sofar=[{}]~~~{}~~~", ii, proc.src.len, proc.wpos, proc.sofar()); - } - if(ii < proc.src.len && proc.src.str[ii] == '\\') - { - _c4dbgfdq("backslash at [{}]", ii); - const char next = ii+1 < proc.src.len ? proc.src.str[ii+1] : '\0'; - if(next == ' ' || next == '\t') - { - _c4dbgfdq("extend skip to backslash", ""); - ++ii; - } - } - } - proc.rpos = ii; -} - -template -template -void ParseEngine::_filter_dquoted_backslash(FilterProcessor &C4_RESTRICT proc) -{ - char next = proc.next(); - _c4dbgfdq("backslash, next='{}'", _c4prc(next)); - if(next == '\r') - { - if(proc.rpos+2 < proc.src.len && proc.src.str[proc.rpos+2] == '\n') - { - proc.skip(); // newline escaped with \ -- skip both (add only one as i is loop-incremented) - next = '\n'; - _c4dbgfdq("[{}]: was \\r\\n, now next='\\n'", proc.rpos); - } - } - - if(next == '\n') - { - size_t ii = proc.rpos + 2; - for( ; ii < proc.src.len; ++ii) - { - // skip leading whitespace - if(proc.src.str[ii] == ' ' || proc.src.str[ii] == '\t') - ; - else - break; - } - proc.skip(ii - proc.rpos); - } - else if(next == '"' || next == '/' || next == ' ' || next == '\t') - { - // escapes for json compatibility - proc.translate_esc(next); - _c4dbgfdq("here, used '{}'", _c4prc(next)); - } - else if(next == '\r') - { - proc.skip(); - } - else if(next == 'n') - { - proc.translate_esc('\n'); - } - else if(next == 'r') - { - proc.translate_esc('\r'); - } - else if(next == 't') - { - proc.translate_esc('\t'); - } - else if(next == '\\') - { - proc.translate_esc('\\'); - } - else if(next == 'x') // 2-digit Unicode escape (\xXX), code point 0x00–0xFF - { - if(C4_UNLIKELY(proc.rpos + 1u + 2u >= proc.src.len)) - _c4err_("\\x requires 2 hex digits. scalar pos={}", proc.rpos); - char readbuf[8]; - csubstr codepoint = proc.src.sub(proc.rpos + 2u, 2u); - _c4dbgfdq("utf8 ~~~{}~~~ rpos={} rem=~~~{}~~~", codepoint, proc.rpos, proc.src.sub(proc.rpos)); - uint32_t codepoint_val = {}; - if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val))) - _c4err_("failed to read \\x codepoint. scalar pos={}", proc.rpos); - const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val); - if(C4_UNLIKELY(numbytes == 0)) - _c4err_("failed to decode code point={}", proc.rpos); - _RYML_CB_ASSERT(callbacks(), numbytes <= 4); - proc.translate_esc_bulk(readbuf, numbytes, /*nread*/3u); - _c4dbgfdq("utf8 after rpos={} rem=~~~{}~~~", proc.rpos, proc.src.sub(proc.rpos)); - } - else if(next == 'u') // 4-digit Unicode escape (\uXXXX), code point 0x0000–0xFFFF - { - if(C4_UNLIKELY(proc.rpos + 1u + 4u >= proc.src.len)) - _c4err_("\\u requires 4 hex digits. scalar pos={}", proc.rpos); - char readbuf[8]; - csubstr codepoint = proc.src.sub(proc.rpos + 2u, 4u); - uint32_t codepoint_val = {}; - if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val))) - _c4err_("failed to parse \\u codepoint. scalar pos={}", proc.rpos); - const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val); - if(C4_UNLIKELY(numbytes == 0)) - _c4err_("failed to decode code point={}", proc.rpos); - _RYML_CB_ASSERT(callbacks(), numbytes <= 4); - proc.translate_esc_bulk(readbuf, numbytes, /*nread*/5u); - } - else if(next == 'U') // 8-digit Unicode escape (\UXXXXXXXX), full 32-bit code point - { - if(C4_UNLIKELY(proc.rpos + 1u + 8u >= proc.src.len)) - _c4err_("\\U requires 8 hex digits. scalar pos={}", proc.rpos); - char readbuf[8]; - csubstr codepoint = proc.src.sub(proc.rpos + 2u, 8u); - uint32_t codepoint_val = {}; - if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val))) - _c4err_("failed to parse \\U codepoint. scalar pos={}", proc.rpos); - const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val); - if(C4_UNLIKELY(numbytes == 0)) - _c4err_("failed to decode code point={}", proc.rpos); - _RYML_CB_ASSERT(callbacks(), numbytes <= 4); - proc.translate_esc_bulk(readbuf, numbytes, /*nread*/9u); - } - // https://yaml.org/spec/1.2.2/#rule-c-ns-esc-char - else if(next == '0') - { - proc.translate_esc('\0'); - } - else if(next == 'b') // backspace - { - proc.translate_esc('\b'); - } - else if(next == 'f') // form feed - { - proc.translate_esc('\f'); - } - else if(next == 'a') // bell character - { - proc.translate_esc('\a'); - } - else if(next == 'v') // vertical tab - { - proc.translate_esc('\v'); - } - else if(next == 'e') // escape character - { - proc.translate_esc('\x1b'); - } - else if(next == '_') // unicode non breaking space \u00a0 - { - // https://www.compart.com/en/unicode/U+00a0 - const char payload[] = { - _RYML_CHCONST(-0x3e, 0xc2), - _RYML_CHCONST(-0x60, 0xa0), - }; - proc.translate_esc_bulk(payload, /*nwrite*/2, /*nread*/1); - } - else if(next == 'N') // unicode next line \u0085 - { - // https://www.compart.com/en/unicode/U+0085 - const char payload[] = { - _RYML_CHCONST(-0x3e, 0xc2), - _RYML_CHCONST(-0x7b, 0x85), - }; - proc.translate_esc_bulk(payload, /*nwrite*/2, /*nread*/1); - } - else if(next == 'L') // unicode line separator \u2028 - { - // https://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192&number=1024&names=-&utf8=0x&unicodeinhtml=hex - const char payload[] = { - _RYML_CHCONST(-0x1e, 0xe2), - _RYML_CHCONST(-0x80, 0x80), - _RYML_CHCONST(-0x58, 0xa8), - }; - proc.translate_esc_extending(payload, /*nwrite*/3, /*nread*/1); - } - else if(next == 'P') // unicode paragraph separator \u2029 - { - // https://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192&number=1024&names=-&utf8=0x&unicodeinhtml=hex - const char payload[] = { - _RYML_CHCONST(-0x1e, 0xe2), - _RYML_CHCONST(-0x80, 0x80), - _RYML_CHCONST(-0x57, 0xa9), - }; - proc.translate_esc_extending(payload, /*nwrite*/3, /*nread*/1); - } - else if(next == '\0') - { - proc.skip(); - } - else - { - _c4err_("unknown character '{}' after '\\' pos={}", _c4prc(next), proc.rpos); - } - _c4dbgfdq("backslash...sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar()); -} - - -template -template -auto ParseEngine::_filter_dquoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result()) -{ - _c4dbgfdq("before=[{}]~~~{}~~~", proc.src.len, proc.src); - // from the YAML spec for double-quoted scalars: - // https://yaml.org/spec/1.2-old/spec.html#style/flow/double-quoted - while(proc.has_more_chars()) - { - const char curr = proc.curr(); - _c4dbgfdq("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case ' ': - case '\t': - { - _c4dbgfdq("whitespace", curr); - _filter_ws_copy_trailing(proc); - break; - } - case '\n': - { - _c4dbgfdq("newline", curr); - _filter_nl_dquoted(proc); - break; - } - case '\r': // skip \r --- https://stackoverflow.com/questions/1885900 - { - _c4dbgfdq("carriage return, ignore", curr); - proc.skip(); - break; - } - case '\\': - { - _filter_dquoted_backslash(proc); - break; - } - default: - { - proc.copy(); - break; - } - } - } - _c4dbgfdq("after[{}]=~~~{}~~~", proc.wpos, proc.sofar()); - return proc.result(); -} - -#undef _c4dbgfdq - - -template -FilterResult ParseEngine::filter_scalar_dquoted(csubstr scalar, substr dst) -{ - FilterProcessorSrcDst proc(scalar, dst); - return _filter_dquoted(proc); -} - -template -FilterResultExtending ParseEngine::filter_scalar_dquoted_in_place(substr dst, size_t cap) -{ - FilterProcessorInplaceMidExtending proc(dst, cap); - return _filter_dquoted(proc); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// block filtering helpers - -C4_NO_INLINE inline size_t _find_last_newline_and_larger_indentation(csubstr s, size_t indentation) noexcept -{ - if(indentation + 1 > s.len) - return npos; - for(size_t i = s.len-indentation-1; i != size_t(-1); --i) - { - if(s.str[i] == '\n') - { - csubstr rem = s.sub(i + 1); - size_t first = rem.first_not_of(' '); - first = (first != npos) ? first : rem.len; - if(first > indentation) - return i; - } - } - return npos; -} - -template -template -void ParseEngine::_filter_chomp(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp, size_t indentation) -{ - _RYML_CB_ASSERT(this->callbacks(), chomp == CHOMP_CLIP || chomp == CHOMP_KEEP || chomp == CHOMP_STRIP); - _RYML_CB_ASSERT(this->callbacks(), proc.rem().first_not_of(" \n\r") == npos); - - // a debugging scaffold: - #if 0 - #define _c4dbgchomp(fmt, ...) _c4dbgpf("chomp[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) - #else - #define _c4dbgchomp(...) - #endif - - // advance to the last line having spaces beyond the indentation - { - size_t last = _find_last_newline_and_larger_indentation(proc.rem(), indentation); - if(last != npos) - { - _c4dbgchomp("found newline and larger indentation. last={}", last); - last = proc.rpos + last + size_t(1) + indentation; // last started at to-be-read. - _RYML_CB_ASSERT(this->callbacks(), last <= proc.src.len); - // remove indentation spaces, copy the rest - while((proc.rpos < last) && proc.has_more_chars()) - { - const char curr = proc.curr(); - _c4dbgchomp("curr='{}'", _c4prc(curr)); - switch(curr) - { - case '\n': - { - _c4dbgchomp("newline! remlen={}", proc.rem().len); - proc.copy(); - // are there spaces after the newline? - csubstr at_next_line = proc.rem(); - if(at_next_line.begins_with(' ')) - { - _c4dbgchomp("next line begins with spaces. indentation={}", indentation); - // there are spaces. - size_t first_non_space = at_next_line.first_not_of(' '); - _c4dbgchomp("first_non_space={}", first_non_space); - if(first_non_space == npos) - { - _c4dbgchomp("{} spaces, to the end", at_next_line.len); - first_non_space = at_next_line.len; - } - if(first_non_space <= indentation) - { - _c4dbgchomp("skip spaces={}<=indentation={}", first_non_space, indentation); - proc.skip(first_non_space); - } - else - { - _c4dbgchomp("skip indentation={}{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfb(...) -#endif - -template -template -void ParseEngine::_filter_block_indentation(FilterProcessor &C4_RESTRICT proc, size_t indentation) -{ - csubstr rem = proc.rem(); // remaining - if(rem.len) - { - size_t first = rem.first_not_of(' '); - if(first != npos) - { - _c4dbgfb("{} spaces follow before next nonws character", first); - if(first < indentation) - { - _c4dbgfb("skip {}<{} spaces from indentation", first, indentation); - proc.skip(first); - } - else - { - _c4dbgfb("skip {} spaces from indentation", indentation); - proc.skip(indentation); - } - } - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - else - { - _c4dbgfb("all spaces to the end: {} spaces", first); - first = rem.len; - if(first) - { - if(first < indentation) - { - _c4dbgfb("skip everything", first); - proc.skip(proc.src.len - proc.rpos); - } - else - { - _c4dbgfb("skip {} spaces from indentation", indentation); - proc.skip(indentation); - } - } - } - #endif - } -} - -template -template -size_t ParseEngine::_handle_all_whitespace(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp) -{ - csubstr contents = proc.src.trimr(" \n\r"); - _c4dbgfb("ws: contents_len={} wslen={}", contents.len, proc.src.len-contents.len); - if(!contents.len) - { - _c4dbgfb("ws: all whitespace: len={}", proc.src.len); - if(chomp == CHOMP_KEEP && proc.src.len) - { - _c4dbgfb("ws: chomp=KEEP all {} newlines", proc.src.count('\n')); - while(proc.has_more_chars()) - { - const char curr = proc.curr(); - if(curr == '\n') - proc.copy(); - else - proc.skip(); - } - if(!proc.wpos) - { - proc.set('\n'); - } - } - } - return contents.len; -} - -template -template -size_t ParseEngine::_extend_to_chomp(FilterProcessor &C4_RESTRICT proc, size_t contents_len) -{ - _c4dbgfb("contents_len={}", contents_len); - - _RYML_CB_ASSERT(this->callbacks(), contents_len > 0u); - - // extend contents to just before the first newline at the end, - // in case it is preceded by spaces - size_t firstnewl = proc.src.first_of('\n', contents_len); - if(firstnewl != npos) - { - contents_len = firstnewl; - _c4dbgfb("contents_len={} <--- firstnewl={}", contents_len, firstnewl); - } - else - { - contents_len = proc.src.len; - _c4dbgfb("contents_len={} <--- src.len={}", contents_len, proc.src.len); - } - - return contents_len; -} - -#undef _c4dbgfb - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -// a debugging scaffold: -#if 0 -#define _c4dbgfbl(fmt, ...) _c4dbgpf("filt_block_lit[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfbl(...) -#endif - -template -template -auto ParseEngine::_filter_block_literal(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result()) -{ - _c4dbgfbl("indentation={} before=[{}]~~~{}~~~", indentation, proc.src.len, proc.src); - - size_t contents_len = _handle_all_whitespace(proc, chomp); - if(!contents_len) - return proc.result(); - - contents_len = _extend_to_chomp(proc, contents_len); - - _c4dbgfbl("to filter=[{}]~~~{}~~~", contents_len, proc.src.first(contents_len)); - - _filter_block_indentation(proc, indentation); - - // now filter the bulk - while(proc.has_more_chars(/*maxpos*/contents_len)) - { - const char curr = proc.curr(); - _c4dbgfbl("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case '\n': - { - _c4dbgfbl("found newline. skip indentation on the next line", curr); - proc.copy(); // copy the newline - _filter_block_indentation(proc, indentation); - break; - } - case '\r': - proc.skip(); - break; - default: - proc.copy(); - break; - } - } - - _c4dbgfbl("before chomp: #tochomp={} sofar=[{}]~~~{}~~~", proc.rem().len, proc.sofar().len, proc.sofar()); - - _filter_chomp(proc, chomp, indentation); - - _c4dbgfbl("final=[{}]~~~{}~~~", proc.sofar().len, proc.sofar()); - - return proc.result(); -} - -#undef _c4dbgfbl - -template -FilterResult ParseEngine::filter_scalar_block_literal(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp) -{ - FilterProcessorSrcDst proc(scalar, dst); - return _filter_block_literal(proc, indentation, chomp); -} - -template -FilterResult ParseEngine::filter_scalar_block_literal_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp) -{ - FilterProcessorInplaceEndExtending proc(scalar, cap); - return _filter_block_literal(proc, indentation, chomp); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -// a debugging scaffold: -#if 0 -#define _c4dbgfbf(fmt, ...) _c4dbgpf("filt_block_folded[{}->{}]: " fmt, proc.rpos, proc.wpos, __VA_ARGS__) -#else -#define _c4dbgfbf(...) -#endif - - -template -template -void ParseEngine::_filter_block_folded_newlines_leading(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len) -{ - _filter_block_indentation(proc, indentation); - while(proc.has_more_chars(len)) - { - const char curr = proc.curr(); - _c4dbgfbf("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case '\n': - _c4dbgfbf("newline.", curr); - proc.copy(); - _filter_block_indentation(proc, indentation); - break; - case '\r': - proc.skip(); - break; - case ' ': - case '\t': - { - size_t first = proc.rem().first_not_of(" \t"); - _c4dbgfbf("space. first={}", first); - if(first == npos) - first = proc.rem().len; - _c4dbgfbf("... indentation increased to {}", first); - _filter_block_folded_indented_block(proc, indentation, len, first); - break; - } - default: - _c4dbgfbf("newl leading: not space, not newline. stop.", 0); - return; - } - } -} - -template -template -size_t ParseEngine::_filter_block_folded_newlines_compress(FilterProcessor &C4_RESTRICT proc, size_t num_newl, size_t wpos_at_first_newl) -{ - switch(num_newl) - { - case 1u: - _c4dbgfbf("... this is the first newline. turn into space. wpos={}", proc.wpos); - wpos_at_first_newl = proc.wpos; - proc.skip(); - proc.set(' '); - break; - case 2u: - _c4dbgfbf("... this is the second newline. prev space (at wpos={}) must be newline", wpos_at_first_newl); - _RYML_CB_ASSERT(this->callbacks(), wpos_at_first_newl != npos); - _RYML_CB_ASSERT(this->callbacks(), proc.sofar()[wpos_at_first_newl] == ' '); - _RYML_CB_ASSERT(this->callbacks(), wpos_at_first_newl + 1u == proc.wpos); - proc.skip(); - proc.set_at(wpos_at_first_newl, '\n'); - _RYML_CB_ASSERT(this->callbacks(), proc.sofar()[wpos_at_first_newl] == '\n'); - break; - default: - _c4dbgfbf("... subsequent newline (num_newl={}). copy", num_newl); - proc.copy(); - break; - } - return wpos_at_first_newl; -} - -template -template -void ParseEngine::_filter_block_folded_newlines(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len) -{ - _RYML_CB_ASSERT(this->callbacks(), proc.curr() == '\n'); - size_t num_newl = 0; - size_t wpos_at_first_newl = npos; - while(proc.has_more_chars(len)) - { - const char curr = proc.curr(); - _c4dbgfbf("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case '\n': - { - _c4dbgfbf("newline. sofar={}", num_newl); - // NOTE: vs2022-32bit-release builds were giving wrong - // results in this block, if it was written as either - // as a switch(num_newl) or its equivalent if-form. - // - // For this reason, we're using a dedicated function - // (**_compress), which seems to work around the issue. - // - // The manifested problem was that somewhere between the - // assignment to curr and this point, proc.wpos (the - // write-position of the processor) jumped to npos, which - // made the write wrap-around! To make things worse, - // enabling prints via _c4dbgpf() and _c4dbgfbf() made the - // problem go away! - // - // The only way to make the problem appear with prints - // enabled was by disabling all prints in this function - // (including in the block which was moved to the compress - // function) and then selectively enabling only some of - // those prints. - // - // This may be due to some bug in the cl-x86 optimizer; or - // it may be triggered by some UB which may be - // inadvertedly present in this function or in the filter - // processor. This is despite our best efforts to weed out - // any such UB problem: neither clang-tidy nor none of the - // sanitizers, or gcc's -fanalyzer pointed to any problems - // in this code. - // - // In the end, moving this block to a separate function - // was the only way to bury the problem. But it may - // resurface again, as The Undead, rising to from the - // grave to haunt us with his terrible presence. - // - // We may have to revisit this. With a stake, and lots of - // garlic. - wpos_at_first_newl = _filter_block_folded_newlines_compress(proc, ++num_newl, wpos_at_first_newl); - _filter_block_indentation(proc, indentation); - break; - } - case ' ': - case '\t': - { - size_t first = proc.rem().first_not_of(" \t"); - _c4dbgfbf("space. first={}", first); - if(first == npos) - first = proc.rem().len; - _c4dbgfbf("... indentation increased to {}", first); - if(num_newl) - { - _c4dbgfbf("... prev space (at wpos={}) must be newline", wpos_at_first_newl); - proc.set_at(wpos_at_first_newl, '\n'); - } - if(num_newl > 1u) - { - _c4dbgfbf("... add missing newline", wpos_at_first_newl); - proc.set('\n'); - } - _filter_block_folded_indented_block(proc, indentation, len, first); - num_newl = 0; - wpos_at_first_newl = npos; - break; - } - case '\r': - proc.skip(); - break; - default: - _c4dbgfbf("not space, not newline. stop.", 0); - return; - } - } -} - - -template -template -void ParseEngine::_filter_block_folded_indented_block(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len, size_t curr_indentation) noexcept -{ - _RYML_CB_ASSERT(this->callbacks(), (proc.rem().first_not_of(" \t") == curr_indentation) || (proc.rem().first_not_of(" \t") == npos)); - if(curr_indentation) - proc.copy(curr_indentation); - while(proc.has_more_chars(len)) - { - const char curr = proc.curr(); - _c4dbgfbf("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case '\n': - { - proc.copy(); - _filter_block_indentation(proc, indentation); - csubstr rem = proc.rem(); - const size_t first = rem.first_not_of(' '); - _c4dbgfbf("newline. firstns={}", first); - if(first == 0) - { - const char c = rem[first]; - _c4dbgfbf("firstns={}='{}'", first, _c4prc(c)); - if(c == '\n' || c == '\r') - { - ; - } - else - { - _c4dbgfbf("done with indented block", first); - goto endloop; - } - } - else if(first != npos) - { - proc.copy(first); - _c4dbgfbf("copy all {} spaces", first); - } - break; - } - break; - case '\r': - proc.skip(); - break; - default: - proc.copy(); - break; - } - } - endloop: - return; -} - - -template -template -auto ParseEngine::_filter_block_folded(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result()) -{ - _c4dbgfbf("indentation={} before=[{}]~~~{}~~~", indentation, proc.src.len, proc.src); - - size_t contents_len = _handle_all_whitespace(proc, chomp); - if(!contents_len) - return proc.result(); - - contents_len = _extend_to_chomp(proc, contents_len); - - _c4dbgfbf("to filter=[{}]~~~{}~~~", contents_len, proc.src.first(contents_len)); - - _filter_block_folded_newlines_leading(proc, indentation, contents_len); - - // now filter the bulk - while(proc.has_more_chars(/*maxpos*/contents_len)) - { - const char curr = proc.curr(); - _c4dbgfbf("'{}' sofar=[{}]~~~{}~~~", _c4prc(curr), proc.wpos, proc.sofar()); - switch(curr) - { - case '\n': - { - _c4dbgfbf("found newline", curr); - _filter_block_folded_newlines(proc, indentation, contents_len); - break; - } - case '\r': - proc.skip(); - break; - default: - proc.copy(); - break; - } - } - - _c4dbgfbf("before chomp: #tochomp={} sofar=[{}]~~~{}~~~", proc.rem().len, proc.sofar().len, proc.sofar()); - - _filter_chomp(proc, chomp, indentation); - - _c4dbgfbf("final=[{}]~~~{}~~~", proc.sofar().len, proc.sofar()); - - return proc.result(); -} - -#undef _c4dbgfbf - -template -FilterResult ParseEngine::filter_scalar_block_folded(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp) -{ - FilterProcessorSrcDst proc(scalar, dst); - return _filter_block_folded(proc, indentation, chomp); -} - -template -FilterResult ParseEngine::filter_scalar_block_folded_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp) -{ - FilterProcessorInplaceEndExtending proc(scalar, cap); - return _filter_block_folded(proc, indentation, chomp); -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_filter_scalar_plain(substr s, size_t indentation) -{ - _c4dbgpf("filtering plain scalar: s=[{}]~~~{}~~~", s.len, s); - FilterResult r = this->filter_scalar_plain_in_place(s, s.len, indentation); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, r.valid()); - _c4dbgpf("filtering plain scalar: success! s=[{}]~~~{}~~~", r.get().len, r.get()); - return r.get(); -} - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_filter_scalar_squot(substr s) -{ - _c4dbgpf("filtering squo scalar: s=[{}]~~~{}~~~", s.len, s); - FilterResult r = this->filter_scalar_squoted_in_place(s, s.len); - _RYML_CB_ASSERT(this->callbacks(), r.valid()); - _c4dbgpf("filtering squo scalar: success! s=[{}]~~~{}~~~", r.get().len, r.get()); - return r.get(); -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_filter_scalar_dquot(substr s) -{ - _c4dbgpf("filtering dquo scalar: s=[{}]~~~{}~~~", s.len, s); - FilterResultExtending r = this->filter_scalar_dquoted_in_place(s, s.len); - if(C4_LIKELY(r.valid())) - { - _c4dbgpf("filtering dquo scalar: success! s=[{}]~~~{}~~~", r.get().len, r.get()); - return r.get(); - } - else - { - const size_t len = r.required_len(); - _c4dbgpf("filtering dquo scalar: not enough space: needs {}, have {}", len, s.len); - substr dst = m_evt_handler->alloc_arena(len, &s); - _c4dbgpf("filtering dquo scalar: dst.len={}", dst.len); - if(dst.str) - { - _RYML_CB_ASSERT(this->callbacks(), dst.len == len); - FilterResult rsd = this->filter_scalar_dquoted(s, dst); - _c4dbgpf("filtering dquo scalar: ... result now needs {} was {}", rsd.required_len(), len); - _RYML_CB_ASSERT(this->callbacks(), rsd.required_len() <= len); // may be smaller! - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, rsd.valid()); - _c4dbgpf("filtering dquo scalar: success! s=[{}]~~~{}~~~", rsd.get().len, rsd.get()); - return rsd.get(); - } - return dst; - } -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_move_scalar_left_and_add_newline(substr s) -{ - if(s.is_sub(m_buf)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.str > m_buf.str); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.str-1 >= m_buf.str); - if(s.len) - memmove(s.str - 1, s.str, s.len); - --s.str; - s.str[s.len] = '\n'; - ++s.len; - return s; - } - else - { - substr dst = m_evt_handler->alloc_arena(s.len + 1); - if(s.len) - memcpy(dst.str, s.str, s.len); - dst[s.len] = '\n'; - return dst; - } -} - -template -csubstr ParseEngine::_filter_scalar_literal(substr s, size_t indentation, BlockChomp_e chomp) -{ - _c4dbgpf("filtering block literal scalar: s=[{}]~~~{}~~~", s.len, s); - FilterResult r = this->filter_scalar_block_literal_in_place(s, s.len, indentation, chomp); - csubstr result; - if(C4_LIKELY(r.valid())) - { - result = r.get(); - } - else - { - _c4dbgpf("filtering block literal scalar: not enough space: needs {}, have {}", r.required_len(), s.len); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, r.required_len() == s.len + 1); - // this can only happen when adding a single newline in clip mode. - // so we shift left the scalar by one place - result = _move_scalar_left_and_add_newline(s); - } - _c4dbgpf("filtering block literal scalar: success! s=[{}]~~~{}~~~", result.len, result); - return result; -} - - -//----------------------------------------------------------------------------- -template -csubstr ParseEngine::_filter_scalar_folded(substr s, size_t indentation, BlockChomp_e chomp) -{ - _c4dbgpf("filtering block folded scalar: s=[{}]~~~{}~~~", s.len, s); - FilterResult r = this->filter_scalar_block_folded_in_place(s, s.len, indentation, chomp); - csubstr result; - if(C4_LIKELY(r.valid())) - { - result = r.get(); - } - else - { - _c4dbgpf("filtering block folded scalar: not enough space: needs {}, have {}", r.required_len(), s.len); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, r.required_len() == s.len + 1); - // this can only happen when adding a single newline in clip mode. - // so we shift left the scalar by one place - result = _move_scalar_left_and_add_newline(s); - } - _c4dbgpf("filtering block folded scalar: success! s=[{}]~~~{}~~~", result.len, result); - return result; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_maybe_filter_key_scalar_plain(ScannedScalar const& C4_RESTRICT sc, size_t indentation) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_plain(sc.scalar, indentation); - } - else - { - _c4dbgp("plain scalar left unfiltered"); - m_evt_handler->mark_key_scalar_unfiltered(); - } - } - else - { - _c4dbgp("plain scalar doesn't need filtering"); - } - return sc.scalar; -} - -template -csubstr ParseEngine::_maybe_filter_val_scalar_plain(ScannedScalar const& C4_RESTRICT sc, size_t indentation) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_plain(sc.scalar, indentation); - } - else - { - _c4dbgp("plain scalar left unfiltered"); - m_evt_handler->mark_val_scalar_unfiltered(); - } - } - else - { - _c4dbgp("plain scalar doesn't need filtering"); - } - return sc.scalar; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_maybe_filter_key_scalar_squot(ScannedScalar const& C4_RESTRICT sc) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_squot(sc.scalar); - } - else - { - _c4dbgp("squo key scalar left unfiltered"); - m_evt_handler->mark_key_scalar_unfiltered(); - } - } - else - { - _c4dbgp("squo key scalar doesn't need filtering"); - } - return sc.scalar; -} - -template -csubstr ParseEngine::_maybe_filter_val_scalar_squot(ScannedScalar const& C4_RESTRICT sc) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_squot(sc.scalar); - } - else - { - _c4dbgp("squo val scalar left unfiltered"); - m_evt_handler->mark_val_scalar_unfiltered(); - } - } - else - { - _c4dbgp("squo val scalar doesn't need filtering"); - } - return sc.scalar; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_maybe_filter_key_scalar_dquot(ScannedScalar const& C4_RESTRICT sc) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_dquot(sc.scalar); - } - else - { - _c4dbgp("dquo scalar left unfiltered"); - m_evt_handler->mark_key_scalar_unfiltered(); - } - } - else - { - _c4dbgp("dquo scalar doesn't need filtering"); - } - return sc.scalar; -} - -template -csubstr ParseEngine::_maybe_filter_val_scalar_dquot(ScannedScalar const& C4_RESTRICT sc) -{ - if(sc.needs_filter) - { - if(m_options.scalar_filtering()) - { - return _filter_scalar_dquot(sc.scalar); - } - else - { - _c4dbgp("dquo scalar left unfiltered"); - m_evt_handler->mark_val_scalar_unfiltered(); - } - } - else - { - _c4dbgp("dquo scalar doesn't need filtering"); - } - return sc.scalar; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_maybe_filter_key_scalar_literal(ScannedBlock const& C4_RESTRICT sb) -{ - if(m_options.scalar_filtering()) - { - return _filter_scalar_literal(sb.scalar, sb.indentation, sb.chomp); - } - else - { - _c4dbgp("literal scalar left unfiltered"); - m_evt_handler->mark_key_scalar_unfiltered(); - } - return sb.scalar; -} - -template -csubstr ParseEngine::_maybe_filter_val_scalar_literal(ScannedBlock const& C4_RESTRICT sb) -{ - if(m_options.scalar_filtering()) - { - return _filter_scalar_literal(sb.scalar, sb.indentation, sb.chomp); - } - else - { - _c4dbgp("literal scalar left unfiltered"); - m_evt_handler->mark_val_scalar_unfiltered(); - } - return sb.scalar; -} - - -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::_maybe_filter_key_scalar_folded(ScannedBlock const& C4_RESTRICT sb) -{ - if(m_options.scalar_filtering()) - { - return _filter_scalar_folded(sb.scalar, sb.indentation, sb.chomp); - } - else - { - _c4dbgp("folded scalar left unfiltered"); - m_evt_handler->mark_key_scalar_unfiltered(); - } - return sb.scalar; -} - -template -csubstr ParseEngine::_maybe_filter_val_scalar_folded(ScannedBlock const& C4_RESTRICT sb) -{ - if(m_options.scalar_filtering()) - { - return _filter_scalar_folded(sb.scalar, sb.indentation, sb.chomp); - } - else - { - _c4dbgp("folded scalar left unfiltered"); - m_evt_handler->mark_val_scalar_unfiltered(); - } - return sb.scalar; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -#ifdef RYML_DBG // !!! <---------------------------------- - -template -void ParseEngine::add_flags(ParserFlag_t on, ParserState * s) -{ - char buf1_[64], buf2_[64], buf3_[64]; - csubstr buf1 = detail::_parser_flags_to_str(buf1_, on); - csubstr buf2 = detail::_parser_flags_to_str(buf2_, s->flags); - csubstr buf3 = detail::_parser_flags_to_str(buf3_, s->flags|on); - _c4dbgpf("state[{}]: add {}: before={} after={}", s->level, buf1, buf2, buf3); - s->flags |= on; -} - -template -void ParseEngine::addrem_flags(ParserFlag_t on, ParserFlag_t off, ParserState * s) -{ - char buf1_[64], buf2_[64], buf3_[64], buf4_[64]; - csubstr buf1 = detail::_parser_flags_to_str(buf1_, on); - csubstr buf2 = detail::_parser_flags_to_str(buf2_, off); - csubstr buf3 = detail::_parser_flags_to_str(buf3_, s->flags); - csubstr buf4 = detail::_parser_flags_to_str(buf4_, ((s->flags|on)&(~off))); - _c4dbgpf("state[{}]: add {} / rem {}: before={} after={}", s->level, buf1, buf2, buf3, buf4); - s->flags |= on; - s->flags &= ~off; -} - -template -void ParseEngine::rem_flags(ParserFlag_t off, ParserState * s) -{ - char buf1_[64], buf2_[64], buf3_[64]; - csubstr buf1 = detail::_parser_flags_to_str(buf1_, off); - csubstr buf2 = detail::_parser_flags_to_str(buf2_, s->flags); - csubstr buf3 = detail::_parser_flags_to_str(buf3_, s->flags&(~off)); - _c4dbgpf("state[{}]: rem {}: before={} after={}", s->level, buf1, buf2, buf3); - s->flags &= ~off; -} - -inline C4_NO_INLINE csubstr detail::_parser_flags_to_str(substr buf, ParserFlag_t flags) -{ - size_t pos = 0; - bool gotone = false; - - #define _prflag(fl) \ - if((flags & fl) == (fl)) \ - { \ - if(gotone) \ - { \ - if(pos + 1 < buf.len) \ - buf[pos] = '|'; \ - ++pos; \ - } \ - csubstr fltxt = #fl; \ - if(pos + fltxt.len <= buf.len) \ - memcpy(buf.str + pos, fltxt.str, fltxt.len); \ - pos += fltxt.len; \ - gotone = true; \ - } - - _prflag(RTOP); - _prflag(RUNK); - _prflag(RMAP); - _prflag(RSEQ); - _prflag(FLOW); - _prflag(BLCK); - _prflag(QMRK); - _prflag(RKEY); - _prflag(RVAL); - _prflag(RKCL); - _prflag(RNXT); - _prflag(SSCL); - _prflag(QSCL); - _prflag(RSET); - _prflag(RDOC); - _prflag(NDOC); - _prflag(USTY); - _prflag(RSEQIMAP); - - #undef _prflag - - if(pos == 0) - if(buf.len > 0) - buf[pos++] = '0'; - - RYML_CHECK(pos <= buf.len); - - return buf.first(pos); -} - -#endif // RYML_DBG !!! <---------------------------------- - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -template -csubstr ParseEngine::location_contents(Location const& loc) const -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, loc.offset < m_buf.len); - return m_buf.sub(loc.offset); -} - -template -Location ParseEngine::val_location(const char *val) const -{ - if(C4_UNLIKELY(val == nullptr)) - return {m_file, 0, 0, 0}; - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_options.locations()); - // NOTE: if any of these checks fails, the parser needs to be - // instantiated with locations enabled. - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.str == m_newline_offsets_buf.str); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.len == m_newline_offsets_buf.len); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_options.locations()); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, !_locations_dirty()); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_newline_offsets != nullptr); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_newline_offsets_size > 0); - // NOTE: the pointer needs to belong to the buffer that was used to parse. - csubstr src = m_buf; - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, val != nullptr || src.str == nullptr); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, (val >= src.begin() && val <= src.end()) || (src.str == nullptr && val == nullptr)); - // ok. search the first stored newline after the given ptr - using lineptr_type = size_t const* C4_RESTRICT; - lineptr_type lineptr = nullptr; - size_t offset = (size_t)(val - src.begin()); - if(m_newline_offsets_size < RYML_LOCATIONS_SMALL_THRESHOLD) - { - // just do a linear search if the size is small. - for(lineptr_type curr = m_newline_offsets, last = m_newline_offsets + m_newline_offsets_size; curr < last; ++curr) - { - if(*curr > offset) - { - lineptr = curr; - break; - } - } - } - else - { - // do a bisection search if the size is not small. - // - // We could use std::lower_bound but this is simple enough and - // spares the costly include of . - size_t count = m_newline_offsets_size; - size_t step; - lineptr_type it; - lineptr = m_newline_offsets; - while(count) - { - step = count >> 1; - it = lineptr + step; - if(*it < offset) - { - lineptr = ++it; - count -= step + 1; - } - else - { - count = step; - } - } - } - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, lineptr >= m_newline_offsets); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, lineptr <= m_newline_offsets + m_newline_offsets_size); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, *lineptr > offset); - Location loc; - loc.name = m_file; - loc.offset = offset; - loc.line = (size_t)(lineptr - m_newline_offsets); - if(lineptr > m_newline_offsets) - loc.col = (offset - *(lineptr-1) - 1u); - else - loc.col = offset; - return loc; -} - -template -void ParseEngine::_prepare_locations() -{ - m_newline_offsets_buf = m_buf; - size_t numnewlines = 1u + m_buf.count('\n'); - _resize_locations(numnewlines); - m_newline_offsets_size = 0; - for(size_t i = 0; i < m_buf.len; i++) - if(m_buf[i] == '\n') - m_newline_offsets[m_newline_offsets_size++] = i; - m_newline_offsets[m_newline_offsets_size++] = m_buf.len; - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_newline_offsets_size == numnewlines); -} - -template -void ParseEngine::_resize_locations(size_t numnewlines) -{ - if(numnewlines > m_newline_offsets_capacity) - { - if(m_newline_offsets) - _RYML_CB_FREE(m_evt_handler->m_stack.m_callbacks, m_newline_offsets, size_t, m_newline_offsets_capacity); - m_newline_offsets = _RYML_CB_ALLOC_HINT(m_evt_handler->m_stack.m_callbacks, size_t, numnewlines, m_newline_offsets); - m_newline_offsets_capacity = numnewlines; - } -} - -template -bool ParseEngine::_locations_dirty() const -{ - return !m_newline_offsets_size; -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_flow_skip_whitespace() -{ - // don't assign to csubstr rem: otherwise, gcc12,13,14 -O3 -m32 misbuilds - if(m_evt_handler->m_curr->line_contents.rem.len > 0) - { - if(m_evt_handler->m_curr->line_contents.rem.str[0] == ' ' || m_evt_handler->m_curr->line_contents.rem.str[0] == '\t') - { - _c4dbgpf("starts with whitespace: '{}'", _c4prc(m_evt_handler->m_curr->line_contents.rem.str[0])); - _skipchars(" \t"); - } - // comments - if(m_evt_handler->m_curr->line_contents.rem.begins_with('#')) - { - _c4dbgpf("it's a comment: {}", m_evt_handler->m_curr->line_contents.rem); - _line_progressed(m_evt_handler->m_curr->line_contents.rem.len); - } - } -} - - -//----------------------------------------------------------------------------- - - -template -void ParseEngine::_handle_colon() -{ - size_t curr = m_evt_handler->m_curr->pos.line; - if(m_prev_colon != npos) - { - if(curr == m_prev_colon) - _c4err("two colons on same line"); - } - m_prev_colon = curr; -} - -template -void ParseEngine::_add_annotation(Annotation *C4_RESTRICT dst, csubstr str, size_t indentation, size_t line) -{ - _c4dbgpf("store annotation[{}]: '{}' indentation={} line={}", dst->num_entries, str, indentation, line); - if(C4_UNLIKELY(dst->num_entries >= C4_COUNTOF(dst->annotations))) // NOLINT(bugprone-sizeof-expression) - _c4err("too many annotations"); - dst->annotations[dst->num_entries].str = str; - dst->annotations[dst->num_entries].indentation = indentation; - dst->annotations[dst->num_entries].line = line; - ++dst->num_entries; -} - -template -void ParseEngine::_clear_annotations(Annotation *C4_RESTRICT dst) -{ - dst->num_entries = 0; -} - -#ifdef RYML_NO_COVERAGE__TO_BE_DELETED -template -bool ParseEngine::_handle_indentation_from_annotations() -{ - if(m_pending_anchors.num_entries == 1u || m_pending_tags.num_entries == 1u) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_anchors.num_entries < 2u && m_pending_tags.num_entries < 2u); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_anchors.annotations[0].line < m_evt_handler->m_curr->pos.line); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_tags.annotations[1].line < m_evt_handler->m_curr->pos.line); - size_t to_skip = m_evt_handler->m_curr->indref; - if(m_pending_anchors.num_entries) - to_skip = m_pending_anchors.annotations[0].indentation > to_skip ? m_pending_anchors.annotations[0].indentation : to_skip; - if(m_pending_tags.num_entries) - to_skip = m_pending_tags.annotations[0].indentation > to_skip ? m_pending_tags.annotations[0].indentation : to_skip; - _c4dbgpf("annotations pending, skip indentation up to {}!", to_skip); - _maybe_skipchars_up_to(' ', to_skip); - return true; - } - return false; -} -#endif - -template -bool ParseEngine::_annotations_require_key_container() const -{ - return m_pending_tags.num_entries > 1 || m_pending_anchors.num_entries > 1; -} - -template -void ParseEngine::_check_tag(csubstr tag) -{ - if(!tag.begins_with("!<")) - { - if(C4_UNLIKELY(tag.first_of("[]{},") != npos)) - _RYML_CB_ERR_(m_evt_handler->m_stack.m_callbacks, "tags must not contain any of '[]{},'", m_evt_handler->m_curr->pos); - } - else - { - if(C4_UNLIKELY(!tag.ends_with('>'))) - _RYML_CB_ERR_(m_evt_handler->m_stack.m_callbacks, "malformed tag", m_evt_handler->m_curr->pos); - } -} - -template -void ParseEngine::_handle_annotations_before_blck_key_scalar() -{ - _c4dbgpf("annotations_before_blck_key_scalar, node={}", m_evt_handler->m_curr->node_id); - if(m_pending_tags.num_entries) - { - _c4dbgpf("annotations_before_blck_key_scalar, #tags={}", m_pending_tags.num_entries); - if(C4_LIKELY(m_pending_tags.num_entries == 1)) - { - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_key_tag(m_pending_tags.annotations[0].str); - _clear_annotations(&m_pending_tags); - } - else - { - _c4err("too many tags"); - } - } - if(m_pending_anchors.num_entries) - { - _c4dbgpf("annotations_before_blck_key_scalar, #anchors={}", m_pending_anchors.num_entries); - if(C4_LIKELY(m_pending_anchors.num_entries == 1)) - { - m_evt_handler->set_key_anchor(m_pending_anchors.annotations[0].str); - _clear_annotations(&m_pending_anchors); - } - else - { - _c4err("too many anchors"); - } - } -} - -template -void ParseEngine::_handle_annotations_before_blck_val_scalar() -{ - _c4dbgpf("annotations_before_blck_val_scalar, node={}", m_evt_handler->m_curr->node_id); - if(m_pending_tags.num_entries) - { - _c4dbgpf("annotations_before_blck_val_scalar, #tags={}", m_pending_tags.num_entries); - if(C4_LIKELY(m_pending_tags.num_entries == 1)) - { - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_val_tag(m_pending_tags.annotations[0].str); - _clear_annotations(&m_pending_tags); - } - else - { - _c4err("too many tags"); - } - } - if(m_pending_anchors.num_entries) - { - _c4dbgpf("annotations_before_blck_val_scalar, #anchors={}", m_pending_anchors.num_entries); - if(C4_LIKELY(m_pending_anchors.num_entries == 1)) - { - m_evt_handler->set_val_anchor(m_pending_anchors.annotations[0].str); - _clear_annotations(&m_pending_anchors); - } - else - { - _c4err("too many anchors"); - } - } -} - -template -void ParseEngine::_handle_annotations_before_start_mapblck(size_t current_line) -{ - _c4dbgpf("annotations_before_start_mapblck, current_line={}", current_line); - if(m_pending_tags.num_entries == 2) - { - _c4dbgp("2 tags, setting entry 0"); - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_val_tag(m_pending_tags.annotations[0].str); - } - else if(m_pending_tags.num_entries == 1) - { - _c4dbgpf("1 tag. line={}, curr={}", m_pending_tags.annotations[0].line); - if(m_pending_tags.annotations[0].line < current_line) - { - _c4dbgp("...tag is for the map. setting it."); - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_val_tag(m_pending_tags.annotations[0].str); - _clear_annotations(&m_pending_tags); - } - } - // - if(m_pending_anchors.num_entries == 2) - { - _c4dbgp("2 anchors, setting entry 0"); - m_evt_handler->set_val_anchor(m_pending_anchors.annotations[0].str); - } - else if(m_pending_anchors.num_entries == 1) - { - _c4dbgpf("1 anchor. line={}, curr={}", m_pending_anchors.annotations[0].line); - if(m_pending_anchors.annotations[0].line < current_line) - { - _c4dbgp("...anchor is for the map. setting it."); - m_evt_handler->set_val_anchor(m_pending_anchors.annotations[0].str); - _clear_annotations(&m_pending_anchors); - } - } -} - -template -void ParseEngine::_handle_annotations_before_start_mapblck_as_key() -{ - _c4dbgp("annotations_before_start_mapblck_as_key"); - if(m_pending_tags.num_entries == 2) - { - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_key_tag(m_pending_tags.annotations[0].str); - } - if(m_pending_anchors.num_entries == 2) - { - m_evt_handler->set_key_anchor(m_pending_anchors.annotations[0].str); - } -} - -template -void ParseEngine::_handle_annotations_and_indentation_after_start_mapblck(size_t key_indentation, size_t key_line) -{ - _c4dbgp("annotations_after_start_mapblck"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_tags.num_entries <= 2); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_anchors.num_entries <= 2); - if(m_pending_anchors.num_entries || m_pending_tags.num_entries) - { - key_indentation = _select_indentation_from_annotations(key_indentation, key_line); - switch(m_pending_tags.num_entries) - { - case 1u: - _check_tag(m_pending_tags.annotations[0].str); - m_evt_handler->set_key_tag(m_pending_tags.annotations[0].str); - _clear_annotations(&m_pending_tags); - break; - case 2u: - _check_tag(m_pending_tags.annotations[1].str); - m_evt_handler->set_key_tag(m_pending_tags.annotations[1].str); - _clear_annotations(&m_pending_tags); - break; - } - switch(m_pending_anchors.num_entries) - { - case 1u: - m_evt_handler->set_key_anchor(m_pending_anchors.annotations[0].str); - _clear_annotations(&m_pending_anchors); - break; - case 2u: - m_evt_handler->set_key_anchor(m_pending_anchors.annotations[1].str); - _clear_annotations(&m_pending_anchors); - break; - } - } - _set_indentation(key_indentation); -} - -template -size_t ParseEngine::_select_indentation_from_annotations(size_t val_indentation, size_t val_line) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_pending_tags.num_entries || m_pending_anchors.num_entries); - // select the left-most annotation on the max line - auto const *C4_RESTRICT curr = m_pending_anchors.num_entries ? &m_pending_anchors.annotations[0] : &m_pending_tags.annotations[0]; - for(size_t i = 0; i < m_pending_anchors.num_entries; ++i) - { - auto const& C4_RESTRICT ann = m_pending_anchors.annotations[i]; - if(ann.line > curr->line) - curr = &ann; - else if(ann.indentation < curr->indentation) - curr = &ann; - } - for(size_t j = 0; j < m_pending_tags.num_entries; ++j) - { - auto const& C4_RESTRICT ann = m_pending_tags.annotations[j]; - if(ann.line > curr->line) - curr = &ann; - else if(ann.indentation < curr->indentation) - curr = &ann; - } - return curr->line < val_line ? val_indentation : curr->indentation; -} - -template -void ParseEngine::_handle_directive(csubstr rem) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.is_sub(m_evt_handler->m_curr->line_contents.rem)); - const size_t pos = rem.find('#'); - _c4dbgpf("handle_directive: pos={} rem={}", pos, rem); - if(pos == npos) // no comments - { - m_evt_handler->add_directive(rem); - _line_progressed(rem.len); - } - else - { - csubstr to_comment = rem.first(pos); - csubstr trimmed = to_comment.trimr(" \t"); - m_evt_handler->add_directive(trimmed); - _line_progressed(pos); - _skip_comment(); - } -} - -template -bool ParseEngine::_handle_bom() -{ - const csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(rem.len) - { - const csubstr rest = rem.sub(1); - // https://yaml.org/spec/1.2.2/#52-character-encodings - #define _rymlisascii(c) ((c) > '\0' && (c) <= '\x7f') // is the character ASCII? - if(rem.begins_with({"\x00\x00\xfe\xff", 4}) || (rem.begins_with({"\x00\x00\x00", 3}) && rem.len >= 4u && _rymlisascii(rem.str[3]))) - { - _c4dbgp("byte order mark: UTF32BE"); - _handle_bom(UTF32BE); - _line_progressed(4); - return true; - } - else if(rem.begins_with("\xff\xfe\x00\x00") || (rest.begins_with({"\x00\x00\x00", 3}) && rem.len >= 4u && _rymlisascii(rem.str[0]))) - { - _c4dbgp("byte order mark: UTF32LE"); - _handle_bom(UTF32LE); - _line_progressed(4); - return true; - } - else if(rem.begins_with("\xfe\xff") || (rem.begins_with('\x00') && rem.len >= 2u && _rymlisascii(rem.str[1]))) - { - _c4dbgp("byte order mark: UTF16BE"); - _handle_bom(UTF16BE); - _line_progressed(2); - return true; - } - else if(rem.begins_with("\xff\xfe") || (rest.begins_with('\x00') && rem.len >= 2u && _rymlisascii(rem.str[0]))) - { - _c4dbgp("byte order mark: UTF16LE"); - _handle_bom(UTF16LE); - _line_progressed(2); - return true; - } - else if(rem.begins_with("\xef\xbb\xbf")) - { - _c4dbgp("byte order mark: UTF8"); - _handle_bom(UTF8); - _line_progressed(3); - return true; - } - #undef _rymlisascii - } - return false; -} - -template -void ParseEngine::_handle_bom(Encoding_e enc) -{ - if(m_encoding == NOBOM) - { - const bool is_beginning_of_file = m_evt_handler->m_curr->line_contents.rem.str == m_buf.str; - if(enc == UTF8 || is_beginning_of_file) - m_encoding = enc; - else - _c4err("non-UTF8 byte order mark can appear only at the beginning of the file"); - } - else if(enc != m_encoding) - { - _c4err("byte order mark can only be set once"); - } -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_seq_json() -{ -seqjson_start: - _c4dbgpf("handle2_seq_json: node_id={} level={} indentation={}", m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL|RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RVAL) != has_all(RNXT)); - - _handle_flow_skip_whitespace(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqjson_again; - - if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - const char first = rem.str[0]; - _c4dbgpf("mapjson[RVAL]: '{}'", first); - switch(first) - { - case '"': - { - _c4dbgp("seqjson[RVAL]: scanning double-quoted scalar"); - ScannedScalar sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - break; - } - case '[': - { - _c4dbgp("seqjson[RVAL]: start child seqjson"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RVAL, RNXT); - _line_progressed(1); - break; - } - case '{': - { - _c4dbgp("seqjson[RVAL]: start child mapjson"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|RKEY, RSEQ|RVAL|RNXT); - _line_progressed(1); - goto seqjson_finish; - } - case ']': // this happens on a trailing comma like ", ]" - { - _c4dbgp("seqjson[RVAL]: end!"); - rem_flags(RSEQ); - m_evt_handler->end_seq(); - _line_progressed(1); - if(!has_all(RSEQ|FLOW)) - goto seqjson_finish; - break; - } - default: - { - ScannedScalar sc; - if(_scan_scalar_seq_json(&sc)) - { - _c4dbgp("seqjson[RVAL]: it's a plain scalar."); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - _c4err("parse error"); - } - } - } - } - else // RNXT - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - const char first = rem.str[0]; - _c4dbgpf("mapjson[RNXT]: '{}'", first); - switch(first) - { - case ',': - { - _c4dbgp("seqjson[RNXT]: expect next val"); - addrem_flags(RVAL, RNXT); - m_evt_handler->add_sibling(); - _line_progressed(1); - break; - } - case ']': - { - _c4dbgp("seqjson[RNXT]: end!"); - m_evt_handler->end_seq(); - _line_progressed(1); - goto seqjson_finish; - } - default: - _c4err("parse error"); - } - } - - seqjson_again: - _c4dbgt("seqjson: go again", 0); - if(_finished_line()) - { - if(C4_LIKELY(!_finished_file())) - { - _line_ended(); - _scan_line(); - _c4dbgnextline(); - } - else - { - _c4err("missing terminating ]"); - } - } - goto seqjson_start; - - seqjson_finish: - _c4dbgp("seqjson: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_map_json() -{ -mapjson_start: - _c4dbgpf("handle2_map_json: node_id={} level={} indentation={}", m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RKCL|RVAL|RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, 1 == (has_any(RKEY) + has_any(RKCL) + has_any(RVAL) + has_any(RNXT))); - - _handle_flow_skip_whitespace(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapjson_again; - - if(has_any(RKEY)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapjson[RKEY]: '{}'", first); - switch(first) - { - case '"': - { - _c4dbgp("mapjson[RKEY]: scanning double-quoted scalar"); - ScannedScalar sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RKCL, RKEY); - break; - } - case '}': // this happens on a trailing comma like ", }" - { - _c4dbgp("mapjson[RKEY]: end!"); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapjson_finish; - } - default: - _c4err("parse error"); - } - } - else if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapjson[RVAL]: '{}'", first); - switch(first) - { - case '"': - { - _c4dbgp("mapjson[RVAL]: scanning double-quoted scalar"); - ScannedScalar sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - break; - } - case '[': - { - _c4dbgp("mapjson[RVAL]: start val seqjson"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_seq_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RSEQ|RVAL, RMAP|RNXT); - _line_progressed(1); - goto mapjson_finish; - } - case '{': - { - _c4dbgp("mapjson[RVAL]: start val mapjson"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RKEY, RNXT); - _line_progressed(1); - // keep going in this function - break; - } - default: - { - ScannedScalar sc; - if(_scan_scalar_map_json(&sc)) - { - _c4dbgp("mapjson[RVAL]: plain scalar."); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - _c4err("parse error"); - } - break; - } - } - } - else if(has_any(RKCL)) // read the key colon - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapjson[RKCL]: '{}'", first); - if(first == ':') - { - _c4dbgp("mapjson[RKCL]: found the colon"); - addrem_flags(RVAL, RKCL); - _line_progressed(1); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RNXT)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _c4dbgpf("mapjson[RNXT]: '{}'", rem.str[0]); - if(rem.begins_with(',')) - { - _c4dbgp("mapjson[RNXT]: expect next keyval"); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - _line_progressed(1); - } - else if(rem.begins_with('}')) - { - _c4dbgp("mapjson[RNXT]: end!"); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapjson_finish; - } - else - { - _c4err("parse error"); - } - } - - mapjson_again: - _c4dbgt("mapjson: go again", 0); - if(_finished_line()) - { - if(C4_LIKELY(!_finished_file())) - { - _line_ended(); - _scan_line(); - _c4dbgnextline(); - } - else - { - _c4err("missing terminating }"); - } - } - goto mapjson_start; - - mapjson_finish: - _c4dbgp("mapjson: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_seq_imap() -{ -seqimap_start: - _c4dbgpf("handle2_seq_imap: node_id={} level={} indref={}", m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RSEQIMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL|RNXT|QMRK|RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, 1 == has_all(RVAL) + has_all(RNXT) + has_all(QMRK) + has_all(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_stack.size() >= 3); - - _handle_flow_skip_whitespace(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqimap_again; - - if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - const char first = rem.str[0]; - _c4dbgpf("seqimap[RVAL]: '{}'", _c4prc(first)); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("seqimap[RVAL]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else if(first == '"') - { - _c4dbgp("seqimap[RVAL]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - m_evt_handler->end_map(); - goto seqimap_finish; - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_map_flow(&sc)) - { - _c4dbgp("seqimap[RVAL]: it's a scalar."); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else if(first == '[') - { - _c4dbgp("seqimap[RVAL]: start child seqflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RVAL, RNXT|RSEQIMAP); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto seqimap_finish; - } - else if(first == '{') - { - _c4dbgp("seqimap[RVAL]: start child mapflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|RKEY, RSEQ|RVAL|RSEQIMAP|RNXT); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto seqimap_finish; - } - else if(first == ',' || first == ']') - { - _c4dbgp("seqimap[RVAL]: finish without val."); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgp("seqimap[RVAL]: anchor!"); - m_evt_handler->set_val_anchor(anchor); - } - else if(first == '*') - { - csubstr ref = _scan_ref_seq(); - _c4dbgp("seqimap[RVAL]: ref!"); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RNXT)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - const char first = rem.str[0]; - _c4dbgpf("seqimap[RNXT]: '{}'", _c4prc(first)); - if(first == ',' || first == ']') - { - // we may get here because a map or a seq started and we - // return later - _c4dbgp("seqimap: done"); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else - { - _c4err("parse error"); - } - } - else if(has_any(QMRK)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - const char first = rem.str[0]; - _c4dbgpf("seqimap[QMRK]: '{}'", _c4prc(first)); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("seqimap[QMRK]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - goto seqimap_again; - } - else if(first == '"') - { - _c4dbgp("seqimap[QMRK]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - goto seqimap_again; - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_map_flow(&sc)) - { - _c4dbgp("seqimap[QMRK]: it's a scalar."); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RKCL, QMRK); - goto seqimap_again; - } - else if(first == '[') - { - _c4dbgp("seqimap[QMRK]: start child seqflow"); - addrem_flags(RKCL, QMRK); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RSEQ|RVAL, RKCL|RSEQIMAP); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto seqimap_finish; - } - else if(first == '{') - { - _c4dbgp("seqimap[QMRK]: start child mapflow"); - addrem_flags(RKCL, QMRK); - m_evt_handler->begin_map_key_flow(); - addrem_flags(RMAP|RKEY, RSEQ|RKCL|RSEQIMAP); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto seqimap_finish; - } - else if(first == ',' || first == ']') - { - _c4dbgp("seqimap[QMRK]: finish without key."); - m_evt_handler->set_key_scalar_plain_empty(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgp("seqimap[QMRK]: anchor!"); - m_evt_handler->set_key_anchor(anchor); - } - else if(first == '*') - { - csubstr ref = _scan_ref_seq(); - _c4dbgp("seqimap[QMRK]: ref!"); - m_evt_handler->set_key_ref(ref); - addrem_flags(RKCL, QMRK); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RKCL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKCL)); - const char first = rem.str[0]; - _c4dbgpf("seqimap[RKCL]: '{}'", _c4prc(first)); - if(first == ':') - { - _c4dbgp("seqimap[RKCL]: found ':'"); - addrem_flags(RVAL, RKCL); - _line_progressed(1); - goto seqimap_again; - } - else if(first == ',' || first == ']') - { - _c4dbgp("seqimap[RKCL]: found ','. finish without val"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - goto seqimap_finish; - } - else - { - _c4err("parse error"); - } - } - - seqimap_again: - _c4dbgt("seqimap: go again", 0); - if(_finished_line()) - { - if(C4_LIKELY(!_finished_file())) - { - _line_ended(); - _scan_line(); - _c4dbgnextline(); - } - else - { - _c4err("parse error"); - } - } - goto seqimap_start; - - seqimap_finish: - _c4dbgp("seqimap: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_seq_flow() -{ -seqflow_start: - _c4dbgpf("handle2_seq_flow: node_id={} level={} indentation={}", m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL|RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RVAL) != has_all(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->indref != npos); - - _handle_flow_skip_whitespace(); - // don't assign to csubstr rem: otherwise, gcc12,13,14 -O3 -m32 misbuilds - if(!m_evt_handler->m_curr->line_contents.rem.len) - goto seqflow_again; - - if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - const char first = m_evt_handler->m_curr->line_contents.rem.str[0]; - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("seqflow[RVAL]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '"') - { - _c4dbgp("seqflow[RVAL]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_seq_flow(&sc)) - { - _c4dbgp("seqflow[RVAL]: it's a scalar."); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '[') - { - _c4dbgp("seqflow[RVAL]: start child seqflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_seq_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RVAL, RNXT); - _line_progressed(1); - } - else if(first == '{') - { - _c4dbgp("seqflow[RVAL]: start child mapflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RMAP|RKEY, RSEQ|RVAL|RNXT); - _line_progressed(1); - goto seqflow_finish; - } - else if(first == ']') // this happens on a trailing comma like ", ]" - { - _c4dbgp("seqflow[RVAL]: end!"); - _line_progressed(1); - m_evt_handler->end_seq(); - goto seqflow_finish; - } - else if(first == '*') - { - csubstr ref = _scan_ref_seq(); - _c4dbgpf("seqflow[RVAL]: ref! [{}]~~~{}~~~", ref.len, ref); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("seqflow[RVAL]: anchor! [{}]~~~{}~~~", anchor.len, anchor); - m_evt_handler->set_val_anchor(anchor); - if(_maybe_scan_following_comma()) - { - _c4dbgp("seqflow[RVAL]: empty scalar!"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - } - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("seqflow[RVAL]: tag! [{}]~~~{}~~~", tag.len, tag); - _check_tag(tag); - m_evt_handler->set_val_tag(tag); - if(_maybe_scan_following_comma()) - { - _c4dbgp("seqflow[RVAL]: empty scalar!"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - } - } - else if(first == ':') - { - _c4dbgpf("seqflow[RVAL]: actually seqimap at node[{}], with empty key", m_evt_handler->m_curr->node_id); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RSEQIMAP|RVAL, RSEQ|RNXT); - _line_progressed(1); - goto seqflow_finish; - } - else if(first == '?') - { - _c4dbgp("seqflow[RVAL]: start child mapflow, explicit key"); - addrem_flags(RNXT, RVAL); - m_was_inside_qmrk = true; - m_evt_handler->begin_map_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RSEQIMAP|QMRK, RSEQ|RNXT); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto seqflow_finish; - } - else - { - _c4err("parse error"); - } - } - else // RNXT - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - const char first = m_evt_handler->m_curr->line_contents.rem.str[0]; - if(first == ',') - { - _c4dbgp("seqflow[RNXT]: expect next val"); - addrem_flags(RVAL, RNXT); - m_evt_handler->add_sibling(); - _line_progressed(1); - } - else if(first == ']') - { - _c4dbgp("seqflow[RNXT]: end!"); - m_evt_handler->end_seq(); - _line_progressed(1); - goto seqflow_finish; - } - else if(first == ':') - { - _c4dbgpf("seqflow[RNXT]: actually seqimap at node[{}]", m_evt_handler->m_curr->node_id); - m_evt_handler->actually_val_is_first_key_of_new_map_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - addrem_flags(RSEQIMAP|RVAL, RNXT); - goto seqflow_finish; - } - else - { - _c4err("parse error"); - } - } - - seqflow_again: - _c4dbgt("seqflow: go again", 0); - if(_finished_line()) - { - if(C4_LIKELY(!_finished_file())) - { - _line_ended(); - _scan_line(); - _c4dbgnextline(); - } - else - { - _c4err("missing terminating ]"); - } - } - goto seqflow_start; - - seqflow_finish: - _c4dbgp("seqflow: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_map_flow() -{ -mapflow_start: - _c4dbgpf("handle2_map_flow: node_id={} level={} indentation={}", m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(FLOW)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RKCL|RVAL|RNXT|QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, 1 == (has_any(RKEY) + has_any(RKCL) + has_any(RVAL) + has_any(RNXT) + has_any(QMRK))); - - _handle_flow_skip_whitespace(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapflow_again; - - if(has_any(RKEY)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapflow[RKEY]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapflow[RKEY]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RKCL, RKEY|QMRK); - } - else if(first == '"') - { - _c4dbgp("mapflow[RKEY]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RKCL, RKEY|QMRK); - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_map_flow(&sc)) - { - _c4dbgp("mapflow[RKEY]: plain scalar"); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RKCL, RKEY|QMRK); - } - else if(first == '?') - { - _c4dbgp("mapflow[RKEY]: explicit key"); - _line_progressed(1); - addrem_flags(QMRK, RKEY); - _maybe_skip_whitespace_tokens(); - } - else if(first == ':') - { - _c4dbgp("mapflow[RKEY]: setting empty key"); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RVAL, RKEY|QMRK); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == ',') - { - _c4dbgp("mapflow[RKEY]: empty key+val!"); - m_evt_handler->set_key_scalar_plain_empty(); - m_evt_handler->set_val_scalar_plain_empty(); - addrem_flags(RNXT, RKEY|QMRK); - // keep going in this function - } - else if(first == '}') // this happens on a trailing comma like ", }" - { - _c4dbgp("mapflow[RKEY]: end!"); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapflow[RKEY]: key anchor! [{}]~~~{}~~~", anchor.len, anchor); - m_evt_handler->set_key_anchor(anchor); - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapflow[RKEY]: key ref! [{}]~~~{}~~~", ref.len, ref); - m_evt_handler->set_key_ref(ref); - addrem_flags(RKCL, RKEY); - } - else if(first == '[') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree sink. Other sink types may be - // able to handle it. - _c4dbgp("mapflow[RKEY]: start child seqflow (!)"); - addrem_flags(RKCL, RKEY); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RSEQ|RVAL, RMAP|RKCL); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == '{') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree sink. Other sink types may be - // able to handle it. - _c4dbgp("mapflow[RKEY]: start child mapflow (!)"); - addrem_flags(RKCL, RKEY); - m_evt_handler->begin_map_key_flow(); - addrem_flags(RKEY, RVAL|RKCL); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - // keep going in this function - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapflow[RKEY]: tag! [{}]~~~{}~~~", tag.len, tag); - _check_tag(tag); - m_evt_handler->set_key_tag(tag); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RKCL)) // read the key colon - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapflow[RKCL]: '{}'", first); - if(first == ':') - { - _c4dbgp("mapflow[RKCL]: found the colon"); - addrem_flags(RVAL, RKCL); - _line_progressed(1); - } - else if(first == '}') - { - _c4dbgp("mapflow[RKCL]: end with missing val!"); - addrem_flags(RVAL, RKCL); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == ',') - { - _c4dbgp("mapflow[RKCL]: got comma. val is missing"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RKCL); - _line_progressed(1); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - const char first = rem.str[0]; - _c4dbgpf("mapflow[RVAL]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapflow[RVAL]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '"') - { - _c4dbgp("mapflow[RVAL]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_map_flow(&sc)) - { - _c4dbgp("mapflow[RVAL]: plain scalar."); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '[') - { - _c4dbgp("mapflow[RVAL]: start val seqflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_seq_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RSEQ|RVAL, RMAP|RNXT); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == '{') - { - _c4dbgp("mapflow[RVAL]: start val mapflow"); - addrem_flags(RNXT, RVAL); - m_evt_handler->begin_map_val_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RKEY, RNXT); - _line_progressed(1); - // keep going in this function - } - else if(first == '}') - { - _c4dbgp("mapflow[RVAL]: end!"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == ',') - { - _c4dbgp("mapflow[RVAL]: empty val!"); - m_evt_handler->set_val_scalar_plain_empty(); - addrem_flags(RNXT, RVAL); - // keep going in this function - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapflow[RVAL]: key ref! [{}]~~~{}~~~", ref.len, ref); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapflow[RVAL]: key anchor! [{}]~~~{}~~~", anchor.len, anchor); - m_evt_handler->set_val_anchor(anchor); - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapflow[RVAL]: tag! [{}]~~~{}~~~", tag.len, tag); - _check_tag(tag); - m_evt_handler->set_val_tag(tag); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RNXT)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _c4dbgpf("mapflow[RNXT]: '{}'", rem.str[0]); - if(rem.begins_with(',')) - { - _c4dbgp("mapflow[RNXT]: expect next keyval"); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - _line_progressed(1); - } - else if(rem.begins_with('}')) - { - _c4dbgp("mapflow[RNXT]: end!"); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapflow_finish; - } - else - { - _c4err("parse error"); - } - } - else if(has_any(QMRK)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - const char first = rem.str[0]; - _c4dbgpf("mapflow[QMRK]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapflow[QMRK]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else if(first == '"') - { - _c4dbgp("mapflow[QMRK]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - // block scalars (ie | and >) cannot appear in flow containers - else if(_scan_scalar_plain_map_flow(&sc)) - { - _c4dbgp("mapflow[QMRK]: plain scalar"); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else if(first == ':') - { - _c4dbgp("mapflow[QMRK]: setting empty key"); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RVAL, QMRK); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '}') // this happens on a trailing comma like ", }" - { - _c4dbgp("mapflow[QMRK]: end!"); - m_evt_handler->set_key_scalar_plain_empty(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_map(); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == ',') - { - _c4dbgp("mapflow[QMRK]: empty key+val!"); - m_evt_handler->set_key_scalar_plain_empty(); - m_evt_handler->set_val_scalar_plain_empty(); - addrem_flags(RNXT, QMRK); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapflow[QMRK]: key anchor! [{}]~~~{}~~~", anchor.len, anchor); - m_evt_handler->set_key_anchor(anchor); - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapflow[QMRK]: key ref! [{}]~~~{}~~~", ref.len, ref); - m_evt_handler->set_key_ref(ref); - addrem_flags(RKCL, QMRK); - } - else if(first == '[') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree sink. Other sink types may be - // able to handle it. - _c4dbgp("mapflow[QMRK]: start child seqflow (!)"); - addrem_flags(RKCL, QMRK); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RSEQ|RVAL, RMAP|RKCL); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto mapflow_finish; - } - else if(first == '{') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree sink. Other sink types may be - // able to handle it. - _c4dbgp("mapflow[QMRK]: start child mapflow (!)"); - addrem_flags(RKCL, QMRK); - m_evt_handler->begin_map_key_flow(); - _set_indentation(m_evt_handler->m_parent->indref); - addrem_flags(RKEY, RKCL); - _line_progressed(1); - // keep going in this function - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapflow[QMRK]: tag! [{}]~~~{}~~~", tag.len, tag); - _check_tag(tag); - m_evt_handler->set_key_tag(tag); - } - else - { - _c4err("parse error"); - } - } - - mapflow_again: - _c4dbgt("mapflow: go again", 0); - if(_finished_line()) - { - if(C4_LIKELY(!_finished_file())) - { - _line_ended(); - _scan_line(); - _c4dbgnextline(); - } - else - { - _c4err("missing terminating }"); - } - } - goto mapflow_start; - - mapflow_finish: - _c4dbgp("mapflow: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_seq_block() -{ -seqblck_start: - _c4dbgpf("handle2_seq_block: seq_id={} node_id={} level={} indent={}", m_evt_handler->m_parent->node_id, m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RSEQ)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RVAL|RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, 1 == (has_any(RVAL) + has_any(RNXT))); - - _maybe_skip_comment(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - - if(has_any(RVAL)) - { - _c4dbgpf("seqblck[RVAL]: col={}", m_evt_handler->m_curr->pos.col); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - if(m_evt_handler->m_curr->at_line_beginning()) - { - _c4dbgpf("seqblck[RVAL]: indref={} indentation={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->line_contents.indentation); - if(m_evt_handler->m_curr->indentation_ge()) - { - _c4dbgpf("seqblck[RVAL]: skip {} from indentation", m_evt_handler->m_curr->line_contents.indentation); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("seqblck[RVAL]: smaller indentation!"); - _handle_indentation_pop_from_block_seq(); - goto seqblck_finish; - } - else if(m_evt_handler->m_curr->line_contents.indentation == npos) - { - _c4dbgp("seqblck[RVAL]: empty line!"); - _line_progressed(m_evt_handler->m_curr->line_contents.rem.len); - goto seqblck_again; - } - } - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - else - { - // accomodate annotation on the previous line. eg: - // - &elm - // foo # <-- on this line - // - &elm - // &foo foo: bar # <-- on this line - if(rem.str[0] == ' ') - { - if(_handle_indentation_from_annotations()) - { - _c4dbgp("seqblck[RVAL]: annotations!"); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - } - } - } - #endif - _RYML_CB_ASSERT(callbacks(), rem.len); - _c4dbgpf("seqblck[RVAL]: '{}' node_id={}", rem.str[0], m_evt_handler->m_curr->node_id); - const char first = rem.str[0]; - const size_t startline = m_evt_handler->m_curr->pos.line; - // warning: the gcc optimizer on x86 builds is brittle with - // this function: - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("seqblck[RVAL]: single-quoted scalar"); - sc = _scan_scalar_squot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("seqblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); // VAL! - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - _c4dbgp("seqblck[RVAL]: start mapblck, set scalar as key"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); // KEY! - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RMAP|RVAL, RSEQ|RNXT); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - } - else if(first == '"') - { - _c4dbgp("seqblck[RVAL]: double-quoted scalar"); - sc = _scan_scalar_dquot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("seqblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); // VAL! - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - _c4dbgp("seqblck[RVAL]: start mapblck, set scalar as key"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); // KEY! - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RMAP|RVAL, RSEQ|RNXT); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - } - // block scalars can only appear as keys when in QMRK scope - // (ie, after ? tokens), so no need to scan following colon in - // here. - else if(first == '|') - { - _c4dbgp("seqblck[RVAL]: block-literal scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_literal(sb); - m_evt_handler->set_val_scalar_literal(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '>') - { - _c4dbgp("seqblck[RVAL]: block-folded scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_folded(sb); - m_evt_handler->set_val_scalar_folded(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(_scan_scalar_plain_seq_blck(&sc)) - { - _c4dbgp("seqblck[RVAL]: plain scalar."); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("seqblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); // VAL! - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - if(startindent > m_evt_handler->m_curr->indref) - { - _c4dbgp("seqblck[RVAL]: start mapblck, set scalar as key"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY! - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RMAP|RVAL, RSEQ|RNXT); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - else if(m_evt_handler->m_parent && m_evt_handler->m_parent->indref == startindent && has_any(RMAP|BLCK, m_evt_handler->m_parent)) - { - _c4dbgp("seqblck[RVAL]: empty val + end indentless seq + set key"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->end_seq(); - m_evt_handler->add_sibling(); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY! - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RVAL, RNXT|RKEY); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - else - { - _c4err("parse error"); - } - } - } - else if(first == '[') - { - _c4dbgp("seqblck[RVAL]: start child seqflow"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(FLOW|RVAL, BLCK|RNXT); - _line_progressed(1); - _set_indentation(m_evt_handler->m_parent->indref + 1u); - goto seqblck_finish; - } - else if(first == '{') - { - _c4dbgp("seqblck[RVAL]: start child mapflow"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|RKEY|FLOW, BLCK|RSEQ|RVAL|RNXT); - _line_progressed(1); - _set_indentation(m_evt_handler->m_parent->indref + 1u); - goto seqblck_finish; - } - else if(first == '-') - { - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("seqblck[RVAL]: prev val was empty"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - // keep in RVAL, but for the next sibling - m_evt_handler->add_sibling(); - } - else - { - _c4dbgp("seqblck[RVAL]: start child seqblck"); - _RYML_CB_ASSERT(this->callbacks(), startindent > m_evt_handler->m_curr->indref); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_block(); - addrem_flags(RVAL, RNXT); - _save_indentation(); - // keep going on inside this function - } - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == ':') - { - _c4dbgp("seqblck[RVAL]: start child mapblck with empty key"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RMAP|RVAL, RSEQ|RNXT); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - else if(first == '&') - { - const csubstr anchor = _scan_anchor(); - _c4dbgpf("seqblck[RVAL]: anchor! [{}]~~~{}~~~", anchor.len, anchor); - // we need to buffer the anchors, as there may be two - // consecutive anchors in here - _add_annotation(&m_pending_anchors, anchor, startindent, startline); - } - else if(first == '*') - { - csubstr ref = _scan_ref_seq(); - _c4dbgpf("seqblck[RVAL]: ref! [{}]~~~{}~~~", ref.len, ref); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("seqblck[RVAL]: set ref as val!"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - else - { - _c4dbgp("seqblck[RVAL]: ref is key of map"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_ref(ref); - addrem_flags(RMAP|RVAL, RSEQ|RNXT); - _set_indentation(startindent); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("seqblck[RVAL]: val tag! [{}]~~~{}~~~", tag.len, tag); - // we need to buffer the tags, as there may be two - // consecutive tags in here - _add_annotation(&m_pending_tags, tag, startindent, startline); - } - else if(first == '?') - { - _c4dbgp("seqblck[RVAL]: start child mapblck, explicit key"); - addrem_flags(RNXT, RVAL); - m_was_inside_qmrk = true; - m_evt_handler->begin_map_val_block(); - addrem_flags(RMAP|QMRK, RSEQ|RNXT); - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - else - { - _c4err("parse error"); - } - } - else // RNXT - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - // - // handle indentation - // - _c4dbgpf("seqblck[RNXT]: indref={} indentation={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->line_contents.indentation); - if(C4_LIKELY(_at_line_begin())) - { - _c4dbgp("seqblck[RNXT]: at line begin"); - if(m_evt_handler->m_curr->indentation_ge()) - { - _c4dbgpf("seqblck[RNXT]: skip {} from indref", m_evt_handler->m_curr->indref); - _line_progressed(m_evt_handler->m_curr->indref); - _maybe_skip_whitespace_tokens(); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("seqblck[RNXT]: smaller indentation!"); - _handle_indentation_pop_from_block_seq(); - if(has_all(RSEQ|BLCK)) - { - _c4dbgp("seqblck[RNXT]: still seqblck!"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RNXT)); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - } - else - { - _c4dbgp("seqblck[RNXT]: no longer seqblck!"); - goto seqblck_finish; - } - } - else if(m_evt_handler->m_curr->line_contents.indentation == npos) - { - _c4dbgpf("seqblck[RNXT]: blank line, len={}", m_evt_handler->m_curr->line_contents.rem); - _line_progressed(m_evt_handler->m_curr->line_contents.rem.len); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto seqblck_again; - } - } - else - { - _c4dbgp("seqblck[RNXT]: NOT at line begin"); - if(!rem.begins_with_any(" \t")) - { - _c4err("parse error"); - } - else - { - _skipchars(" \t"); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - { - _c4dbgp("seqblck[RNXT]: again"); - goto seqblck_again; - } - } - } - // - // now handle the tokens - // - const char first = rem.str[0]; - _c4dbgpf("seqblck[RNXT]: '{}' node_id={}", first, m_evt_handler->m_curr->node_id); - if(first == '-') - { - if(m_evt_handler->m_curr->indref > 0 || m_evt_handler->m_curr->line_contents.indentation > 0 || !_is_doc_begin_token(rem)) - { - _c4dbgp("seqblck[RNXT]: expect next val"); - addrem_flags(RVAL, RNXT); - m_evt_handler->add_sibling(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else - { - _c4dbgp("seqblck[RNXT]: start doc"); - _start_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - } - else if(first == ':') - { - // This happens for example in `- [a: b]: c` (after - // terminating the seq, ie, after `]`). All other cases - // (ie colon after scalars) are caught elsewhere (ie, in - // RVAL state). - auto const *C4_RESTRICT prev_state = m_evt_handler->m_parent; - if(C4_LIKELY(prev_state && (prev_state->flags & RMAP))) - { - _c4dbgp("seqblck[RNXT]: actually this seq was '?' key of parent map"); - m_evt_handler->end_seq(); - goto seqblck_finish; - } - else - { - _c4err("parse error"); - } - } - else if(first == '.') - { - _c4dbgp("seqblck[RNXT]: maybe doc?"); - csubstr rs = rem.sub(1); - if(rs == ".." || rs.begins_with(".. ")) - { - _c4dbgp("seqblck[RNXT]: end+start doc"); - _end_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto seqblck_finish; - } - else - { - _c4err("parse error"); - } - } - else - { - // may be an indentless sequence nested in a map... - //if(m_evt_handler->m_stack.size() >= 2) - #ifdef RYML_DBG - char flagbuf_[128]; - for(auto const& s : m_evt_handler->m_stack) - { - _dbg_printf("state[{}]: ind={} node={} flags={}\n", s.level, s.indref, s.node_id, detail::_parser_flags_to_str(flagbuf_, s.flags)); - } - #endif - if(m_evt_handler->m_parent && has_all(RMAP|BLCK, m_evt_handler->m_parent) && m_evt_handler->m_curr->indref == m_evt_handler->m_parent->indref) - { - _c4dbgpf("seqblck[RNXT]: end indentless seq, go to parent={}. node={}", m_evt_handler->m_parent->node_id, m_evt_handler->m_curr->node_id); - _RYML_CB_ASSERT(this->callbacks(), m_evt_handler->m_curr != m_evt_handler->m_parent); - _handle_indentation_pop(m_evt_handler->m_parent); - _RYML_CB_ASSERT(this->callbacks(), has_all(RMAP|BLCK)); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - goto seqblck_finish; - } - else //if(first != '*') - { - _c4err("parse error"); - } - } - } - - seqblck_again: - _c4dbgt("seqblck: go again", 0); - if(_finished_line()) - { - _line_ended(); - _scan_line(); - if(_finished_file()) - { - _c4dbgp("seqblck: finish!"); - _end_seq_blck(); - goto seqblck_finish; - } - _c4dbgnextline(); - } - goto seqblck_start; - - seqblck_finish: - _c4dbgp("seqblck: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_map_block() -{ -mapblck_start: - _c4dbgpf("handle2_map_block: map_id={} node_id={} level={} indref={}", m_evt_handler->m_parent->node_id, m_evt_handler->m_curr->node_id, m_evt_handler->m_curr->level, m_evt_handler->m_curr->indref); - - // states: RKEY|QMRK -> RKCL -> RVAL -> RNXT - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(BLCK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY|RKCL|RVAL|RNXT|QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, 1 == (has_any(RKEY) + has_any(RKCL) + has_any(RVAL) + has_any(RNXT) + has_any(QMRK))); - - _maybe_skip_comment(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - - if(has_any(RKEY)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - // - // handle indentation - // - if(m_evt_handler->m_curr->at_line_beginning()) - { - if(m_evt_handler->m_curr->indentation_eq()) - { - _c4dbgpf("mapblck[RKEY]: skip {} from indref", m_evt_handler->m_curr->indref); - _line_progressed(m_evt_handler->m_curr->indref); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("mapblck[RKEY]: smaller indentation!"); - _handle_indentation_pop_from_block_map(); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - if(has_all(RMAP|BLCK)) - { - _c4dbgp("mapblck[RKEY]: still mapblck!"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(RKEY)); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else - { - _c4dbgp("mapblck[RKEY]: no longer mapblck!"); - goto mapblck_finish; - } - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->indentation_gt()); - _c4err("invalid indentation"); - } - } - // - // now handle the tokens - // - const char first = rem.str[0]; - const size_t startline = m_evt_handler->m_curr->pos.line; - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(); - _c4dbgpf("mapblck[RKEY]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapblck[RKEY]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RVAL, RKEY); - if(!_maybe_scan_following_colon()) - _c4err("could not find ':' colon after key"); - _maybe_skip_whitespace_tokens(); - } - else if(first == '"') - { - _c4dbgp("mapblck[RKEY]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RVAL, RKEY); - if(!_maybe_scan_following_colon()) - _c4err("could not find ':' colon after key"); - _maybe_skip_whitespace_tokens(); - } - // block scalars (| and >) can not be used as keys unless they - // appear in an explicit QMRK scope (ie, after the ? token), - else if(C4_UNLIKELY(first == '|')) - { - _c4err("block literal keys must be enclosed in '?'"); - } - else if(C4_UNLIKELY(first == '>')) - { - _c4err("block literal keys must be enclosed in '?'"); - } - else if(_scan_scalar_plain_map_blck(&sc)) - { - _c4dbgp("mapblck[RKEY]: plain scalar"); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RVAL, RKEY); - if(!_maybe_scan_following_colon()) - _c4err("could not find ':' colon after key"); - _maybe_skip_whitespace_tokens(); - } - else if(first == '?') - { - _c4dbgp("mapblck[RKEY]: key token!"); - addrem_flags(QMRK, RKEY); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - m_was_inside_qmrk = true; - goto mapblck_again; - } - else if(first == ':') - { - _c4dbgp("mapblck[RKEY]: setting empty key"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RVAL, RKEY); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapblck[RKEY]: key ref! [{}]~~~{}~~~", ref.len, ref); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_ref(ref); - addrem_flags(RVAL, RKEY); - if(!_maybe_scan_following_colon()) - _c4err("could not find ':' colon after key"); - _maybe_skip_whitespace_tokens(); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapblck[RKEY]: key anchor! [{}]~~~{}~~~", anchor.len, anchor); - _add_annotation(&m_pending_anchors, anchor, startindent, startline); - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapblck[RKEY]: key tag! [{}]~~~{}~~~", tag.len, tag); - _add_annotation(&m_pending_tags, tag, startindent, startline); - } - else if(first == '[') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree handler. Other handlers may be - // able to handle it. - _c4dbgp("mapblck[RKEY]: start child seqflow (!)"); - addrem_flags(RKCL, RKEY); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RMAP|BLCK|RKCL); - _line_progressed(1); - _set_indentation(startindent); - goto mapblck_finish; - } - else if(first == '{') - { - // RYML's tree cannot store container keys, but that's - // handled inside the tree handler. Other handlers may be - // able to handle it. - _c4dbgp("mapblck[RKEY]: start child mapflow (!)"); - addrem_flags(RKCL, RKEY); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->begin_map_key_flow(); - addrem_flags(FLOW|RKEY, BLCK|RKCL); - _line_progressed(1); - _set_indentation(startindent); - goto mapblck_finish; - } - else if(first == '-') - { - _c4dbgp("mapblck[RKEY]: maybe doc?"); - if(m_evt_handler->m_curr->line_contents.indentation == 0 && _is_doc_begin_token(rem)) - { - _c4dbgp("mapblck[RKEY]: end+start doc"); - _start_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - else if(first == '.') - { - _c4dbgp("mapblck[RKEY]: maybe end doc?"); - if(m_evt_handler->m_curr->line_contents.indentation == 0 && _is_doc_end_token(rem)) - { - _c4dbgp("mapblck[RKEY]: end doc"); - _end_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - _RYML_WITH_TAB_TOKENS( - else if(first == '\t') - { - _c4dbgp("mapblck[RKEY]: skip tabs"); - _maybe_skipchars('\t'); - }) - else - { - _c4err("parse error"); - } - } - else if(has_any(RKCL)) // read the key colon - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - // - // handle indentation - // - if(m_evt_handler->m_curr->at_line_beginning()) - { - if(m_evt_handler->m_curr->indentation_eq()) - { - _c4dbgpf("mapblck[RKCL]: skip {} from indref", m_evt_handler->m_curr->indref); - _line_progressed(m_evt_handler->m_curr->indref); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else if(C4_UNLIKELY(m_evt_handler->m_curr->indentation_lt())) - { - _c4err("invalid indentation"); - } - } - const char first = rem.str[0]; - _c4dbgpf("mapblck[RKCL]: '{}'", first); - if(first == ':') - { - _c4dbgp("mapblck[RKCL]: found the colon"); - addrem_flags(RVAL, RKCL); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '?') - { - _c4dbgp("mapblck[RKCL]: got '?'. val was empty"); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_was_inside_qmrk); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - addrem_flags(QMRK, RKCL); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '-') - { - if(m_evt_handler->m_curr->indref == 0 || m_evt_handler->m_curr->line_contents.indentation == 0 || _is_doc_begin_token(rem)) - { - _c4dbgp("mapblck[RKCL]: end+start doc"); - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, _is_doc_begin_token(rem)); - _start_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - else if(first == '.') - { - _c4dbgp("mapblck[RKCL]: maybe end doc?"); - csubstr rs = rem.sub(1); - if(rs == ".." || rs.begins_with(".. ")) - { - _c4dbgp("mapblck[RKCL]: end+start doc"); - _end_doc_suddenly(); - _line_progressed(3); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - else if(m_was_inside_qmrk) - { - _RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->indentation_eq()); - _c4dbgp("mapblck[RKCL]: missing :"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - m_was_inside_qmrk = false; - addrem_flags(RKEY, RKCL); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(RVAL)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - // - // handle indentation - // - if(m_evt_handler->m_curr->at_line_beginning()) - { - _c4dbgpf("mapblck[RVAL]: indref={} indentation={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->line_contents.indentation); - m_evt_handler->m_curr->more_indented = false; - if(m_evt_handler->m_curr->indref == npos) - { - _c4dbgpf("mapblck[RVAL]: setting indentation={}", m_evt_handler->m_parent->indref); - _set_indentation(m_evt_handler->m_curr->line_contents.indentation); - _line_progressed(m_evt_handler->m_curr->indref); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else if(m_evt_handler->m_curr->indentation_eq()) - { - _c4dbgp("mapblck[RVAL]: skip indentation!"); - _line_progressed(m_evt_handler->m_curr->indref); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - // TODO: this is valid: - // - // ```yaml - // a: - // b: - // --- - // a: - // b - // --- - // a: - // b: c - // ``` - // - // ... but this is not: - // - // ```yaml - // a: - // v - // --- - // a: b: c - // ``` - // - // here, we probably need to set a boolean on the state - // to disambiguate between these cases. - } - else if(m_evt_handler->m_curr->indentation_gt()) - { - _c4dbgp("mapblck[RVAL]: more indented!"); - m_evt_handler->m_curr->more_indented = true; - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("mapblck[RVAL]: smaller indentation!"); - _handle_indentation_pop_from_block_map(); - if(has_all(RMAP|BLCK)) - { - _c4dbgp("mapblck[RVAL]: still mapblck!"); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - if(has_any(RNXT)) - { - _c4dbgp("mapblck[RVAL]: speculatively expect next keyval"); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - } - goto mapblck_again; - } - else - { - _c4dbgp("mapblck[RVAL]: no longer mapblck!"); - goto mapblck_finish; - } - } - else if(m_evt_handler->m_curr->line_contents.indentation == npos) - { - _c4dbgp("mapblck[RVAL]: empty line!"); - _line_progressed(m_evt_handler->m_curr->line_contents.rem.len); - goto mapblck_again; - } - } - // - // now handle the tokens - // - const char first = rem.str[0]; - const size_t startline = m_evt_handler->m_curr->pos.line; - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(); - _c4dbgpf("mapblck[RVAL]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapblck[RVAL]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); // VAL! - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - if(startindent != m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: start new block map, set scalar as key"); - _handle_annotations_before_start_mapblck(startline); - addrem_flags(RNXT, RVAL); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); // KEY! - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - // keep the child state on RVAL - addrem_flags(RVAL, RNXT); - } - else - { - _c4dbgp("mapblck[RVAL]: prev val empty+this is a key"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); // KEY! - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - // keep going on RVAL - _maybe_skip_whitespace_tokens(); - } - } - } - else if(first == '"') - { - _c4dbgp("mapblck[RVAL]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); // VAL! - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - if(startindent != m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: start new block map, set scalar as key"); - _handle_annotations_before_start_mapblck(startline); - addrem_flags(RNXT, RVAL); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); // KEY! - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - // keep the child state on RVAL - addrem_flags(RVAL, RNXT); - } - else - { - _c4dbgp("mapblck[RVAL]: prev val empty+this is a key"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); // KEY! - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - // keep going on RVAL - _maybe_skip_whitespace_tokens(); - } - } - } - // block scalars can only appear as keys when in QMRK scope - // (ie, after ? tokens), so no need to scan following colon - else if(first == '|') - { - _c4dbgp("mapblck[RVAL]: scanning block-literal scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_literal(sb); - m_evt_handler->set_val_scalar_literal(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(first == '>') - { - _c4dbgp("mapblck[RVAL]: scanning block-folded scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_folded(sb); - m_evt_handler->set_val_scalar_folded(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else if(_scan_scalar_plain_map_blck(&sc)) - { - _c4dbgp("mapblck[RVAL]: plain scalar."); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[RVAL]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref); // VAL! - m_evt_handler->set_val_scalar_plain(maybe_filtered); - addrem_flags(RNXT, RVAL); - } - else - { - if(startindent != m_evt_handler->m_curr->indref) - { - _c4dbgpf("mapblck[RVAL]: start new block map, set scalar as key {}", m_evt_handler->m_curr->indref); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY! - m_evt_handler->set_key_scalar_plain(maybe_filtered); - _maybe_skip_whitespace_tokens(); - // keep the child state on RVAL - addrem_flags(RVAL, RNXT); - } - else - { - _c4dbgp("mapblck[RVAL]: prev val empty+this is a key"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY! - m_evt_handler->set_key_scalar_plain(maybe_filtered); - // keep going on RVAL - _maybe_skip_whitespace_tokens(); - } - } - } - else if(first == '-') - { - if(rem.len == 1 || rem.str[1] == ' ' _RYML_WITH_TAB_TOKENS(|| rem.str[1] == '\t')) - { - _c4dbgp("mapblck[RVAL]: start val seqblck"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_block(); - addrem_flags(RSEQ|RVAL, RMAP|RNXT); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else if(m_evt_handler->m_curr->indref == 0 || m_evt_handler->m_curr->line_contents.indentation == 0 || _is_doc_begin_token(rem)) - { - _c4dbgp("mapblck[RVAL]: end+start doc"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, _is_doc_begin_token(rem)); - _start_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - else if(first == '[') - { - _c4dbgp("mapblck[RVAL]: start val seqflow"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RMAP|BLCK|RNXT); - _set_indentation(m_evt_handler->m_curr->indref + 1u); - _line_progressed(1); - goto mapblck_finish; - } - else if(first == '{') - { - _c4dbgp("mapblck[RVAL]: start val mapflow"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RKEY|FLOW, BLCK|RVAL|RNXT); - m_evt_handler->m_curr->scalar_col = m_evt_handler->m_curr->line_contents.indentation; - _set_indentation(m_evt_handler->m_curr->indref + 1u); - _line_progressed(1); - goto mapblck_finish; - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapblck[RVAL]: ref! [{}]~~~{}~~~", ref.len, ref); - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgpf("mapblck[RVAL]: same indentation {}", startindent); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - else - { - _c4dbgpf("mapblck[RVAL]: larger indentation {}>{}", startindent, m_evt_handler->m_curr->indref); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, startindent > m_evt_handler->m_curr->indref); - if(_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[RVAL]: start child map, block"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_block(); - m_evt_handler->set_key_ref(ref); - _set_indentation(startindent); - // keep going in RVAL - addrem_flags(RVAL, RNXT); - } - else - { - _c4dbgp("mapblck[RVAL]: was val ref"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_ref(ref); - addrem_flags(RNXT, RVAL); - } - } - _maybe_skip_whitespace_tokens(); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapblck[RVAL]: anchor! [{}]~~~{}~~~", anchor.len, anchor); - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: anchor for next key. val is missing!"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RVAL); - } - // we need to buffer the anchors, as there may be two - // consecutive anchors in here - _add_annotation(&m_pending_anchors, anchor, startindent, startline); - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapblck[RVAL]: tag! [{}]~~~{}~~~", tag.len, tag); - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: tag for next key. val is missing!"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RVAL); - } - // we need to buffer the tags, as there may be two - // consecutive tags in here - _add_annotation(&m_pending_tags, tag, startindent, startline); - } - else if(first == '?') - { - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: got '?'. val was empty"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - addrem_flags(QMRK, RVAL); - } - else if(startindent > m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: start val mapblck"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_block(); - addrem_flags(QMRK|BLCK, RNXT); - _set_indentation(startindent); - } - else - { - _c4err("parse error"); - } - m_was_inside_qmrk = true; - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto mapblck_again; - } - else if(first == ':') - { - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: got ':'. val was empty, next key as well"); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - m_evt_handler->set_key_scalar_plain_empty(); - } - else if(startindent > m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[RVAL]: start val mapblck"); - addrem_flags(RNXT, RVAL); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_plain_empty(); - // keep the child state on RVAL - addrem_flags(RVAL, RNXT); - } - else - { - _c4err("parse error"); - } - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - goto mapblck_again; - } - else if(first == '.') - { - _c4dbgp("mapblck[RVAL]: maybe doc?"); - csubstr rs = rem.sub(1); - if(rs == ".." || rs.begins_with(".. ")) - { - _c4dbgp("seqblck[RVAL]: end doc expl"); - _end_doc_suddenly(); - _line_progressed(3); - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - _RYML_WITH_TAB_TOKENS( - else if(first == '\t') - { - _c4dbgp("mapblck[RVAL]: skip tabs"); - _maybe_skipchars('\t'); - }) - else - { - _c4err("parse error"); - } - } - else if(has_any(RNXT)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(QMRK)); - // - // handle indentation - // - if(m_evt_handler->m_curr->at_line_beginning()) - { - _c4dbgpf("mapblck[RNXT]: indref={} indentation={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->line_contents.indentation); - if(m_evt_handler->m_curr->indentation_eq()) - { - _c4dbgpf("mapblck[RNXT]: skip {} from indref", m_evt_handler->m_curr->indref); - _line_progressed(m_evt_handler->m_curr->indref); - _c4dbgp("mapblck[RNXT]: speculatively expect next keyval"); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - goto mapblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("mapblck[RNXT]: smaller indentation!"); - _handle_indentation_pop_from_block_map(); - if(has_all(RMAP|BLCK)) - { - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - if(!has_any(RKCL)) - { - _c4dbgp("mapblck[RNXT]: speculatively expect next keyval"); - m_evt_handler->add_sibling(); - addrem_flags(RKEY, RNXT); - } - goto mapblck_again; - } - else - { - goto mapblck_finish; - } - } - } - else - { - _c4dbgp("mapblck[RNXT]: NOT at line begin"); - if(!rem.begins_with_any(" \t")) - { - _c4err("parse error"); - } - else - { - _skipchars(" \t"); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - { - _c4dbgp("seqblck[RNXT]: again"); - goto mapblck_again; - } - } - } - // - // handle tokens - // - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.len > 0); - const char first = rem.str[0]; - _c4dbgpf("mapblck[RNXT]: '{}'", _c4prc(first)); - if(first == ':') - { - if(m_evt_handler->m_curr->more_indented) - { - _c4dbgp("mapblck[RNXT]: start child block map"); - C4_NOT_IMPLEMENTED(); - //m_evt_handler->actually_as_block_map(); - _line_progressed(1); - _set_indentation(m_evt_handler->m_curr->scalar_col); - m_evt_handler->m_curr->more_indented = false; - goto mapblck_again; - } - else - { - _c4err("parse error"); - } - } - else if(first == ' ') - { - _c4dbgp("mapblck[RNXT]: skip spaces"); - _maybe_skip_whitespace_tokens(); - } - else - { - _c4err("parse error"); - } - } - else if(has_any(QMRK)) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKEY)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RKCL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RVAL)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT)); - // - // handle indentation - // - if(m_evt_handler->m_curr->at_line_beginning()) - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.indentation != npos); - if(m_evt_handler->m_curr->indentation_eq()) - { - _c4dbgpf("mapblck[QMRK]: skip {} from indref", m_evt_handler->m_curr->indref); - _line_progressed(m_evt_handler->m_curr->indref); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else if(m_evt_handler->m_curr->indentation_lt()) - { - _c4dbgp("mapblck[QMRK]: smaller indentation!"); - _handle_indentation_pop_from_block_map(); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - if(has_all(RMAP|BLCK)) - { - _c4dbgp("mapblck[QMRK]: still mapblck!"); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_any(QMRK)); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - else - { - _c4dbgp("mapblck[QMRK]: no longer mapblck!"); - goto mapblck_finish; - } - } - // indentation can be larger in QMRK state - else - { - _c4dbgp("mapblck[QMRK]: larger indentation !"); - _line_progressed(m_evt_handler->m_curr->line_contents.indentation); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - goto mapblck_again; - } - } - // - // now handle the tokens - // - const char first = rem.str[0]; - const size_t startline = m_evt_handler->m_curr->pos.line; - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(); - _c4dbgpf("mapblck[QMRK]: '{}'", first); - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("mapblck[QMRK]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); // KEY! - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[QMRK]: set as key"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else - { - _c4dbgp("mapblck[QMRK]: start new block map as key (!), set scalar as key"); - addrem_flags(RKCL, QMRK); - _handle_annotations_before_start_mapblck_as_key(); - m_evt_handler->begin_map_key_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - // keep the child state on RVAL - addrem_flags(RVAL, RKCL|QMRK); - } - } - else if(first == '"') - { - _c4dbgp("mapblck[QMRK]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); // KEY! - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[QMRK]: set as key"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else - { - _c4dbgp("mapblck[QMRK]: start new block map as key (!), set scalar as key"); - addrem_flags(RKCL, QMRK); - _handle_annotations_before_start_mapblck_as_key(); - m_evt_handler->begin_map_key_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - // keep the child state on RVAL - addrem_flags(RVAL, RKCL|QMRK); - } - } - else if(first == '|') - { - _c4dbgp("mapblck[QMRK]: scanning block-literal scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - csubstr maybe_filtered = _maybe_filter_key_scalar_literal(sb); // KEY! - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_literal(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else if(first == '>') - { - _c4dbgp("mapblck[QMRK]: scanning block-literal scalar"); - ScannedBlock sb; - _scan_block(&sb, m_evt_handler->m_curr->indref + 1); - csubstr maybe_filtered = _maybe_filter_key_scalar_folded(sb); // KEY! - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_folded(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else if(_scan_scalar_plain_map_blck(&sc)) - { - _c4dbgp("mapblck[QMRK]: plain scalar"); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY! - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[QMRK]: set as key"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - addrem_flags(RKCL, QMRK); - } - else - { - _c4dbgp("mapblck[QMRK]: start new block map as key (!), set scalar as key"); - addrem_flags(RKCL, QMRK); - _handle_annotations_before_start_mapblck_as_key(); - m_evt_handler->begin_map_key_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - // keep the child state on RVAL - addrem_flags(RVAL, RKCL|QMRK); - } - } - else if(first == ':') - { - if(startindent == m_evt_handler->m_curr->indref) - { - _c4dbgp("mapblck[QMRK]: empty key"); - addrem_flags(RVAL, QMRK); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_scalar_plain_empty(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else - { - _c4dbgp("mapblck[QMRK]: start new block map as key (!), empty key"); - addrem_flags(RKCL, QMRK); - _handle_annotations_before_start_mapblck_as_key(); - m_evt_handler->begin_map_key_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_plain_empty(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - // keep the child state on RVAL - addrem_flags(RVAL, RKCL|QMRK); - } - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("mapblck[QMRK]: key ref! [{}]~~~{}~~~", ref.len, ref); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("mapblck[QMRK]: set ref as key"); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->set_key_ref(ref); - addrem_flags(RKCL, QMRK); - } - else - { - _c4dbgp("mapblck[QMRK]: start new block map as key (!), set ref as key"); - addrem_flags(RKCL, QMRK); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->begin_map_key_block(); - m_evt_handler->set_key_ref(ref); - _set_indentation(startindent); - // keep the child state on RVAL - addrem_flags(RVAL, RKCL|QMRK); - } - _maybe_skip_whitespace_tokens(); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("mapblck[QMRK]: key anchor! [{}]~~~{}~~~", anchor.len, anchor); - _add_annotation(&m_pending_anchors, anchor, startindent, startline); - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("mapblck[QMRK]: key tag! [{}]~~~{}~~~", tag.len, tag); - _add_annotation(&m_pending_tags, tag, startindent, startline); - } - else if(first == '-') - { - _c4dbgp("mapblck[QMRK]: maybe doc?"); - csubstr rs = rem.sub(1); - if(rs == "--" || rs.begins_with("-- ")) - { - _c4dbgp("mapblck[QMRK]: end+start doc"); - _start_doc_suddenly(); - _line_progressed(3); - } - else - { - _c4dbgp("mapblck[QMRK]: start child seqblck (!)"); - addrem_flags(RKCL, RKEY|QMRK); - _handle_annotations_before_blck_key_scalar(); - m_evt_handler->begin_seq_key_block(); - addrem_flags(RVAL|RSEQ, RMAP|RKCL|QMRK); - _set_indentation(startindent); - _line_progressed(1); - } - _maybe_skip_whitespace_tokens(); - goto mapblck_finish; - } - else if(first == '[') - { - _c4dbgp("mapblck[QMRK]: start child seqflow (!)"); - addrem_flags(RKCL, RKEY|QMRK); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RVAL|RSEQ|FLOW, RMAP|RKCL|QMRK|BLCK); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto mapblck_finish; - } - else if(first == '{') - { - _c4dbgp("mapblck[QMRK]: start child mapblck (!)"); - addrem_flags(RKCL, RKEY|QMRK); - m_evt_handler->begin_map_key_flow(); - addrem_flags(RKEY|FLOW, RVAL|RKCL|QMRK|BLCK); - _set_indentation(m_evt_handler->m_parent->indref); - _line_progressed(1); - goto mapblck_finish; - } - else if(first == '?') - { - _c4dbgp("mapblck[QMRK]: another QMRK '?'"); - m_evt_handler->set_key_scalar_plain_empty(); - m_evt_handler->set_val_scalar_plain_empty(); - m_evt_handler->add_sibling(); - _line_progressed(1); - } - else if(first == '.') - { - _c4dbgp("mapblck[QMRK]: maybe end doc?"); - csubstr rs = rem.sub(1); - if(rs == ".." || rs.begins_with(".. ")) - { - _c4dbgp("mapblck[QMRK]: end+start doc"); - _end_doc_suddenly(); - _line_progressed(3); - goto mapblck_finish; - } - else - { - _c4err("parse error"); - } - } - else - { - _c4err("parse error"); - } - } - - mapblck_again: - _c4dbgt("mapblck: again", 0); - if(_finished_line()) - { - _line_ended(); - _scan_line(); - if(_finished_file()) - { - _c4dbgp("mapblck: file finished!"); - _end_map_blck(); - goto mapblck_finish; - } - _c4dbgnextline(); - } - goto mapblck_start; - - mapblck_finish: - _c4dbgp("mapblck: finish"); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_unk_json() -{ - _c4dbgpf("handle_unk_json indref={} target={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->node_id); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT|RSEQ|RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RTOP)); - - _maybe_skip_comment(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - - size_t pos = rem.first_not_of(" \t"); - if(pos) - { - pos = pos != npos ? pos : rem.len; - _c4dbgpf("skipping indentation of {}", pos); - _line_progressed(pos); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - _c4dbgpf("rem is now [{}]~~~{}~~~", rem.len, rem); - } - - if(rem.begins_with('[')) - { - _c4dbgp("it's a seq"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RUNK|RTOP|RDOC); - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - m_doc_empty = false; - _line_progressed(1); - } - else if(rem.begins_with('{')) - { - _c4dbgp("it's a map"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|FLOW|RKEY, RVAL|RTOP|RUNK|RDOC); - m_doc_empty = false; - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - _line_progressed(1); - } - else if(_handle_bom()) - { - _c4dbgp("byte order mark"); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(SSCL)); - _maybe_skip_whitespace_tokens(); - csubstr s = m_evt_handler->m_curr->line_contents.rem; - if(!s.len) - return; - const size_t startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const char first = s.str[0]; - ScannedScalar sc; - if(first == '"') - { - _c4dbgp("runk_json: scanning double-quoted scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - sc = _scan_scalar_dquot(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk_json: set as val"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - } - else - { - _c4err("parse error"); - } - } - else if(_scan_scalar_plain_unk(&sc)) - { - _c4dbgp("runk_json: got a plain scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk_json: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, startindent); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - } - else - { - _c4err("parse error"); - } - } - else - { - _c4err("parse error"); - } - } -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::_handle_unk() -{ - _c4dbgpf("handle_unk indref={} target={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->node_id); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(RNXT|RSEQ|RMAP)); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RTOP)); - - _maybe_skip_comment(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - - size_t pos = rem.first_not_of(" \t"); - if(pos) - { - pos = pos != npos ? pos : rem.len; - _c4dbgpf("skipping {} whitespace characters", pos); - _line_progressed(pos); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - _c4dbgpf("rem is now [{}]~~~{}~~~", rem.len, rem); - } - - if(m_evt_handler->m_curr->line_contents.indentation == 0u && _at_line_begin()) - { - _c4dbgp("rtop: zero indent + at line begin"); - if(_handle_bom()) - { - _c4dbgp("byte order mark!"); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - } - const char first = rem.str[0]; - if(first == '-') - { - _c4dbgp("rtop: suspecting doc"); - if(_is_doc_begin_token(rem)) - { - _c4dbgp("rtop: begin doc"); - _maybe_end_doc(); - _begin2_doc_expl(); - _set_indentation(0); - addrem_flags(RDOC|RUNK, NDOC); - _line_progressed(3u); - _maybe_skip_whitespace_tokens(); - return; - } - } - else if(first == '.') - { - _c4dbgp("rtop: suspecting doc end"); - if(_is_doc_end_token(rem)) - { - _c4dbgp("rtop: end doc"); - if(has_any(RDOC)) - { - _end2_doc_expl(); - } - else - { - _c4dbgp("rtop: ignore end doc"); - } - addrem_flags(NDOC|RUNK, RDOC); - _line_progressed(3u); - _maybe_skip_whitespace_tokens(); - return; - } - } - else if(first == '%') - { - _c4dbgpf("directive: {}", rem); - if(C4_UNLIKELY(!m_doc_empty && has_none(NDOC))) - _RYML_CB_ERR(m_evt_handler->m_stack.m_callbacks, "need document footer before directives"); - _handle_directive(rem); - return; - } - } - - /* no else-if! */ - char first = rem.str[0]; - - if(first == '[') - { - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - m_doc_empty = false; - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(rem); - if(C4_LIKELY( ! _annotations_require_key_container())) - { - _c4dbgp("it's a seq, flow"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RUNK|RTOP|RDOC); - _set_indentation(startindent); - } - else - { - _c4dbgp("start new block map, set flow seq as key (!)"); - _handle_annotations_before_start_mapblck(m_evt_handler->m_curr->pos.line); - m_evt_handler->begin_map_val_block(); - addrem_flags(RMAP|BLCK|RKCL, RUNK|RTOP|RDOC); - _handle_annotations_and_indentation_after_start_mapblck(startindent, m_evt_handler->m_curr->pos.line); - m_evt_handler->begin_seq_key_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RMAP|BLCK|RKCL); - _set_indentation(startindent); - } - _line_progressed(1); - } - else if(first == '{') - { - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - m_doc_empty = false; - const size_t startindent = m_evt_handler->m_curr->line_contents.current_col(rem); - if(C4_LIKELY( ! _annotations_require_key_container())) - { - _c4dbgp("it's a map, flow"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|FLOW|RKEY, RVAL|RTOP|RUNK|RDOC); - _set_indentation(startindent); - } - else - { - _c4dbgp("start new block map, set flow map as key (!)"); - _handle_annotations_before_start_mapblck(m_evt_handler->m_curr->pos.line); - m_evt_handler->begin_map_val_block(); - addrem_flags(RMAP|BLCK|RKCL, RUNK|RTOP|RDOC); - _handle_annotations_and_indentation_after_start_mapblck(startindent, m_evt_handler->m_curr->pos.line); - m_evt_handler->begin_map_key_flow(); - addrem_flags(RMAP|FLOW|RKEY, BLCK|RKCL); - _set_indentation(startindent); - } - _line_progressed(1); - } - else if(first == '-' && _is_blck_token(rem)) - { - _c4dbgp("it's a seq, block"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_block(); - addrem_flags(RSEQ|BLCK|RVAL, RNXT|RTOP|RUNK|RDOC); - m_doc_empty = false; - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '?' && _is_blck_token(rem)) - { - _c4dbgp("it's a map + this key is complex"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_block(); - addrem_flags(RMAP|BLCK|QMRK, RKEY|RVAL|RTOP|RUNK); - m_doc_empty = false; - m_was_inside_qmrk = true; - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == ':' && _is_blck_token(rem)) - { - if(m_doc_empty) - { - _c4dbgp("it's a map with an empty key"); - const size_t startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const size_t startline = m_evt_handler->m_curr->pos.line; // save - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_scalar_plain_empty(); - m_doc_empty = false; - _set_indentation(startindent); - } - else - { - _c4dbgp("actually prev val is a key!"); - size_t prev_indentation = m_evt_handler->m_curr->indref; - m_evt_handler->actually_val_is_first_key_of_new_map_block(); - _set_indentation(prev_indentation); - } - addrem_flags(RMAP|BLCK|RVAL, RTOP|RUNK|RDOC); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("anchor! [{}]~~~{}~~~", anchor.len, anchor); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_anchors, anchor, indentation, line); - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - m_doc_empty = false; - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("ref! [{}]~~~{}~~~", ref.len, ref); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - m_doc_empty = false; - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk: set val ref"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_ref(ref); - } - else - { - _c4dbgp("runk: start new block map, set ref as key"); - const size_t startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const size_t startline = m_evt_handler->m_curr->pos.line; // save - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_ref(ref); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RTOP|RUNK|RDOC); - } - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("unk: val tag! [{}]~~~{}~~~", tag.len, tag); - // we need to buffer the tags, as there may be two - // consecutive tags in here - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_tags, tag, indentation, line); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(SSCL)); - _maybe_skip_whitespace_tokens(); - csubstr s = m_evt_handler->m_curr->line_contents.rem; - if(!s.len) - return; - const size_t startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const size_t startline = m_evt_handler->m_curr->pos.line; // save - first = s.str[0]; - ScannedScalar sc; - if(first == '\'') - { - _c4dbgp("runk: scanning single-quoted scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - sc = _scan_scalar_squot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - } - else - { - _c4dbgp("runk: start new block map, set scalar as key"); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RTOP|RUNK|RDOC); - } - } - else if(first == '"') - { - _c4dbgp("runk: scanning double-quoted scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - sc = _scan_scalar_dquot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - } - else - { - _c4dbgp("runk: start new block map, set double-quoted scalar as key"); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_colon(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RTOP|RUNK|RDOC); - } - } - else if(first == '|') - { - _c4dbgp("runk: scanning block-literal scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - ScannedBlock sb; - _scan_block(&sb, startindent); - if(C4_LIKELY(!_maybe_scan_following_colon())) - { - _c4dbgp("runk: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_literal(sb); - m_evt_handler->set_val_scalar_literal(maybe_filtered); - } - else - { - _c4err("block literal keys must be enclosed in '?'"); - } - } - else if(first == '>') - { - _c4dbgp("runk: scanning block-folded scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - ScannedBlock sb; - _scan_block(&sb, startindent); - if(C4_LIKELY(!_maybe_scan_following_colon())) - { - _c4dbgp("runk: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_folded(sb); - m_evt_handler->set_val_scalar_folded(maybe_filtered); - } - else - { - _c4err("block folded keys must be enclosed in '?'"); - } - } - else if(_scan_scalar_plain_unk(&sc)) - { - _c4dbgp("runk: got a plain scalar"); - m_evt_handler->check_trailing_doc_token(); - _maybe_begin_doc(); - add_flags(RDOC); - m_doc_empty = false; - if(!_maybe_scan_following_colon()) - { - _c4dbgp("runk: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, startindent); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - } - else - { - _c4dbgp("runk: start new block map, set scalar as key"); - _handle_annotations_before_start_mapblck(startline); - _handle_colon(); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, startindent); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RTOP|RUNK|RDOC); - } - } - } -} - - -//----------------------------------------------------------------------------- - -template -C4_COLD void ParseEngine::_handle_usty() -{ - _c4dbgpf("handle_usty target={}", m_evt_handler->m_curr->indref, m_evt_handler->m_curr->node_id); - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_none(BLCK|FLOW)); - - #ifdef RYML_NO_COVERAGE__TO_BE_DELETED - if(has_any(RNXT)) - { - _c4dbgp("usty[RNXT]: finishing!"); - _end_stream(); - } - #endif - - _maybe_skip_comment(); - csubstr rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - - size_t pos = rem.first_not_of(" \t"); - if(pos) - { - pos = pos != npos ? pos : rem.len; - _c4dbgpf("skipping indentation of {}", pos); - _line_progressed(pos); - rem = m_evt_handler->m_curr->line_contents.rem; - if(!rem.len) - return; - _c4dbgpf("rem is now [{}]~~~{}~~~", rem.len, rem); - } - - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, rem.len > 0); - size_t startindent = m_evt_handler->m_curr->line_contents.indentation; // save - char first = rem.str[0]; - if(has_any(RSEQ)) // destination is a sequence - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(RMAP)); - _c4dbgpf("usty[RSEQ]: first='{}'", _c4prc(first)); - if(first == '[') - { - _c4dbgp("usty[RSEQ]: it's a flow seq. merging it"); - add_flags(RNXT); - m_evt_handler->_push(); - addrem_flags(FLOW|RVAL, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '-' && _is_blck_token(rem)) - { - _c4dbgp("usty[RSEQ]: it's a block seq. merging it"); - add_flags(RNXT); - m_evt_handler->_push(); - addrem_flags(BLCK|RVAL, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else - { - _c4err("can only parse a seq into an existing seq"); - } - } - else if(has_any(RMAP)) // destination is a map - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(RSEQ)); - _c4dbgpf("usty[RMAP]: first='{}'", _c4prc(first)); - if(first == '{') - { - _c4dbgp("usty[RMAP]: it's a flow map. merging it"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->_push(); - addrem_flags(RMAP|FLOW|RKEY, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '?' && _is_blck_token(rem)) - { - _c4dbgp("usty[RMAP]: it's a block map + this key is complex"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->_push(); - addrem_flags(RMAP|BLCK|QMRK, RNXT|USTY); - m_was_inside_qmrk = true; - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == ':' && _is_blck_token(rem)) - { - _c4dbgp("usty[RMAP]: it's a map with an empty key"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->_push(); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(rem.begins_with('&')) - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("usty[RMAP]: anchor! [{}]~~~{}~~~", anchor.len, anchor); - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_anchors, anchor, indentation, line); - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("usty[RMAP]: ref! [{}]~~~{}~~~", ref.len, ref); - if(!_maybe_scan_following_colon()) - { - _c4err("cannot read a VAL to a map"); - } - else - { - _c4dbgp("usty[RMAP]: start new block map, set ref as key"); - const size_t startline = m_evt_handler->m_curr->pos.line; // save - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->_push(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_ref(ref); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - } - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("usty[RMAP]: val tag! [{}]~~~{}~~~", tag.len, tag); - // we need to buffer the tags, as there may be two - // consecutive tags in here - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_tags, tag, indentation, line); - } - else if(first == '[' || (first == '-' && _is_blck_token(rem))) - { - _c4err("cannot parse a seq into an existing map"); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(SSCL)); - startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const size_t startline = m_evt_handler->m_curr->pos.line; // save - ScannedScalar sc; - _c4dbgpf("usty[RMAP]: maybe scalar. first='{}'", _c4prc(first)); - if(first == '\'') - { - _c4dbgp("usty[RMAP]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - if(!_maybe_scan_following_colon()) - { - _c4err("cannot read a VAL to a map"); - } - else - { - _c4dbgp("usty[RMAP]: start new block map, set scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->_push(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else if(first == '"') - { - _c4dbgp("usty[RMAP]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - if(!_maybe_scan_following_colon()) - { - _c4err("cannot read a VAL to a map"); - } - else - { - _c4dbgp("usty[RMAP]: start new block map, set double-quoted scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->_push(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else if(first == '|') - { - _c4err("block literal keys must be enclosed in '?'"); - } - else if(first == '>') - { - _c4err("block literal keys must be enclosed in '?'"); - } - else if(_scan_scalar_plain_unk(&sc)) - { - _c4dbgp("usty[RMAP]: got a plain scalar"); - if(!_maybe_scan_following_colon()) - { - _c4err("cannot read a VAL to a map"); - } - else - { - _c4dbgp("usty[RMAP]: start new block map, set scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->_push(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, startindent); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else - { - _c4err("parse error"); - } - } - } - else // destination is unknown - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(RSEQ)); - _c4dbgpf("usty[UNK]: first='{}'", _c4prc(first)); - if(first == '[') - { - _c4dbgp("usty[UNK]: it's a flow seq"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_flow(); - addrem_flags(RSEQ|FLOW|RVAL, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '-' && _is_blck_token(rem)) - { - _c4dbgp("usty[UNK]: it's a block seq"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_seq_val_block(); - addrem_flags(RSEQ|BLCK|RVAL, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '{') - { - _c4dbgp("usty[UNK]: it's a flow map"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_flow(); - addrem_flags(RMAP|FLOW|RKEY, RNXT|USTY); - _set_indentation(startindent); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '?' && _is_blck_token(rem)) - { - _c4dbgp("usty[UNK]: it's a map + this key is complex"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_block(); - addrem_flags(RMAP|BLCK|QMRK, RNXT|USTY); - m_was_inside_qmrk = true; - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == ':' && _is_blck_token(rem)) - { - _c4dbgp("usty[UNK]: it's a map with an empty key"); - add_flags(RNXT); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->begin_map_val_block(); - m_evt_handler->set_key_scalar_plain_empty(); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _save_indentation(); - _line_progressed(1); - _maybe_skip_whitespace_tokens(); - } - else if(first == '&') - { - csubstr anchor = _scan_anchor(); - _c4dbgpf("usty[UNK]: anchor! [{}]~~~{}~~~", anchor.len, anchor); - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_anchors, anchor, indentation, line); - _set_indentation(m_evt_handler->m_curr->line_contents.current_col(rem)); - } - else if(first == '*') - { - csubstr ref = _scan_ref_map(); - _c4dbgpf("usty[UNK]: ref! [{}]~~~{}~~~", ref.len, ref); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("usty[UNK]: set val ref"); - _handle_annotations_before_blck_val_scalar(); - m_evt_handler->set_val_ref(ref); - } - else - { - _c4dbgp("usty[UNK]: start new block map, set ref as key"); - const size_t startline = m_evt_handler->m_curr->pos.line; // save - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - m_evt_handler->set_key_ref(ref); - _maybe_skip_whitespace_tokens(); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - } - } - else if(first == '!') - { - csubstr tag = _scan_tag(); - _c4dbgpf("usty[UNK]: val tag! [{}]~~~{}~~~", tag.len, tag); - // we need to buffer the tags, as there may be two - // consecutive tags in here - const size_t indentation = m_evt_handler->m_curr->line_contents.current_col(rem); - const size_t line = m_evt_handler->m_curr->pos.line; - _add_annotation(&m_pending_tags, tag, indentation, line); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! has_any(SSCL)); - startindent = m_evt_handler->m_curr->line_contents.indentation; // save - const size_t startline = m_evt_handler->m_curr->pos.line; // save - first = rem.str[0]; - ScannedScalar sc; - _c4dbgpf("usty[UNK]: maybe scalar. first='{}'", _c4prc(first)); - if(first == '\'') - { - _c4dbgp("usty[UNK]: scanning single-quoted scalar"); - sc = _scan_scalar_squot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("usty[UNK]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc); - m_evt_handler->set_val_scalar_squoted(maybe_filtered); - _end_stream(); - } - else - { - _c4dbgp("usty[UNK]: start new block map, set scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); - m_evt_handler->set_key_scalar_squoted(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else if(first == '"') - { - _c4dbgp("usty[UNK]: scanning double-quoted scalar"); - sc = _scan_scalar_dquot(); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("usty[UNK]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc); - m_evt_handler->set_val_scalar_dquoted(maybe_filtered); - _end_stream(); - } - else - { - _c4dbgp("usty[UNK]: start new block map, set double-quoted scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); - m_evt_handler->set_key_scalar_dquoted(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else if(first == '|') - { - _c4dbgp("usty[UNK]: scanning block-literal scalar"); - ScannedBlock sb; - _scan_block(&sb, startindent); - _c4dbgp("usty[UNK]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_literal(sb); - m_evt_handler->set_val_scalar_literal(maybe_filtered); - _end_stream(); - } - else if(first == '>') - { - _c4dbgp("usty[UNK]: scanning block-folded scalar"); - ScannedBlock sb; - _scan_block(&sb, startindent); - _c4dbgp("usty[UNK]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_folded(sb); - m_evt_handler->set_val_scalar_folded(maybe_filtered); - _end_stream(); - } - else if(_scan_scalar_plain_unk(&sc)) - { - _c4dbgp("usty[UNK]: got a plain scalar"); - if(!_maybe_scan_following_colon()) - { - _c4dbgp("usty[UNK]: set as val"); - _handle_annotations_before_blck_val_scalar(); - csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, startindent); - m_evt_handler->set_val_scalar_plain(maybe_filtered); - _end_stream(); - } - else - { - _c4dbgp("usty[UNK]: start new block map, set scalar as key"); - add_flags(RNXT); - _handle_annotations_before_start_mapblck(startline); - m_evt_handler->begin_map_val_block(); - _handle_annotations_and_indentation_after_start_mapblck(startindent, startline); - csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, startindent); - m_evt_handler->set_key_scalar_plain(maybe_filtered); - _set_indentation(startindent); - addrem_flags(RMAP|BLCK|RVAL, RNXT|USTY); - _maybe_skip_whitespace_tokens(); - } - } - else - { - _c4err("parse error"); - } - } - } -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::parse_json_in_place_ev(csubstr filename, substr src) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_stack.size() >= 1); - m_file = filename; - m_buf = src; - _reset(); - m_evt_handler->start_parse(filename.str, &_s_relocate_arena, this); - m_evt_handler->begin_stream(); - while( ! _finished_file()) - { - _scan_line(); - while( ! _finished_line()) - { - _c4dbgnextline(); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! m_evt_handler->m_curr->line_contents.rem.empty()); - if(has_any(RSEQ)) - { - _handle_seq_json(); - } - else if(has_any(RMAP)) - { - _handle_map_json(); - } - else if(has_any(RUNK)) - { - _handle_unk_json(); - } - else - { - _c4err("internal error"); - } - } - if(_finished_file()) - break; // it may have finished because of multiline blocks - _line_ended(); - } - _end_stream(); - m_evt_handler->finish_parse(); -} - - -//----------------------------------------------------------------------------- - -template -void ParseEngine::parse_in_place_ev(csubstr filename, substr src) -{ - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_stack.size() >= 1); - m_file = filename; - m_buf = src; - _reset(); - m_evt_handler->start_parse(filename.str, &_s_relocate_arena, this); - m_evt_handler->begin_stream(); - while( ! _finished_file()) - { - _scan_line(); - while( ! _finished_line()) - { - _c4dbgnextline(); - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, ! m_evt_handler->m_curr->line_contents.rem.empty()); - if(has_any(FLOW)) - { - if(has_none(RSEQIMAP)) - { - if(has_any(RSEQ)) - { - _handle_seq_flow(); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RMAP)); - _handle_map_flow(); - } - } - else - { - _handle_seq_imap(); - } - } - else if(has_any(BLCK)) - { - if(has_any(RSEQ)) - { - _handle_seq_block(); - } - else - { - _RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, has_all(RMAP)); - _handle_map_block(); - } - } - else if(has_any(RUNK)) - { - _handle_unk(); - } - else if(has_any(USTY)) - { - _handle_usty(); - } - else - { - _c4err("internal error"); - } - } - if(_finished_file()) - break; // it may have finished because of multiline blocks - _line_ended(); - } - _end_stream(); - m_evt_handler->finish_parse(); -} -/** @endcond */ - -} // namespace yml -} // namespace c4 - -// NOLINTEND(hicpp-signed-bitwise,cppcoreguidelines-avoid-goto,hicpp-avoid-goto,hicpp-multiway-paths-covered) - -#undef _c4dbgnextline - -#if defined(_MSC_VER) -# pragma warning(pop) -#elif defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -#endif // _C4_YML_PARSE_ENGINE_DEF_HPP_ diff --git a/3rdparty/rapidyaml/include/c4/yml/parse_engine.hpp b/3rdparty/rapidyaml/include/c4/yml/parse_engine.hpp deleted file mode 100644 index 656b87ea5d..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/parse_engine.hpp +++ /dev/null @@ -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 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 RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place( substr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place(csubstr filename, substr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place( substr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place(csubstr filename, substr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place( substr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place(csubstr filename, substr yaml ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_place( substr yaml ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena( csubstr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena( csubstr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena( csubstr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, csubstr yaml ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if::type parse_in_arena( csubstr yaml ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena( substr yaml, Tree *t, size_t node_id); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, substr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena( substr yaml, Tree *t ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, substr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena( substr yaml, NodeRef node ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::type parse_in_arena(csubstr filename, substr yaml ); - template RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if::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 - RYML_DEPRECATED("moved to Tree::location(Parser const&). deliberately undefined here.") - auto location(Tree const&, id_type node) const -> typename std::enable_if::type; - - template - RYML_DEPRECATED("moved to ConstNodeRef::location(Parser const&), deliberately undefined here.") - auto location(ConstNodeRef const&) const -> typename std::enable_if::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 - void _skipchars(const char (&chars)[N]); - bool _maybe_scan_following_colon() noexcept; - bool _maybe_scan_following_comma() noexcept; - -public: - - /** @cond dev */ - template auto _filter_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation) -> decltype(proc.result()); - template auto _filter_squoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result()); - template auto _filter_dquoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result()); - template auto _filter_block_literal(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result()); - template auto _filter_block_folded(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result()); - /** @endcond */ - -public: - - /** @cond dev */ - template void _filter_nl_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation); - template void _filter_nl_squoted(FilterProcessor &C4_RESTRICT proc); - template void _filter_nl_dquoted(FilterProcessor &C4_RESTRICT proc); - - template bool _filter_ws_handle_to_first_non_space(FilterProcessor &C4_RESTRICT proc); - template void _filter_ws_copy_trailing(FilterProcessor &C4_RESTRICT proc); - template void _filter_ws_skip_trailing(FilterProcessor &C4_RESTRICT proc); - - template void _filter_dquoted_backslash(FilterProcessor &C4_RESTRICT proc); - - template void _filter_chomp(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp, size_t indentation); - template size_t _handle_all_whitespace(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp); - template size_t _extend_to_chomp(FilterProcessor &C4_RESTRICT proc, size_t contents_len); - template void _filter_block_indentation(FilterProcessor &C4_RESTRICT proc, size_t indentation); - template void _filter_block_folded_newlines(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len); - template size_t _filter_block_folded_newlines_compress(FilterProcessor &C4_RESTRICT proc, size_t num_newl, size_t wpos_at_first_newl); - template void _filter_block_folded_newlines_leading(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len); - template 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 void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const; - #endif - template void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const; - template void _errloc(csubstr fmt, Location const& loc, Args const& C4_RESTRICT ...args) const; - - template 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/parser_state.hpp b/3rdparty/rapidyaml/include/c4/yml/parser_state.hpp deleted file mode 100644 index beabb8948e..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/parser_state.hpp +++ /dev/null @@ -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(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(s.str - full.str); - return col; - } -}; -static_assert(std::is_standard_layout::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::value, "ParserState not standard"); - - -} // namespace yml -} // namespace c4 - -// NOLINTEND(hicpp-signed-bitwise) - -#endif /* _C4_YML_PARSER_STATE_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/preprocess.hpp b/3rdparty/rapidyaml/include/c4/yml/preprocess.hpp deleted file mode 100644 index 3db4f700b5..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/preprocess.hpp +++ /dev/null @@ -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 - - -namespace c4 { -namespace yml { - -/** @addtogroup doc_preprocessors - * @{ - */ - -/** @cond dev */ -namespace detail { -using Preprocessor = size_t(csubstr, substr); -template -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 -substr preprocess_rxmap(csubstr rxmap, CharContainer *out) -{ - return detail::preprocess_into_container(rxmap, out); -} - - -/** Create a container with the result. - * @overload preprocess_rxmap */ -template -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/reference_resolver.hpp b/3rdparty/rapidyaml/include/c4/yml/reference_resolver.hpp deleted file mode 100644 index 7f277131ea..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/reference_resolver.hpp +++ /dev/null @@ -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 m_refs; - - /** @endcond */ -}; - -/** @} */ - -} // namespace ryml -} // namespace c4 - - -#endif // _C4_YML_REFERENCE_RESOLVER_HPP_ diff --git a/3rdparty/rapidyaml/include/c4/yml/std/map.hpp b/3rdparty/rapidyaml/include/c4/yml/std/map.hpp deleted file mode 100644 index dc07c67f54..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/std/map.hpp +++ /dev/null @@ -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 - -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 -void write(c4::yml::NodeRef *n, std::map 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 -bool read(c4::yml::ConstNodeRef const& n, std::map * 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_ diff --git a/3rdparty/rapidyaml/include/c4/yml/std/std.hpp b/3rdparty/rapidyaml/include/c4/yml/std/std.hpp deleted file mode 100644 index 08e80d1557..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/std/std.hpp +++ /dev/null @@ -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_ diff --git a/3rdparty/rapidyaml/include/c4/yml/std/string.hpp b/3rdparty/rapidyaml/include/c4/yml/std/string.hpp deleted file mode 100644 index e3318f91c1..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/std/string.hpp +++ /dev/null @@ -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 - -#endif // C4_YML_STD_STRING_HPP_ diff --git a/3rdparty/rapidyaml/include/c4/yml/std/vector.hpp b/3rdparty/rapidyaml/include/c4/yml/std/vector.hpp deleted file mode 100644 index 68aa39a241..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/std/vector.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _C4_YML_STD_VECTOR_HPP_ -#define _C4_YML_STD_VECTOR_HPP_ - -#include "c4/yml/node.hpp" -#include -#include - -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 -void write(c4::yml::NodeRef *n, std::vector const& vec) -{ - *n |= c4::yml::SEQ; - for(V const& v : vec) - n->append_child() << v; -} - -/** read the node members, overwriting existing vector entries. */ -template -bool read(c4::yml::ConstNodeRef const& n, std::vector *vec) -{ - C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast") - vec->resize(static_cast(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 uses std::vector::reference as - * the return value of its operator[]. */ -template -bool read(c4::yml::ConstNodeRef const& n, std::vector *vec) -{ - C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast") - vec->resize(static_cast(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_ diff --git a/3rdparty/rapidyaml/include/c4/yml/tag.hpp b/3rdparty/rapidyaml/include/c4/yml/tag.hpp deleted file mode 100644 index 1915b3ba67..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/tag.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _C4_YML_TAG_HPP_ -#define _C4_YML_TAG_HPP_ - -#include - -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
!e!
in
%TAG !e! tag:example.com,2000:app/
*/ - csubstr handle; - /** Eg
tag:example.com,2000:app/
in
%TAG !e! tag:example.com,2000:app/
*/ - 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/tree.hpp b/3rdparty/rapidyaml/include/c4/yml/tree.hpp deleted file mode 100644 index 2d93dd7b04..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/tree.hpp +++ /dev/null @@ -1,1561 +0,0 @@ -#ifndef _C4_YML_TREE_HPP_ -#define _C4_YML_TREE_HPP_ - -/** @file tree.hpp */ - -#include "c4/error.hpp" -#include "c4/types.hpp" -#ifndef _C4_YML_FWD_HPP_ -#include "c4/yml/fwd.hpp" -#endif -#ifndef _C4_YML_COMMON_HPP_ -#include "c4/yml/common.hpp" -#endif -#ifndef C4_YML_NODE_TYPE_HPP_ -#include "c4/yml/node_type.hpp" -#endif -#ifndef _C4_YML_TAG_HPP_ -#include "c4/yml/tag.hpp" -#endif -#ifndef _C4_CHARCONV_HPP_ -#include -#endif - -#include -#include - - -C4_SUPPRESS_WARNING_MSVC_PUSH -C4_SUPPRESS_WARNING_MSVC(4251) // needs to have dll-interface to be used by clients of struct -C4_SUPPRESS_WARNING_MSVC(4296) // expression is always 'boolean_value' -C4_SUPPRESS_WARNING_GCC_CLANG_PUSH -C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast") -C4_SUPPRESS_WARNING_GCC("-Wuseless-cast") -C4_SUPPRESS_WARNING_GCC("-Wtype-limits") - - -namespace c4 { -namespace yml { - -template inline auto read(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value, bool>::type; -template inline auto read(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value && !std::is_floating_point::value, bool>::type; -template inline auto read(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value, bool>::type; - -template inline auto readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value, bool>::type; -template inline auto readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value && !std::is_floating_point::value, bool>::type; -template inline auto readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) -> typename std::enable_if::value, bool>::type; - -template size_t to_chars_float(substr buf, T val); -template bool from_chars_float(csubstr buf, T *C4_RESTRICT val); - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/** @addtogroup doc_tree - * - * @{ - */ - -/** a node scalar is a csubstr, which may be tagged and anchored. */ -struct NodeScalar -{ - csubstr tag; - csubstr scalar; - csubstr anchor; - -public: - - /// initialize as an empty scalar - NodeScalar() noexcept : tag(), scalar(), anchor() {} // NOLINT - - /// initialize as an untagged scalar - template - NodeScalar(const char (&s)[N]) noexcept : tag(), scalar(s), anchor() {} - NodeScalar(csubstr s ) noexcept : tag(), scalar(s), anchor() {} - - /// initialize as a tagged scalar - template - NodeScalar(const char (&t)[N], const char (&s)[N]) noexcept : tag(t), scalar(s), anchor() {} - NodeScalar(csubstr t , csubstr s ) noexcept : tag(t), scalar(s), anchor() {} - -public: - - ~NodeScalar() noexcept = default; - NodeScalar(NodeScalar &&) noexcept = default; - NodeScalar(NodeScalar const&) noexcept = default; - NodeScalar& operator= (NodeScalar &&) noexcept = default; - NodeScalar& operator= (NodeScalar const&) noexcept = default; - -public: - - bool empty() const noexcept { return tag.empty() && scalar.empty() && anchor.empty(); } - - void clear() noexcept { tag.clear(); scalar.clear(); anchor.clear(); } - - void set_ref_maybe_replacing_scalar(csubstr ref, bool has_scalar) RYML_NOEXCEPT - { - csubstr trimmed = ref.begins_with('*') ? ref.sub(1) : ref; - anchor = trimmed; - if((!has_scalar) || !scalar.ends_with(trimmed)) - scalar = ref; - } -}; -C4_MUST_BE_TRIVIAL_COPY(NodeScalar); - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** convenience class to initialize nodes */ -struct NodeInit -{ - - NodeType type; - NodeScalar key; - NodeScalar val; - -public: - - /// initialize as an empty node - NodeInit() : type(NOTYPE), key(), val() {} - /// initialize as a typed node - NodeInit(NodeType_e t) : type(t), key(), val() {} - /// initialize as a sequence member - NodeInit(NodeScalar const& v) : type(VAL), key(), val(v) { _add_flags(); } - /// initialize as a sequence member with explicit type - NodeInit(NodeScalar const& v, NodeType_e t) : type(t|VAL), key(), val(v) { _add_flags(); } - /// initialize as a mapping member - NodeInit( NodeScalar const& k, NodeScalar const& v) : type(KEYVAL), key(k), val(v) { _add_flags(); } - /// initialize as a mapping member with explicit type - NodeInit(NodeType_e t, NodeScalar const& k, NodeScalar const& v) : type(t), key(k), val(v) { _add_flags(); } - /// initialize as a mapping member with explicit type (eg for SEQ or MAP) - NodeInit(NodeType_e t, NodeScalar const& k ) : type(t), key(k), val( ) { _add_flags(KEY); } - -public: - - void clear() - { - type.clear(); - key.clear(); - val.clear(); - } - - void _add_flags(type_bits more_flags=0) - { - type = (type|more_flags); - if( ! key.tag.empty()) - type = (type|KEYTAG); - if( ! val.tag.empty()) - type = (type|VALTAG); - if( ! key.anchor.empty()) - type = (type|KEYANCH); - if( ! val.anchor.empty()) - type = (type|VALANCH); - } - - bool _check() const - { - // key cannot be empty - RYML_ASSERT(key.scalar.empty() == ((type & KEY) == 0)); - // key tag cannot be empty - RYML_ASSERT(key.tag.empty() == ((type & KEYTAG) == 0)); - // val may be empty even though VAL is set. But when VAL is not set, val must be empty - RYML_ASSERT(((type & VAL) != 0) || val.scalar.empty()); - // val tag cannot be empty - RYML_ASSERT(val.tag.empty() == ((type & VALTAG) == 0)); - return true; - } -}; - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** contains the data for each YAML node. */ -struct NodeData -{ - NodeType m_type; - - NodeScalar m_key; - NodeScalar m_val; - - id_type m_parent; - id_type m_first_child; - id_type m_last_child; - id_type m_next_sibling; - id_type m_prev_sibling; -}; -C4_MUST_BE_TRIVIAL_COPY(NodeData); - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -class RYML_EXPORT Tree -{ -public: - - /** @name construction and assignment */ - /** @{ */ - - Tree() : Tree(get_callbacks()) {} - Tree(Callbacks const& cb); - Tree(id_type node_capacity, size_t arena_capacity=0) : Tree(node_capacity, arena_capacity, get_callbacks()) {} - Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb); - - ~Tree(); - - Tree(Tree const& that); - Tree(Tree && that) noexcept; - - Tree& operator= (Tree const& that); - Tree& operator= (Tree && that) noexcept; - - /** @} */ - -public: - - /** @name memory and sizing */ - /** @{ */ - - void reserve(id_type node_capacity); - - /** clear the tree and zero every node - * @note does NOT clear the arena - * @see clear_arena() */ - void clear(); - void clear_arena() { m_arena_pos = 0; } - - bool empty() const { return m_size == 0; } - - id_type size() const { return m_size; } - id_type capacity() const { return m_cap; } - id_type slack() const { RYML_ASSERT(m_cap >= m_size); return m_cap - m_size; } - - Callbacks const& callbacks() const { return m_callbacks; } - void callbacks(Callbacks const& cb) { m_callbacks = cb; } - - /** @} */ - -public: - - /** @name node getters */ - /** @{ */ - - //! get the index of a node belonging to this tree. - //! @p n can be nullptr, in which case NONE is returned - id_type id(NodeData const* n) const - { - if( ! n) - return NONE; - _RYML_CB_ASSERT(m_callbacks, n >= m_buf && n < m_buf + m_cap); - return static_cast(n - m_buf); - } - - //! get a pointer to a node's NodeData. - //! i can be NONE, in which case a nullptr is returned - NodeData *get(id_type node) // NOLINT(readability-make-member-function-const) - { - if(node == NONE) - return nullptr; - _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap); - return m_buf + node; - } - //! get a pointer to a node's NodeData. - //! i can be NONE, in which case a nullptr is returned. - NodeData const *get(id_type node) const - { - if(node == NONE) - return nullptr; - _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap); - return m_buf + node; - } - - //! An if-less form of get() that demands a valid node index. - //! This function is implementation only; use at your own risk. - NodeData * _p(id_type node) { _RYML_CB_ASSERT(m_callbacks, node != NONE && node >= 0 && node < m_cap); return m_buf + node; } // NOLINT(readability-make-member-function-const) - //! An if-less form of get() that demands a valid node index. - //! This function is implementation only; use at your own risk. - NodeData const * _p(id_type node) const { _RYML_CB_ASSERT(m_callbacks, node != NONE && node >= 0 && node < m_cap); return m_buf + node; } - - //! Get the id of the root node - id_type root_id() { if(m_cap == 0) { reserve(16); } _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; } - //! Get the id of the root node - id_type root_id() const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; } - - //! Get a NodeRef of a node by id - NodeRef ref(id_type node); - //! Get a NodeRef of a node by id - ConstNodeRef ref(id_type node) const; - //! Get a NodeRef of a node by id - ConstNodeRef cref(id_type node) const; - - //! Get the root as a NodeRef - NodeRef rootref(); - //! Get the root as a ConstNodeRef - ConstNodeRef rootref() const; - //! Get the root as a ConstNodeRef - ConstNodeRef crootref() const; - - //! get the i-th document of the stream - //! @note @p i is NOT the node id, but the doc position within the stream - NodeRef docref(id_type i); - //! get the i-th document of the stream - //! @note @p i is NOT the node id, but the doc position within the stream - ConstNodeRef docref(id_type i) const; - //! get the i-th document of the stream - //! @note @p i is NOT the node id, but the doc position within the stream - ConstNodeRef cdocref(id_type i) const; - - //! find a root child by name, return it as a NodeRef - //! @note requires the root to be a map. - NodeRef operator[] (csubstr key); - //! find a root child by name, return it as a NodeRef - //! @note requires the root to be a map. - ConstNodeRef operator[] (csubstr key) const; - - //! find a root child by index: return the root node's @p i-th child as a NodeRef - //! @note @p i is NOT the node id, but the child's position - NodeRef operator[] (id_type i); - //! find a root child by index: return the root node's @p i-th child as a NodeRef - //! @note @p i is NOT the node id, but the child's position - ConstNodeRef operator[] (id_type i) const; - - /** @} */ - -public: - - /** @name node property getters */ - /** @{ */ - - NodeType type(id_type node) const { return _p(node)->m_type; } - const char* type_str(id_type node) const { return NodeType::type_str(_p(node)->m_type); } - - csubstr const& key (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key(node)); return _p(node)->m_key.scalar; } - csubstr const& key_tag (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key_tag(node)); return _p(node)->m_key.tag; } - csubstr const& key_ref (id_type node) const { _RYML_CB_ASSERT(m_callbacks, is_key_ref(node)); return _p(node)->m_key.anchor; } - csubstr const& key_anchor(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key_anchor(node)); return _p(node)->m_key.anchor; } - NodeScalar const& keysc (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key(node)); return _p(node)->m_key; } - - csubstr const& val (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val(node)); return _p(node)->m_val.scalar; } - csubstr const& val_tag (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val_tag(node)); return _p(node)->m_val.tag; } - csubstr const& val_ref (id_type node) const { _RYML_CB_ASSERT(m_callbacks, is_val_ref(node)); return _p(node)->m_val.anchor; } - csubstr const& val_anchor(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val_anchor(node)); return _p(node)->m_val.anchor; } - NodeScalar const& valsc (id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val(node)); return _p(node)->m_val; } - - /** @} */ - -public: - - /** @name node type predicates */ - /** @{ */ - - C4_ALWAYS_INLINE bool type_has_any(id_type node, NodeType_e bits) const { return _p(node)->m_type.has_any(bits); } - C4_ALWAYS_INLINE bool type_has_all(id_type node, NodeType_e bits) const { return _p(node)->m_type.has_all(bits); } - C4_ALWAYS_INLINE bool type_has_none(id_type node, NodeType_e bits) const { return _p(node)->m_type.has_none(bits); } - - C4_ALWAYS_INLINE bool is_stream(id_type node) const { return _p(node)->m_type.is_stream(); } - C4_ALWAYS_INLINE bool is_doc(id_type node) const { return _p(node)->m_type.is_doc(); } - C4_ALWAYS_INLINE bool is_container(id_type node) const { return _p(node)->m_type.is_container(); } - C4_ALWAYS_INLINE bool is_map(id_type node) const { return _p(node)->m_type.is_map(); } - C4_ALWAYS_INLINE bool is_seq(id_type node) const { return _p(node)->m_type.is_seq(); } - C4_ALWAYS_INLINE bool has_key(id_type node) const { return _p(node)->m_type.has_key(); } - C4_ALWAYS_INLINE bool has_val(id_type node) const { return _p(node)->m_type.has_val(); } - C4_ALWAYS_INLINE bool is_val(id_type node) const { return _p(node)->m_type.is_val(); } - C4_ALWAYS_INLINE bool is_keyval(id_type node) const { return _p(node)->m_type.is_keyval(); } - C4_ALWAYS_INLINE bool has_key_tag(id_type node) const { return _p(node)->m_type.has_key_tag(); } - C4_ALWAYS_INLINE bool has_val_tag(id_type node) const { return _p(node)->m_type.has_val_tag(); } - C4_ALWAYS_INLINE bool has_key_anchor(id_type node) const { return _p(node)->m_type.has_key_anchor(); } - C4_ALWAYS_INLINE bool has_val_anchor(id_type node) const { return _p(node)->m_type.has_val_anchor(); } - C4_ALWAYS_INLINE bool has_anchor(id_type node) const { return _p(node)->m_type.has_anchor(); } - C4_ALWAYS_INLINE bool is_key_ref(id_type node) const { return _p(node)->m_type.is_key_ref(); } - C4_ALWAYS_INLINE bool is_val_ref(id_type node) const { return _p(node)->m_type.is_val_ref(); } - C4_ALWAYS_INLINE bool is_ref(id_type node) const { return _p(node)->m_type.is_ref(); } - - C4_ALWAYS_INLINE bool parent_is_seq(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_parent(node)); return is_seq(_p(node)->m_parent); } - C4_ALWAYS_INLINE bool parent_is_map(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_parent(node)); return is_map(_p(node)->m_parent); } - - /** true when the node has an anchor named a */ - C4_ALWAYS_INLINE bool has_anchor(id_type node, csubstr a) const { return _p(node)->m_key.anchor == a || _p(node)->m_val.anchor == a; } - - /** true if the node key is empty, or its scalar verifies @ref scalar_is_null(). - * @warning the node must verify @ref Tree::has_key() (asserted) (ie must be a member of a map) - * @see https://github.com/biojppm/rapidyaml/issues/413 */ - C4_ALWAYS_INLINE bool key_is_null(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key(node)); NodeData const* C4_RESTRICT n = _p(node); return !n->m_type.is_key_quoted() && (n->m_type.key_is_null() || scalar_is_null(n->m_key.scalar)); } - /** true if the node val is empty, or its scalar verifies @ref scalar_is_null(). - * @warning the node must verify @ref Tree::has_val() (asserted) (ie must be a scalar / must not be a container) - * @see https://github.com/biojppm/rapidyaml/issues/413 */ - C4_ALWAYS_INLINE bool val_is_null(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val(node)); NodeData const* C4_RESTRICT n = _p(node); return !n->m_type.is_val_quoted() && (n->m_type.val_is_null() || scalar_is_null(n->m_val.scalar)); } - - /// true if the key was a scalar requiring filtering and was left - /// unfiltered during the parsing (see ParserOptions) - C4_ALWAYS_INLINE bool is_key_unfiltered(id_type node) const { return _p(node)->m_type.is_key_unfiltered(); } - /// true if the val was a scalar requiring filtering and was left - /// unfiltered during the parsing (see ParserOptions) - C4_ALWAYS_INLINE bool is_val_unfiltered(id_type node) const { return _p(node)->m_type.is_val_unfiltered(); } - - RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor(id_type node) const { return _p(node)->m_type.has_key_anchor(); } - RYML_DEPRECATED("use has_val_anchor()") bool is_val_anchor(id_type node) const { return _p(node)->m_type.has_val_anchor(); } - RYML_DEPRECATED("use has_anchor()") bool is_anchor(id_type node) const { return _p(node)->m_type.has_anchor(); } - RYML_DEPRECATED("use has_anchor_or_ref()") bool is_anchor_or_ref(id_type node) const { return _p(node)->m_type.has_anchor() || _p(node)->m_type.is_ref(); } - - /** @} */ - -public: - - /** @name hierarchy predicates */ - /** @{ */ - - bool is_root(id_type node) const { _RYML_CB_ASSERT(m_callbacks, _p(node)->m_parent != NONE || node == 0); return _p(node)->m_parent == NONE; } - - bool has_parent(id_type node) const { return _p(node)->m_parent != NONE; } - - /** true when ancestor is parent or parent of a parent of node */ - bool is_ancestor(id_type node, id_type ancestor) const; - - /** true when key and val are empty, and has no children */ - bool empty(id_type node) const { return ! has_children(node) && _p(node)->m_key.empty() && (( ! (_p(node)->m_type & VAL)) || _p(node)->m_val.empty()); } - - /** true if @p node has a child with id @p ch */ - bool has_child(id_type node, id_type ch) const { return _p(ch)->m_parent == node; } - /** true if @p node has a child with key @p key */ - bool has_child(id_type node, csubstr key) const { return find_child(node, key) != NONE; } - /** true if @p node has any children key */ - bool has_children(id_type node) const { return _p(node)->m_first_child != NONE; } - - /** true if @p node has a sibling with id @p sib */ - bool has_sibling(id_type node, id_type sib) const { return _p(node)->m_parent == _p(sib)->m_parent; } - /** true if one of the node's siblings has the given key */ - bool has_sibling(id_type node, csubstr key) const { return find_sibling(node, key) != NONE; } - /** true if node is not a single child */ - bool has_other_siblings(id_type node) const - { - NodeData const *n = _p(node); - if(C4_LIKELY(n->m_parent != NONE)) - { - n = _p(n->m_parent); - return n->m_first_child != n->m_last_child; - } - return false; - } - - RYML_DEPRECATED("use has_other_siblings()") static bool has_siblings(id_type /*node*/) { return true; } - - /** @} */ - -public: - - /** @name hierarchy getters */ - /** @{ */ - - id_type parent(id_type node) const { return _p(node)->m_parent; } - - id_type prev_sibling(id_type node) const { return _p(node)->m_prev_sibling; } - id_type next_sibling(id_type node) const { return _p(node)->m_next_sibling; } - - /** O(#num_children) */ - id_type num_children(id_type node) const; - id_type child_pos(id_type node, id_type ch) const; - id_type first_child(id_type node) const { return _p(node)->m_first_child; } - id_type last_child(id_type node) const { return _p(node)->m_last_child; } - id_type child(id_type node, id_type pos) const; - id_type find_child(id_type node, csubstr const& key) const; - - /** O(#num_siblings) */ - /** counts with this */ - id_type num_siblings(id_type node) const { return is_root(node) ? 1 : num_children(_p(node)->m_parent); } - /** does not count with this */ - id_type num_other_siblings(id_type node) const { id_type ns = num_siblings(node); _RYML_CB_ASSERT(m_callbacks, ns > 0); return ns-1; } - id_type sibling_pos(id_type node, id_type sib) const { _RYML_CB_ASSERT(m_callbacks, ! is_root(node) || node == root_id()); return child_pos(_p(node)->m_parent, sib); } - id_type first_sibling(id_type node) const { return is_root(node) ? node : _p(_p(node)->m_parent)->m_first_child; } - id_type last_sibling(id_type node) const { return is_root(node) ? node : _p(_p(node)->m_parent)->m_last_child; } - id_type sibling(id_type node, id_type pos) const { return child(_p(node)->m_parent, pos); } - id_type find_sibling(id_type node, csubstr const& key) const { return find_child(_p(node)->m_parent, key); } - - id_type doc(id_type i) const { id_type rid = root_id(); _RYML_CB_ASSERT(m_callbacks, is_stream(rid)); return child(rid, i); } //!< gets the @p i document node index. requires that the root node is a stream. - - id_type depth_asc(id_type node) const; /**< O(log(num_tree_nodes)) get the ascending depth of the node: number of levels between root and node */ - id_type depth_desc(id_type node) const; /**< O(num_tree_nodes) get the descending depth of the node: number of levels between node and deepest child */ - - /** @} */ - -public: - - /** @name node style predicates and modifiers. see the corresponding predicate in NodeType */ - /** @{ */ - - C4_ALWAYS_INLINE bool is_container_styled(id_type node) const { return _p(node)->m_type.is_container_styled(); } - C4_ALWAYS_INLINE bool is_block(id_type node) const { return _p(node)->m_type.is_block(); } - C4_ALWAYS_INLINE bool is_flow_sl(id_type node) const { return _p(node)->m_type.is_flow_sl(); } - C4_ALWAYS_INLINE bool is_flow_ml(id_type node) const { return _p(node)->m_type.is_flow_ml(); } - C4_ALWAYS_INLINE bool is_flow(id_type node) const { return _p(node)->m_type.is_flow(); } - - C4_ALWAYS_INLINE bool is_key_styled(id_type node) const { return _p(node)->m_type.is_key_styled(); } - C4_ALWAYS_INLINE bool is_val_styled(id_type node) const { return _p(node)->m_type.is_val_styled(); } - C4_ALWAYS_INLINE bool is_key_literal(id_type node) const { return _p(node)->m_type.is_key_literal(); } - C4_ALWAYS_INLINE bool is_val_literal(id_type node) const { return _p(node)->m_type.is_val_literal(); } - C4_ALWAYS_INLINE bool is_key_folded(id_type node) const { return _p(node)->m_type.is_key_folded(); } - C4_ALWAYS_INLINE bool is_val_folded(id_type node) const { return _p(node)->m_type.is_val_folded(); } - C4_ALWAYS_INLINE bool is_key_squo(id_type node) const { return _p(node)->m_type.is_key_squo(); } - C4_ALWAYS_INLINE bool is_val_squo(id_type node) const { return _p(node)->m_type.is_val_squo(); } - C4_ALWAYS_INLINE bool is_key_dquo(id_type node) const { return _p(node)->m_type.is_key_dquo(); } - C4_ALWAYS_INLINE bool is_val_dquo(id_type node) const { return _p(node)->m_type.is_val_dquo(); } - C4_ALWAYS_INLINE bool is_key_plain(id_type node) const { return _p(node)->m_type.is_key_plain(); } - C4_ALWAYS_INLINE bool is_val_plain(id_type node) const { return _p(node)->m_type.is_val_plain(); } - C4_ALWAYS_INLINE bool is_key_quoted(id_type node) const { return _p(node)->m_type.is_key_quoted(); } - C4_ALWAYS_INLINE bool is_val_quoted(id_type node) const { return _p(node)->m_type.is_val_quoted(); } - C4_ALWAYS_INLINE bool is_quoted(id_type node) const { return _p(node)->m_type.is_quoted(); } - - C4_ALWAYS_INLINE NodeType key_style(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key(node)); return _p(node)->m_type.key_style(); } - C4_ALWAYS_INLINE NodeType val_style(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val(node) || is_root(node)); return _p(node)->m_type.val_style(); } - - C4_ALWAYS_INLINE void set_container_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, is_container(node)); _p(node)->m_type.set_container_style(style); } - C4_ALWAYS_INLINE void set_key_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_type.set_key_style(style); } - C4_ALWAYS_INLINE void set_val_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, has_val(node)); _p(node)->m_type.set_val_style(style); } - - void clear_style(id_type node, bool recurse=false); - void set_style_conditionally(id_type node, - NodeType type_mask, - NodeType rem_style_flags, - NodeType add_style_flags, - bool recurse=false); - /** @} */ - -public: - - /** @name node type modifiers */ - /** @{ */ - - void to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags=0); - void to_map(id_type node, csubstr key, type_bits more_flags=0); - void to_seq(id_type node, csubstr key, type_bits more_flags=0); - void to_val(id_type node, csubstr val, type_bits more_flags=0); - void to_map(id_type node, type_bits more_flags=0); - void to_seq(id_type node, type_bits more_flags=0); - void to_doc(id_type node, type_bits more_flags=0); - void to_stream(id_type node, type_bits more_flags=0); - - void set_key(id_type node, csubstr key) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_key.scalar = key; } - void set_val(id_type node, csubstr val) { _RYML_CB_ASSERT(m_callbacks, has_val(node)); _p(node)->m_val.scalar = val; } - - void set_key_tag(id_type node, csubstr tag) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_key.tag = tag; _add_flags(node, KEYTAG); } - void set_val_tag(id_type node, csubstr tag) { _RYML_CB_ASSERT(m_callbacks, has_val(node) || is_container(node)); _p(node)->m_val.tag = tag; _add_flags(node, VALTAG); } - - void set_key_anchor(id_type node, csubstr anchor) { _RYML_CB_ASSERT(m_callbacks, ! is_key_ref(node)); _p(node)->m_key.anchor = anchor.triml('&'); _add_flags(node, KEYANCH); } - void set_val_anchor(id_type node, csubstr anchor) { _RYML_CB_ASSERT(m_callbacks, ! is_val_ref(node)); _p(node)->m_val.anchor = anchor.triml('&'); _add_flags(node, VALANCH); } - void set_key_ref (id_type node, csubstr ref ) { _RYML_CB_ASSERT(m_callbacks, ! has_key_anchor(node)); NodeData* C4_RESTRICT n = _p(node); n->m_key.set_ref_maybe_replacing_scalar(ref, n->m_type.has_key()); _add_flags(node, KEY|KEYREF); } - void set_val_ref (id_type node, csubstr ref ) { _RYML_CB_ASSERT(m_callbacks, ! has_val_anchor(node)); NodeData* C4_RESTRICT n = _p(node); n->m_val.set_ref_maybe_replacing_scalar(ref, n->m_type.has_val()); _add_flags(node, VAL|VALREF); } - - void rem_key_anchor(id_type node) { _p(node)->m_key.anchor.clear(); _rem_flags(node, KEYANCH); } - void rem_val_anchor(id_type node) { _p(node)->m_val.anchor.clear(); _rem_flags(node, VALANCH); } - void rem_key_ref (id_type node) { _p(node)->m_key.anchor.clear(); _rem_flags(node, KEYREF); } - void rem_val_ref (id_type node) { _p(node)->m_val.anchor.clear(); _rem_flags(node, VALREF); } - void rem_anchor_ref(id_type node) { _p(node)->m_key.anchor.clear(); _p(node)->m_val.anchor.clear(); _rem_flags(node, KEYANCH|VALANCH|KEYREF|VALREF); } - - /** @} */ - -public: - - /** @name tree modifiers */ - /** @{ */ - - /** reorder the tree in memory so that all the nodes are stored - * in a linear sequence when visited in depth-first order. - * This will invalidate existing ids, since the node id is its - * position in the tree's node array. */ - void reorder(); - - /** @} */ - -public: - - /** @name anchors and references/aliases */ - /** @{ */ - - /** Resolve references (aliases <- anchors), by forwarding to @ref - * ReferenceResolver::resolve(); refer to @ref - * ReferenceResolver::resolve() for further details. */ - void resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors=true); - - /** Resolve references (aliases <- anchors), by forwarding to @ref - * ReferenceResolver::resolve(); refer to @ref - * ReferenceResolver::resolve() for further details. This overload - * uses a throwaway resolver object. */ - void resolve(bool clear_anchors=true); - - /** @} */ - -public: - - /** @name tag directives */ - /** @{ */ - - void resolve_tags(); - void normalize_tags(); - void normalize_tags_long(); - - id_type num_tag_directives() const; - bool add_tag_directive(csubstr directive); - id_type add_tag_directive(TagDirective const& td); - void clear_tag_directives(); - - /** resolve the given tag, appearing at node_id. Write the result into output. - * @return the number of characters required for the resolved tag */ - size_t resolve_tag(substr output, csubstr tag, id_type node_id) const; - csubstr resolve_tag_sub(substr output, csubstr tag, id_type node_id) const - { - size_t needed = resolve_tag(output, tag, node_id); - return needed <= output.len ? output.first(needed) : output; - } - - TagDirective const* begin_tag_directives() const { return m_tag_directives; } - TagDirective const* end_tag_directives() const { return m_tag_directives + num_tag_directives(); } - c4::yml::TagDirectiveRange tag_directives() const { return c4::yml::TagDirectiveRange{begin_tag_directives(), end_tag_directives()}; } - - RYML_DEPRECATED("use c4::yml::tag_directive_const_iterator") typedef TagDirective const* tag_directive_const_iterator; - RYML_DEPRECATED("use c4::yml::TagDirectiveRange") typedef c4::yml::TagDirectiveRange TagDirectiveProxy; - - /** @} */ - -public: - - /** @name modifying hierarchy */ - /** @{ */ - - /** create and insert a new child of @p parent. insert after the (to-be) - * sibling @p after, which must be a child of @p parent. To insert as the - * first child, set after to NONE */ - C4_ALWAYS_INLINE id_type insert_child(id_type parent, id_type after) - { - _RYML_CB_ASSERT(m_callbacks, parent != NONE); - _RYML_CB_ASSERT(m_callbacks, is_container(parent) || is_root(parent)); - _RYML_CB_ASSERT(m_callbacks, after == NONE || (_p(after)->m_parent == parent)); - id_type child = _claim(); - _set_hierarchy(child, parent, after); - return child; - } - /** create and insert a node as the first child of @p parent */ - C4_ALWAYS_INLINE id_type prepend_child(id_type parent) { return insert_child(parent, NONE); } - /** create and insert a node as the last child of @p parent */ - C4_ALWAYS_INLINE id_type append_child(id_type parent) { return insert_child(parent, _p(parent)->m_last_child); } - C4_ALWAYS_INLINE id_type _append_child__unprotected(id_type parent) - { - id_type child = _claim(); - _set_hierarchy(child, parent, _p(parent)->m_last_child); - return child; - } - -public: - - #if defined(__clang__) - # pragma clang diagnostic push - # pragma clang diagnostic ignored "-Wnull-dereference" - #elif defined(__GNUC__) - # pragma GCC diagnostic push - # if __GNUC__ >= 6 - # pragma GCC diagnostic ignored "-Wnull-dereference" - # endif - #endif - - //! create and insert a new sibling of n. insert after "after" - C4_ALWAYS_INLINE id_type insert_sibling(id_type node, id_type after) - { - return insert_child(_p(node)->m_parent, after); - } - /** create and insert a node as the first node of @p parent */ - C4_ALWAYS_INLINE id_type prepend_sibling(id_type node) { return prepend_child(_p(node)->m_parent); } - C4_ALWAYS_INLINE id_type append_sibling(id_type node) { return append_child(_p(node)->m_parent); } - -public: - - /** remove an entire branch at once: ie remove the children and the node itself */ - void remove(id_type node) - { - remove_children(node); - _release(node); - } - - /** remove all the node's children, but keep the node itself */ - void remove_children(id_type node); - - /** change the @p type of the node to one of MAP, SEQ or VAL. @p - * type must have one and only one of MAP,SEQ,VAL; @p type may - * possibly have KEY, but if it does, then the @p node must also - * have KEY. Changing to the same type is a no-op. Otherwise, - * changing to a different type will initialize the node with an - * empty value of the desired type: changing to VAL will - * initialize with a null scalar (~), changing to MAP will - * initialize with an empty map ({}), and changing to SEQ will - * initialize with an empty seq ([]). */ - bool change_type(id_type node, NodeType type); - - bool change_type(id_type node, type_bits type) - { - return change_type(node, (NodeType)type); - } - - #if defined(__clang__) - # pragma clang diagnostic pop - #elif defined(__GNUC__) - # pragma GCC diagnostic pop - #endif - -public: - - /** change the node's position in the parent */ - void move(id_type node, id_type after); - - /** change the node's parent and position */ - void move(id_type node, id_type new_parent, id_type after); - - /** change the node's parent and position to a different tree - * @return the index of the new node in the destination tree */ - id_type move(Tree * src, id_type node, id_type new_parent, id_type after); - - /** ensure the first node is a stream. Eg, change this tree - * - * DOCMAP - * MAP - * KEYVAL - * KEYVAL - * SEQ - * VAL - * - * to - * - * STREAM - * DOCMAP - * MAP - * KEYVAL - * KEYVAL - * SEQ - * VAL - * - * If the root is already a stream, this is a no-op. - */ - void set_root_as_stream(); - -public: - - /** recursively duplicate a node from this tree into a new parent, - * placing it after one of its children - * @return the index of the copy */ - id_type duplicate(id_type node, id_type new_parent, id_type after); - /** recursively duplicate a node from a different tree into a new parent, - * placing it after one of its children - * @return the index of the copy */ - id_type duplicate(Tree const* src, id_type node, id_type new_parent, id_type after); - - /** recursively duplicate the node's children (but not the node) - * @return the index of the last duplicated child */ - id_type duplicate_children(id_type node, id_type parent, id_type after); - /** recursively duplicate the node's children (but not the node), where - * the node is from a different tree - * @return the index of the last duplicated child */ - id_type duplicate_children(Tree const* src, id_type node, id_type parent, id_type after); - - /** duplicate the node's children (but not the node) in a new parent, but - * omit repetitions where a duplicated node has the same key (in maps) or - * value (in seqs). If one of the duplicated children has the same key - * (in maps) or value (in seqs) as one of the parent's children, the one - * that is placed closest to the end will prevail. */ - id_type duplicate_children_no_rep(id_type node, id_type parent, id_type after); - id_type duplicate_children_no_rep(Tree const* src, id_type node, id_type parent, id_type after); - - void duplicate_contents(id_type node, id_type where); - void duplicate_contents(Tree const* src, id_type node, id_type where); - -public: - - void merge_with(Tree const* src, id_type src_node=NONE, id_type dst_root=NONE); - - /** @} */ - -public: - - /** @name locations */ - /** @{ */ - - /** Get the location of a node from the parse used to parse this tree. */ - Location location(Parser const& p, id_type node) const; - -private: - - bool _location_from_node(Parser const& p, id_type node, Location *C4_RESTRICT loc, id_type level) const; - bool _location_from_cont(Parser const& p, id_type node, Location *C4_RESTRICT loc) const; - - /** @} */ - -public: - - /** @name internal string arena */ - /** @{ */ - - /** get the current size of the tree's internal arena */ - RYML_DEPRECATED("use arena_size() instead") size_t arena_pos() const { return m_arena_pos; } - /** get the current size of the tree's internal arena */ - size_t arena_size() const { return m_arena_pos; } - /** get the current capacity of the tree's internal arena */ - size_t arena_capacity() const { return m_arena.len; } - /** get the current slack of the tree's internal arena */ - size_t arena_slack() const { _RYML_CB_ASSERT(m_callbacks, m_arena.len >= m_arena_pos); return m_arena.len - m_arena_pos; } - - /** get the current arena */ - csubstr arena() const { return m_arena.first(m_arena_pos); } - /** get the current arena */ - substr arena() { return m_arena.first(m_arena_pos); } // NOLINT(readability-make-member-function-const) - - /** return true if the given substring is part of the tree's string arena */ - bool in_arena(csubstr s) const - { - return m_arena.is_super(s); - } - - /** serialize the given floating-point variable to the tree's - * arena, growing it as needed to accomodate the serialization. - * - * @note Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual - * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this - * cost, ensure that the arena is reserved to an appropriate size - * using @ref Tree::reserve_arena(). - * - * @see alloc_arena() */ - template - auto to_arena(T const& C4_RESTRICT a) - -> typename std::enable_if::value, csubstr>::type - { - substr rem(m_arena.sub(m_arena_pos)); - size_t num = to_chars_float(rem, a); - if(num > rem.len) - { - rem = _grow_arena(num); - num = to_chars_float(rem, a); - _RYML_CB_ASSERT(m_callbacks, num <= rem.len); - } - rem = _request_span(num); - return rem; - } - - /** serialize the given non-floating-point variable to the tree's - * arena, growing it as needed to accomodate the serialization. - * - * @note Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual - * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this - * cost, ensure that the arena is reserved to an appropriate size - * using @ref Tree::reserve_arena(). - * - * @see alloc_arena() */ - template - auto to_arena(T const& C4_RESTRICT a) - -> typename std::enable_if::value, csubstr>::type - { - substr rem(m_arena.sub(m_arena_pos)); - size_t num = to_chars(rem, a); - if(num > rem.len) - { - rem = _grow_arena(num); - num = to_chars(rem, a); - _RYML_CB_ASSERT(m_callbacks, num <= rem.len); - } - rem = _request_span(num); - return rem; - } - - /** serialize the given csubstr to the tree's arena, growing the - * arena as needed to accomodate the serialization. - * - * @note Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual - * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this - * cost, ensure that the arena is reserved to an appropriate size - * using @ref Tree::reserve_arena(). - * - * @see alloc_arena() */ - csubstr to_arena(csubstr a) - { - if(a.len > 0) - { - substr rem(m_arena.sub(m_arena_pos)); - size_t num = to_chars(rem, a); - if(num > rem.len) - { - rem = _grow_arena(num); - num = to_chars(rem, a); - _RYML_CB_ASSERT(m_callbacks, num <= rem.len); - } - return _request_span(num); - } - else - { - if(a.str == nullptr) - { - return csubstr{}; - } - else if(m_arena.str == nullptr) - { - // Arena is empty and we want to store a non-null - // zero-length string. - // Even though the string has zero length, we need - // some "memory" to store a non-nullptr string - _grow_arena(1); - } - return _request_span(0); - } - } - C4_ALWAYS_INLINE csubstr to_arena(const char *s) - { - return to_arena(to_csubstr(s)); - } - C4_ALWAYS_INLINE static csubstr to_arena(std::nullptr_t) - { - return csubstr{}; - } - - /** copy the given substr to the tree's arena, growing it by the - * required size - * - * @note Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual - * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this - * cost, ensure that the arena is reserved to an appropriate size - * before using @ref Tree::reserve_arena() - * - * @see reserve_arena() - * @see alloc_arena() - */ - substr copy_to_arena(csubstr s) - { - substr cp = alloc_arena(s.len); - _RYML_CB_ASSERT(m_callbacks, cp.len == s.len); - _RYML_CB_ASSERT(m_callbacks, !s.overlaps(cp)); - #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10) - C4_SUPPRESS_WARNING_GCC_PUSH - C4_SUPPRESS_WARNING_GCC("-Wstringop-overflow=") // no need for terminating \0 - C4_SUPPRESS_WARNING_GCC("-Wrestrict") // there's an assert to ensure no violation of restrict behavior - #endif - if(s.len) - memcpy(cp.str, s.str, s.len); - #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10) - C4_SUPPRESS_WARNING_GCC_POP - #endif - return cp; - } - - /** grow the tree's string arena by the given size and return a substr - * of the added portion - * - * @note Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual - * nodes, and thus cost O(numnodes)+O(arenasize). To avoid this - * cost, ensure that the arena is reserved to an appropriate size - * using .reserve_arena(). - * - * @see reserve_arena() */ - substr alloc_arena(size_t sz) - { - if(sz > arena_slack()) - _grow_arena(sz - arena_slack()); - substr s = _request_span(sz); - return s; - } - - /** ensure the tree's internal string arena is at least the given capacity - * @warning This operation may be expensive, with a potential complexity of O(numNodes)+O(arenasize). - * @warning Growing the arena may cause relocation of the entire - * existing arena, and thus change the contents of individual nodes. */ - void reserve_arena(size_t arena_cap) - { - if(arena_cap > m_arena.len) - { - substr buf; - buf.str = (char*) m_callbacks.m_allocate(arena_cap, m_arena.str, m_callbacks.m_user_data); - buf.len = arena_cap; - if(m_arena.str) - { - _RYML_CB_ASSERT(m_callbacks, m_arena.len >= 0); - _relocate(buf); // does a memcpy and changes nodes using the arena - m_callbacks.m_free(m_arena.str, m_arena.len, m_callbacks.m_user_data); - } - m_arena = buf; - } - } - - /** @} */ - -private: - - substr _grow_arena(size_t more) - { - size_t cap = m_arena.len + more; - cap = cap < 2 * m_arena.len ? 2 * m_arena.len : cap; - cap = cap < 64 ? 64 : cap; - reserve_arena(cap); - return m_arena.sub(m_arena_pos); - } - - substr _request_span(size_t sz) - { - _RYML_CB_ASSERT(m_callbacks, m_arena_pos + sz <= m_arena.len); - substr s; - s = m_arena.sub(m_arena_pos, sz); - m_arena_pos += sz; - return s; - } - - substr _relocated(csubstr s, substr next_arena) const - { - _RYML_CB_ASSERT(m_callbacks, m_arena.is_super(s)); - _RYML_CB_ASSERT(m_callbacks, m_arena.sub(0, m_arena_pos).is_super(s)); - auto pos = (s.str - m_arena.str); // this is larger than 0 based on the assertions above - substr r(next_arena.str + pos, s.len); - _RYML_CB_ASSERT(m_callbacks, r.str - next_arena.str == pos); - _RYML_CB_ASSERT(m_callbacks, next_arena.sub(0, m_arena_pos).is_super(r)); - return r; - } - -public: - - /** @name lookup */ - /** @{ */ - - struct lookup_result - { - id_type target; - id_type closest; - size_t path_pos; - csubstr path; - - operator bool() const { return target != NONE; } - - lookup_result() : target(NONE), closest(NONE), path_pos(0), path() {} - lookup_result(csubstr path_, id_type start) : target(NONE), closest(start), path_pos(0), path(path_) {} - - /** get the part ot the input path that was resolved */ - csubstr resolved() const; - /** get the part ot the input path that was unresolved */ - csubstr unresolved() const; - }; - - /** for example foo.bar[0].baz */ - lookup_result lookup_path(csubstr path, id_type start=NONE) const; - - /** defaulted lookup: lookup @p path; if the lookup fails, recursively modify - * the tree so that the corresponding lookup_path() would return the - * default value. - * @see lookup_path() */ - id_type lookup_path_or_modify(csubstr default_value, csubstr path, id_type start=NONE); - - /** defaulted lookup: lookup @p path; if the lookup fails, recursively modify - * the tree so that the corresponding lookup_path() would return the - * branch @p src_node (from the tree @p src). - * @see lookup_path() */ - id_type lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start=NONE); - - /** @} */ - -private: - - struct _lookup_path_token - { - csubstr value; - NodeType type; - _lookup_path_token() : value(), type() {} - _lookup_path_token(csubstr v, NodeType t) : value(v), type(t) {} - operator bool() const { return type != NOTYPE; } - bool is_index() const { return value.begins_with('[') && value.ends_with(']'); } - }; - - id_type _lookup_path_or_create(csubstr path, id_type start); - - void _lookup_path (lookup_result *r) const; - void _lookup_path_modify(lookup_result *r); - - id_type _next_node (lookup_result *r, _lookup_path_token *parent) const; - id_type _next_node_modify(lookup_result *r, _lookup_path_token *parent); - - static void _advance(lookup_result *r, size_t more); - - _lookup_path_token _next_token(lookup_result *r, _lookup_path_token const& parent) const; - -private: - - void _clear(); - void _free(); - void _copy(Tree const& that); - void _move(Tree & that) noexcept; - - void _relocate(substr next_arena); - -public: - - /** @cond dev*/ - - #if ! RYML_USE_ASSERT - C4_ALWAYS_INLINE void _check_next_flags(id_type, type_bits) {} - #else - void _check_next_flags(id_type node, type_bits f) - { - NodeData *n = _p(node); - type_bits o = n->m_type; // old - C4_UNUSED(o); - if(f & MAP) - { - RYML_ASSERT_MSG((f & SEQ) == 0, "cannot mark simultaneously as map and seq"); - RYML_ASSERT_MSG((f & VAL) == 0, "cannot mark simultaneously as map and val"); - RYML_ASSERT_MSG((o & SEQ) == 0, "cannot turn a seq into a map; clear first"); - RYML_ASSERT_MSG((o & VAL) == 0, "cannot turn a val into a map; clear first"); - } - else if(f & SEQ) - { - RYML_ASSERT_MSG((f & MAP) == 0, "cannot mark simultaneously as seq and map"); - RYML_ASSERT_MSG((f & VAL) == 0, "cannot mark simultaneously as seq and val"); - RYML_ASSERT_MSG((o & MAP) == 0, "cannot turn a map into a seq; clear first"); - RYML_ASSERT_MSG((o & VAL) == 0, "cannot turn a val into a seq; clear first"); - } - if(f & KEY) - { - _RYML_CB_ASSERT(m_callbacks, !is_root(node)); - auto pid = parent(node); C4_UNUSED(pid); - _RYML_CB_ASSERT(m_callbacks, is_map(pid)); - } - if((f & VAL) && !is_root(node)) - { - auto pid = parent(node); C4_UNUSED(pid); - _RYML_CB_ASSERT(m_callbacks, is_map(pid) || is_seq(pid)); - } - } - #endif - - void _set_flags(id_type node, NodeType_e f) { _check_next_flags(node, f); _p(node)->m_type = f; } - void _set_flags(id_type node, type_bits f) { _check_next_flags(node, f); _p(node)->m_type = f; } - - void _add_flags(id_type node, NodeType_e f) { NodeData *d = _p(node); type_bits fb = f | d->m_type; _check_next_flags(node, fb); d->m_type = (NodeType_e) fb; } - void _add_flags(id_type node, type_bits f) { NodeData *d = _p(node); f |= d->m_type; _check_next_flags(node, f); d->m_type = f; } - - void _rem_flags(id_type node, NodeType_e f) { NodeData *d = _p(node); type_bits fb = d->m_type & ~f; _check_next_flags(node, fb); d->m_type = (NodeType_e) fb; } - void _rem_flags(id_type node, type_bits f) { NodeData *d = _p(node); f = d->m_type & ~f; _check_next_flags(node, f); d->m_type = f; } - - void _set_key(id_type node, csubstr key, type_bits more_flags=0) - { - _p(node)->m_key.scalar = key; - _add_flags(node, KEY|more_flags); - } - void _set_key(id_type node, NodeScalar const& key, type_bits more_flags=0) - { - _p(node)->m_key = key; - _add_flags(node, KEY|more_flags); - } - - void _set_val(id_type node, csubstr val, type_bits more_flags=0) - { - _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0); - _RYML_CB_ASSERT(m_callbacks, !is_seq(node) && !is_map(node)); - _p(node)->m_val.scalar = val; - _add_flags(node, VAL|more_flags); - } - void _set_val(id_type node, NodeScalar const& val, type_bits more_flags=0) - { - _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0); - _RYML_CB_ASSERT(m_callbacks, ! is_container(node)); - _p(node)->m_val = val; - _add_flags(node, VAL|more_flags); - } - - void _set(id_type node, NodeInit const& i) - { - _RYML_CB_ASSERT(m_callbacks, i._check()); - NodeData *n = _p(node); - _RYML_CB_ASSERT(m_callbacks, n->m_key.scalar.empty() || i.key.scalar.empty() || i.key.scalar == n->m_key.scalar); - _add_flags(node, i.type); - if(n->m_key.scalar.empty()) - { - if( ! i.key.scalar.empty()) - { - _set_key(node, i.key.scalar); - } - } - n->m_key.tag = i.key.tag; - n->m_val = i.val; - } - - void _set_parent_as_container_if_needed(id_type in) - { - NodeData const* n = _p(in); - id_type ip = parent(in); - if(ip != NONE) - { - if( ! (is_seq(ip) || is_map(ip))) - { - if((in == first_child(ip)) && (in == last_child(ip))) - { - if( ! n->m_key.empty() || has_key(in)) - { - _add_flags(ip, MAP); - } - else - { - _add_flags(ip, SEQ); - } - } - } - } - } - - void _seq2map(id_type node) - { - _RYML_CB_ASSERT(m_callbacks, is_seq(node)); - for(id_type i = first_child(node); i != NONE; i = next_sibling(i)) - { - NodeData *C4_RESTRICT ch = _p(i); - if(ch->m_type.is_keyval()) - continue; - ch->m_type.add(KEY); - ch->m_key = ch->m_val; - } - auto *C4_RESTRICT n = _p(node); - n->m_type.rem(SEQ); - n->m_type.add(MAP); - } - - id_type _do_reorder(id_type *node, id_type count); - - void _swap(id_type n_, id_type m_); - void _swap_props(id_type n_, id_type m_); - void _swap_hierarchy(id_type n_, id_type m_); - void _copy_hierarchy(id_type dst_, id_type src_); - - void _copy_props(id_type dst_, id_type src_) - { - _copy_props(dst_, this, src_); - } - - void _copy_props_wo_key(id_type dst_, id_type src_) - { - _copy_props_wo_key(dst_, this, src_); - } - - void _copy_props(id_type dst_, Tree const* that_tree, id_type src_) - { - auto & C4_RESTRICT dst = *_p(dst_); - auto const& C4_RESTRICT src = *that_tree->_p(src_); - dst.m_type = src.m_type; - dst.m_key = src.m_key; - dst.m_val = src.m_val; - } - - void _copy_props(id_type dst_, Tree const* that_tree, id_type src_, type_bits src_mask) - { - auto & C4_RESTRICT dst = *_p(dst_); - auto const& C4_RESTRICT src = *that_tree->_p(src_); - dst.m_type = (src.m_type & src_mask) | (dst.m_type & ~src_mask); - dst.m_key = src.m_key; - dst.m_val = src.m_val; - } - - void _copy_props_wo_key(id_type dst_, Tree const* that_tree, id_type src_) - { - auto & C4_RESTRICT dst = *_p(dst_); - auto const& C4_RESTRICT src = *that_tree->_p(src_); - dst.m_type = (src.m_type & ~_KEYMASK) | (dst.m_type & _KEYMASK); - dst.m_val = src.m_val; - } - - void _copy_props_wo_key(id_type dst_, Tree const* that_tree, id_type src_, type_bits src_mask) - { - auto & C4_RESTRICT dst = *_p(dst_); - auto const& C4_RESTRICT src = *that_tree->_p(src_); - dst.m_type = (src.m_type & ((~_KEYMASK)|src_mask)) | (dst.m_type & (_KEYMASK|~src_mask)); - dst.m_val = src.m_val; - } - - void _clear_type(id_type node) - { - _p(node)->m_type = NOTYPE; - } - - void _clear(id_type node) - { - auto *C4_RESTRICT n = _p(node); - n->m_type = NOTYPE; - n->m_key.clear(); - n->m_val.clear(); - n->m_parent = NONE; - n->m_first_child = NONE; - n->m_last_child = NONE; - } - - void _clear_key(id_type node) - { - _p(node)->m_key.clear(); - _rem_flags(node, KEY); - } - - void _clear_val(id_type node) - { - _p(node)->m_val.clear(); - _rem_flags(node, VAL); - } - - /** @endcond */ - -private: - - void _clear_range(id_type first, id_type num); - -public: - id_type _claim(); -private: - void _claim_root(); - void _release(id_type node); - void _free_list_add(id_type node); - void _free_list_rem(id_type node); - - void _set_hierarchy(id_type node, id_type parent, id_type after_sibling); - void _rem_hierarchy(id_type node); - -public: - - // members are exposed, but you should NOT access them directly - - NodeData *m_buf; - id_type m_cap; - - id_type m_size; - - id_type m_free_head; - id_type m_free_tail; - - substr m_arena; - size_t m_arena_pos; - - Callbacks m_callbacks; - - TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES]; - -}; - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -/** @defgroup doc_serialization_helpers Serialization helpers - * - * @{ - */ - - -// NON-ARITHMETIC ------------------------------------------------------------- - -/** convert the val of a scalar node to a particular non-arithmetic - * non-float type, by forwarding its val to @ref from_chars(). The - * full string is used. - * @return false if the conversion failed, or if the key was empty and unquoted */ -template -inline auto read(Tree const* C4_RESTRICT tree, id_type id, T *v) - -> typename std::enable_if::value, bool>::type -{ - return C4_LIKELY(!(tree->type(id) & VALNIL)) ? from_chars(tree->val(id), v) : false; -} - -/** convert the key of a node to a particular non-arithmetic - * non-float type, by forwarding its key to @ref from_chars(). The - * full string is used. - * @return false if the conversion failed, or if the key was empty and unquoted */ -template -inline auto readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) - -> typename std::enable_if::value, bool>::type -{ - return C4_LIKELY(!(tree->type(id) & KEYNIL)) ? from_chars(tree->key(id), v) : false; -} - - -// INTEGRAL, NOT FLOATING ------------------------------------------------------------- - -/** convert the val of a scalar node to a particular arithmetic - * integral non-float type, by forwarding its val to @ref - * from_chars(). The full string is used. - * - * @return false if the conversion failed */ -template -inline auto read(Tree const* C4_RESTRICT tree, id_type id, T *v) - -> typename std::enable_if::value && !std::is_floating_point::value, bool>::type -{ - using U = typename std::remove_cv::type; - enum { ischar = std::is_same::value || std::is_same::value || std::is_same::value }; - csubstr val = tree->val(id); - NodeType ty = tree->type(id); - if(C4_UNLIKELY((ty & VALNIL) || val.empty())) - return false; - // quote integral numbers if they have a leading 0 - // https://github.com/biojppm/rapidyaml/issues/291 - char first = val[0]; - if(ty.is_val_quoted() && (first != '0' && !ischar)) - return false; - else if(first == '+') - val = val.sub(1); - return from_chars(val, v); -} - -/** convert the key of a node to a particular arithmetic - * integral non-float type, by forwarding its val to @ref - * from_chars(). The full string is used. - * - * @return false if the conversion failed */ -template -inline auto readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) - -> typename std::enable_if::value && !std::is_floating_point::value, bool>::type -{ - using U = typename std::remove_cv::type; - enum { ischar = std::is_same::value || std::is_same::value || std::is_same::value }; - csubstr key = tree->key(id); - NodeType ty = tree->type(id); - if((ty & KEYNIL) || key.empty()) - return false; - // quote integral numbers if they have a leading 0 - // https://github.com/biojppm/rapidyaml/issues/291 - char first = key[0]; - if(ty.is_key_quoted() && (first != '0' && !ischar)) - return false; - else if(first == '+') - key = key.sub(1); - return from_chars(key, v); -} - - -// FLOATING ------------------------------------------------------------- - -/** encode a floating point value to a string. */ -template -size_t to_chars_float(substr buf, T val) -{ - static_assert(std::is_floating_point::value, "must be floating point"); - C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wfloat-equal"); - if(C4_UNLIKELY(std::isnan(val))) - return to_chars(buf, csubstr(".nan")); - else if(C4_UNLIKELY(val == std::numeric_limits::infinity())) - return to_chars(buf, csubstr(".inf")); - else if(C4_UNLIKELY(val == -std::numeric_limits::infinity())) - return to_chars(buf, csubstr("-.inf")); - return to_chars(buf, val); - C4_SUPPRESS_WARNING_GCC_CLANG_POP -} - - -/** decode a floating point from string. Accepts special values: .nan, - * .inf, -.inf */ -template -bool from_chars_float(csubstr buf, T *C4_RESTRICT val) -{ - static_assert(std::is_floating_point::value, "must be floating point"); - if(buf.begins_with('+')) - { - buf = buf.sub(1); - } - if(C4_LIKELY(from_chars(buf, val))) - { - return true; - } - else if(C4_UNLIKELY(buf == ".nan" || buf == ".NaN" || buf == ".NAN")) - { - *val = std::numeric_limits::quiet_NaN(); - return true; - } - else if(C4_UNLIKELY(buf == ".inf" || buf == ".Inf" || buf == ".INF")) - { - *val = std::numeric_limits::infinity(); - return true; - } - else if(C4_UNLIKELY(buf == "-.inf" || buf == "-.Inf" || buf == "-.INF")) - { - *val = -std::numeric_limits::infinity(); - return true; - } - else - { - return false; - } -} - -/** convert the val of a scalar node to a floating point type, by - * forwarding its val to @ref from_chars_float(). - * - * @return false if the conversion failed - * - * @warning Unlike non-floating types, only the leading part of the - * string that may constitute a number is processed. This happens - * because the float parsing is delegated to fast_float, which is - * implemented that way. Consequently, for example, all of `"34"`, - * `"34 "` `"34hg"` `"34 gh"` will be read as 34. If you are not sure - * about the contents of the data, you can use - * csubstr::first_real_span() to check before calling `>>`, for - * example like this: - * - * ```cpp - * csubstr val = node.val(); - * if(val.first_real_span() == val) - * node >> v; - * else - * ERROR("not a real") - * ``` - */ -template -typename std::enable_if::value, bool>::type -inline read(Tree const* C4_RESTRICT tree, id_type id, T *v) -{ - csubstr val = tree->val(id); - return C4_LIKELY(!val.empty()) ? from_chars_float(val, v) : false; -} - -/** convert the key of a scalar node to a floating point type, by - * forwarding its key to @ref from_chars_float(). - * - * @return false if the conversion failed - * - * @warning Unlike non-floating types, only the leading part of the - * string that may constitute a number is processed. This happens - * because the float parsing is delegated to fast_float, which is - * implemented that way. Consequently, for example, all of `"34"`, - * `"34 "` `"34hg"` `"34 gh"` will be read as 34. If you are not sure - * about the contents of the data, you can use - * csubstr::first_real_span() to check before calling `>>`, for - * example like this: - * - * ```cpp - * csubstr key = node.key(); - * if(key.first_real_span() == key) - * node >> v; - * else - * ERROR("not a real") - * ``` - */ -template -typename std::enable_if::value, bool>::type -inline readkey(Tree const* C4_RESTRICT tree, id_type id, T *v) -{ - csubstr key = tree->key(id); - return C4_LIKELY(!key.empty()) ? from_chars_float(key, v) : false; -} - -/** @} */ - -/** @} */ - - -} // namespace yml -} // namespace c4 - - -C4_SUPPRESS_WARNING_MSVC_POP -C4_SUPPRESS_WARNING_GCC_CLANG_POP - - -#endif /* _C4_YML_TREE_HPP_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/version.hpp b/3rdparty/rapidyaml/include/c4/yml/version.hpp deleted file mode 100644 index a6c3df310e..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/version.hpp +++ /dev/null @@ -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 -#include - -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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/writer.hpp b/3rdparty/rapidyaml/include/c4/yml/writer.hpp deleted file mode 100644 index 3506f079a7..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/writer.hpp +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef _C4_YML_WRITER_HPP_ -#define _C4_YML_WRITER_HPP_ - -#ifndef _C4_YML_COMMON_HPP_ -#include "./common.hpp" -#endif - -#include -#include // fwrite(), fputc() -#include // 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 - 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 -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 - 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 - 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_ */ diff --git a/3rdparty/rapidyaml/include/c4/yml/yml.hpp b/3rdparty/rapidyaml/include/c4/yml/yml.hpp deleted file mode 100644 index 0f997246b7..0000000000 --- a/3rdparty/rapidyaml/include/c4/yml/yml.hpp +++ /dev/null @@ -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_ diff --git a/3rdparty/rapidyaml/include/ryml-gdbtypes.py b/3rdparty/rapidyaml/include/ryml-gdbtypes.py deleted file mode 100644 index 2625a6ccde..0000000000 --- a/3rdparty/rapidyaml/include/ryml-gdbtypes.py +++ /dev/null @@ -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 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 = "!!!!!!!!!!" - 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) diff --git a/3rdparty/rapidyaml/include/ryml.hpp b/3rdparty/rapidyaml/include/ryml.hpp deleted file mode 100644 index c2b3e74b23..0000000000 --- a/3rdparty/rapidyaml/include/ryml.hpp +++ /dev/null @@ -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_ */ diff --git a/3rdparty/rapidyaml/include/ryml.natvis b/3rdparty/rapidyaml/include/ryml.natvis deleted file mode 100644 index cb0827546a..0000000000 --- a/3rdparty/rapidyaml/include/ryml.natvis +++ /dev/null @@ -1,304 +0,0 @@ - - - - - - - - {scalar.str,[scalar.len]} - {scalar.str,[scalar.len]} [T] - {scalar.str,[scalar.len]} [A] - {scalar.str,[scalar.len]} [T][A] - - scalar - tag - anchor - - - - - [KEYVAL] - [KEYSEQ] - [KEYMAP] - [DOCVAL] - [DOCSEQ] - [DOCMAP] - [VAL] - [KEY] - [SEQ] - [MAP] - [DOC] - [STREAM] - [NOTYPE] - - - - c4::yml::KEY - c4::yml::VAL - c4::yml::MAP - c4::yml::SEQ - c4::yml::DOC - c4::yml::STREAM - c4::yml::KEYREF - c4::yml::VALREF - c4::yml::KEYANCH - c4::yml::VALANCH - c4::yml::KEYTAG - c4::yml::VALTAG - - - - - c4::yml::_WIP_KEY_UNFILT - c4::yml::_WIP_VAL_UNFILT - c4::yml::_WIP_STYLE_FLOW - c4::yml::_WIP_STYLE_FLOW - c4::yml::_WIP_STYLE_BLOCK - c4::yml::_WIP_KEY_LITERAL - c4::yml::_WIP_VAL_LITERAL - c4::yml::_WIP_KEY_FOLDED - c4::yml::_WIP_VAL_FOLDED - c4::yml::_WIP_KEY_SQUO - c4::yml::_WIP_VAL_SQUO - c4::yml::_WIP_KEY_DQUO - c4::yml::_WIP_VAL_DQUO - c4::yml::_WIP_KEY_PLAIN - c4::yml::_WIP_VAL_PLAIN - - - - - - - [KEYVAL] {m_key.scalar.str,[m_key.scalar.len]}: {m_val.scalar.str,[m_val.scalar.len]} - [KEYSEQ] {m_key.scalar.str,[m_key.scalar.len]} - [KEYMAP] {m_key.scalar.str,[m_key.scalar.len]} - [DOCSEQ] - [DOCMAP] - [VAL] {m_val.scalar.str,[m_val.scalar.len]} - [KEY] {m_key.scalar.str,[m_key.scalar.len]} - [SEQ] - [MAP] - [DOC] - [STREAM] - [NOTYPE] - - m_type - m_key - m_val - c4::yml::KEYQUO - c4::yml::VALQUO - m_key.anchor - m_val.anchor - m_key.anchor - m_val.anchor - NONE - m_parent - m_first_child - m_last_child - m_prev_sibling - m_next_sibling - - - - - sz={m_size}, cap={m_cap} - - m_size - m_cap - - - - m_cap - m_buf - - - - m_free_head - m_arena - - - - - {value} ({type}) - - value - type - - - - - {path} -- target={target} closest={closest} - - target - closest - path_pos - path - - {path.str,[path_pos]} - - - {path.str+path_pos,[path.len-path_pos]} - - - - - - (void) - [INDEX SEED for] {*(m_tree->m_buf + m_id)} - [NAMED SEED for] {*(m_tree->m_buf + m_id)} - {*(m_tree->m_buf + m_id)} - - m_id - *(m_tree->m_buf + m_id) - m_tree - - - - - - - - buf + curr - curr = (buf + curr)->m_next_sibling - - - - - - - - - - (void) - {*(m_tree->m_buf + m_id)} - - m_id - *(m_tree->m_buf + m_id) - m_tree - - - - - - - - buf + curr - curr = (buf + curr)->m_next_sibling - - - - - - - - - - #refs={refs.m_size} #nodes={t->m_size} - - - - - - - t->m_buf + (refs.m_stack + curr)->node - curr = curr+1 - - - - - - - - - refs.m_size - refs.m_stack - - - - t - - - - - sz={m_size} cap={m_capacity} - - m_size - m_capacity - m_buf == m_stack - - - - m_size - m_stack - - - - - - - - src={src.str,[rpos]} dst={dst.str,[wpos]} - - src - dst - rpos - wpos - - src.str,[rpos] - - - rpos - src.str - - - - - - - - src={src.str,[rpos]} dst={src.str,[wpos]} - - rpos - wpos - wcap - - src.str,[wcap] - - - wcap - src.str - - - - src - - src.str+rpos,[src.len-rpos] - - src.len-rpossrc.str+rpos - - - - src.str,[rpos] - - rpossrc.str - - - - src.str,[wpos] - - wpossrc.str - - - - - - diff --git a/3rdparty/rapidyaml/include/ryml_std.hpp b/3rdparty/rapidyaml/include/ryml_std.hpp deleted file mode 100644 index 5e81439ac6..0000000000 --- a/3rdparty/rapidyaml/include/ryml_std.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _RYML_STD_HPP_ -#define _RYML_STD_HPP_ - -#include "./c4/yml/std/std.hpp" - -#endif /* _RYML_STD_HPP_ */ diff --git a/3rdparty/rapidyaml/rapidyaml.vcxproj b/3rdparty/rapidyaml/rapidyaml.vcxproj deleted file mode 100644 index 502da175e3..0000000000 --- a/3rdparty/rapidyaml/rapidyaml.vcxproj +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - {DE9653B6-17DD-356A-9EE0-28A731772587} - Win32Proj - rapidyaml - - - - StaticLibrary - $(DefaultPlatformToolset) - ClangCL - MultiByte - true - true - false - - - - - - - - - - - - - - AllRules.ruleset - - - - %(PreprocessorDefinitions);C4_NO_DEBUG_BREAK - TurnOffAllWarnings - %(AdditionalIncludeDirectories);$(ProjectDir)src;$(ProjectDir)include;$(ProjectDir)..\fast_float\include - stdcpp17 - - - - - %(PreprocessorDefinitions);WIN32;_WINDOWS - - - - - %(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/3rdparty/rapidyaml/src/c4/base64.cpp b/3rdparty/rapidyaml/src/c4/base64.cpp deleted file mode 100644 index b30ca64e7f..0000000000 --- a/3rdparty/rapidyaml/src/c4/base64.cpp +++ /dev/null @@ -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(c); } ++wpos; } - #define c4appendval_(c, shift)\ - {\ - C4_XASSERT((c) >= 0);\ - C4_XASSERT(size_t(c) < sizeof(detail::base64_char_to_sextet_));\ - val |= static_cast(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 diff --git a/3rdparty/rapidyaml/src/c4/error.cpp b/3rdparty/rapidyaml/src/c4/error.cpp deleted file mode 100644 index 94954ffedb..0000000000 --- a/3rdparty/rapidyaml/src/c4/error.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "c4/error.hpp" - -#include -#include -#include - -#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 -#elif defined(C4_UNIX) || defined(C4_LINUX) -# include -# include -# include -#elif defined(C4_MACOS) || defined(C4_IOS) -# include -# include -# include -# include -#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 -#endif - -#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION) -# include -#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(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 diff --git a/3rdparty/rapidyaml/src/c4/format.cpp b/3rdparty/rapidyaml/src/c4/format.cpp deleted file mode 100644 index fc994781f4..0000000000 --- a/3rdparty/rapidyaml/src/c4/format.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "c4/format.hpp" - -#include // 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(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 diff --git a/3rdparty/rapidyaml/src/c4/language.cpp b/3rdparty/rapidyaml/src/c4/language.cpp deleted file mode 100644 index d1b5697412..0000000000 --- a/3rdparty/rapidyaml/src/c4/language.cpp +++ /dev/null @@ -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 diff --git a/3rdparty/rapidyaml/src/c4/memory_util.cpp b/3rdparty/rapidyaml/src/c4/memory_util.cpp deleted file mode 100644 index 8e32330283..0000000000 --- a/3rdparty/rapidyaml/src/c4/memory_util.cpp +++ /dev/null @@ -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(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(end - (begin + n))); - } -} - - -} // namespace c4 diff --git a/3rdparty/rapidyaml/src/c4/utf.cpp b/3rdparty/rapidyaml/src/c4/utf.cpp deleted file mode 100644 index 797be3247c..0000000000 --- a/3rdparty/rapidyaml/src/c4/utf.cpp +++ /dev/null @@ -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 diff --git a/3rdparty/rapidyaml/src/c4/yml/common.cpp b/3rdparty/rapidyaml/src/c4/yml/common.cpp deleted file mode 100644 index 0c968a2e82..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/common.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "c4/yml/common.hpp" - -#ifndef RYML_NO_DEFAULT_CALLBACKS -# include -# include -# ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS -# include -# 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 diff --git a/3rdparty/rapidyaml/src/c4/yml/node.cpp b/3rdparty/rapidyaml/src/c4/yml/node.cpp deleted file mode 100644 index 50c7a0b60b..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/node.cpp +++ /dev/null @@ -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 diff --git a/3rdparty/rapidyaml/src/c4/yml/node_type.cpp b/3rdparty/rapidyaml/src/c4/yml/node_type.cpp deleted file mode 100644 index c31fee9b3e..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/node_type.cpp +++ /dev/null @@ -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 diff --git a/3rdparty/rapidyaml/src/c4/yml/parse.cpp b/3rdparty/rapidyaml/src/c4/yml/parse.cpp deleted file mode 100644 index 4f5622ff6f..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/parse.cpp +++ /dev/null @@ -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; - -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 diff --git a/3rdparty/rapidyaml/src/c4/yml/preprocess.cpp b/3rdparty/rapidyaml/src/c4/yml/preprocess.cpp deleted file mode 100644 index e45abb8569..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/preprocess.cpp +++ /dev/null @@ -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(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(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 diff --git a/3rdparty/rapidyaml/src/c4/yml/reference_resolver.cpp b/3rdparty/rapidyaml/src/c4/yml/reference_resolver.cpp deleted file mode 100644 index 9ce9c57d70..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/reference_resolver.cpp +++ /dev/null @@ -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(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 diff --git a/3rdparty/rapidyaml/src/c4/yml/tag.cpp b/3rdparty/rapidyaml/src/c4/yml/tag.cpp deleted file mode 100644 index ba5dbf14a4..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/tag.cpp +++ /dev/null @@ -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("'; - 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(""}; - case TAG_OMAP: - return {""}; - case TAG_PAIRS: - return {""}; - case TAG_SET: - return {""}; - case TAG_SEQ: - return {""}; - case TAG_BINARY: - return {""}; - case TAG_BOOL: - return {""}; - case TAG_FLOAT: - return {""}; - case TAG_INT: - return {""}; - case TAG_MERGE: - return {""}; - case TAG_NULL: - return {""}; - case TAG_STR: - return {""}; - case TAG_TIMESTAMP: - return {""}; - case TAG_VALUE: - return {""}; - case TAG_YAML: - return {""}; - 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(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 diff --git a/3rdparty/rapidyaml/src/c4/yml/tree.cpp b/3rdparty/rapidyaml/src/c4/yml/tree.cpp deleted file mode 100644 index fb2e58bcc2..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/tree.cpp +++ /dev/null @@ -1,1978 +0,0 @@ -#include "c4/yml/tree.hpp" -#include "c4/yml/detail/dbgprint.hpp" -#include "c4/yml/node.hpp" -#include "c4/yml/reference_resolver.hpp" - - -C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/) -C4_SUPPRESS_WARNING_MSVC(4702/*unreachable code*/) -C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast") -C4_SUPPRESS_WARNING_GCC("-Wtype-limits") -C4_SUPPRESS_WARNING_GCC("-Wuseless-cast") - -namespace c4 { -namespace yml { - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -NodeRef Tree::rootref() -{ - return NodeRef(this, root_id()); -} -ConstNodeRef Tree::rootref() const -{ - return ConstNodeRef(this, root_id()); -} - -ConstNodeRef Tree::crootref() const -{ - return ConstNodeRef(this, root_id()); -} - -NodeRef Tree::ref(id_type id) -{ - _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap); - return NodeRef(this, id); -} -ConstNodeRef Tree::ref(id_type id) const -{ - _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap); - return ConstNodeRef(this, id); -} -ConstNodeRef Tree::cref(id_type id) const -{ - _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap); - return ConstNodeRef(this, id); -} - -NodeRef Tree::operator[] (csubstr key) -{ - return rootref()[key]; -} -ConstNodeRef Tree::operator[] (csubstr key) const -{ - return rootref()[key]; -} - -NodeRef Tree::operator[] (id_type i) -{ - return rootref()[i]; -} -ConstNodeRef Tree::operator[] (id_type i) const -{ - return rootref()[i]; -} - -NodeRef Tree::docref(id_type i) -{ - return ref(doc(i)); -} -ConstNodeRef Tree::docref(id_type i) const -{ - return cref(doc(i)); -} -ConstNodeRef Tree::cdocref(id_type i) const -{ - return cref(doc(i)); -} - - -//----------------------------------------------------------------------------- -Tree::Tree(Callbacks const& cb) - : m_buf(nullptr) - , m_cap(0) - , m_size(0) - , m_free_head(NONE) - , m_free_tail(NONE) - , m_arena() - , m_arena_pos(0) - , m_callbacks(cb) - , m_tag_directives() -{ -} - -Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb) - : Tree(cb) -{ - reserve(node_capacity); - reserve_arena(arena_capacity); -} - -Tree::~Tree() -{ - _free(); -} - - -Tree::Tree(Tree const& that) : Tree(that.m_callbacks) -{ - _copy(that); -} - -Tree& Tree::operator= (Tree const& that) -{ - if(&that != this) - { - _free(); - m_callbacks = that.m_callbacks; - _copy(that); - } - return *this; -} - -Tree::Tree(Tree && that) noexcept : Tree(that.m_callbacks) -{ - _move(that); -} - -Tree& Tree::operator= (Tree && that) noexcept -{ - if(&that != this) - { - _free(); - m_callbacks = that.m_callbacks; - _move(that); - } - return *this; -} - -void Tree::_free() -{ - if(m_buf) - { - _RYML_CB_ASSERT(m_callbacks, m_cap > 0); - _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap); - } - if(m_arena.str) - { - _RYML_CB_ASSERT(m_callbacks, m_arena.len > 0); - _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len); - } - _clear(); -} - - -C4_SUPPRESS_WARNING_GCC_PUSH -#if defined(__GNUC__) && __GNUC__>= 8 - C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wclass-memaccess") // error: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘class c4::yml::Tree’ with no trivial copy-assignment; use assignment or value-initialization instead -#endif - -void Tree::_clear() -{ - m_buf = nullptr; - m_cap = 0; - m_size = 0; - m_free_head = 0; - m_free_tail = 0; - m_arena = {}; - m_arena_pos = 0; - for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i) - m_tag_directives[i] = {}; -} - -void Tree::_copy(Tree const& that) -{ - _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr); - _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr); - _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0); - if(that.m_cap) - { - m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)that.m_cap, that.m_buf); - memcpy(m_buf, that.m_buf, (size_t)that.m_cap * sizeof(NodeData)); - } - m_cap = that.m_cap; - m_size = that.m_size; - m_free_head = that.m_free_head; - m_free_tail = that.m_free_tail; - m_arena_pos = that.m_arena_pos; - m_arena = that.m_arena; - if(that.m_arena.str) - { - _RYML_CB_ASSERT(m_callbacks, that.m_arena.len > 0); - substr arena; - arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str); - arena.len = that.m_arena.len; - _relocate(arena); // does a memcpy of the arena and updates nodes using the old arena - m_arena = arena; - } - for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i) - m_tag_directives[i] = that.m_tag_directives[i]; -} - -void Tree::_move(Tree & that) noexcept -{ - _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr); - _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr); - _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0); - m_buf = that.m_buf; - m_cap = that.m_cap; - m_size = that.m_size; - m_free_head = that.m_free_head; - m_free_tail = that.m_free_tail; - m_arena = that.m_arena; - m_arena_pos = that.m_arena_pos; - for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i) - m_tag_directives[i] = that.m_tag_directives[i]; - that._clear(); -} - -void Tree::_relocate(substr next_arena) -{ - _RYML_CB_ASSERT(m_callbacks, next_arena.not_empty()); - _RYML_CB_ASSERT(m_callbacks, next_arena.len >= m_arena.len); - if(m_arena_pos) - memcpy(next_arena.str, m_arena.str, m_arena_pos); - for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n) - { - if(in_arena(n->m_key.scalar)) - n->m_key.scalar = _relocated(n->m_key.scalar, next_arena); - if(in_arena(n->m_key.tag)) - n->m_key.tag = _relocated(n->m_key.tag, next_arena); - if(in_arena(n->m_key.anchor)) - n->m_key.anchor = _relocated(n->m_key.anchor, next_arena); - if(in_arena(n->m_val.scalar)) - n->m_val.scalar = _relocated(n->m_val.scalar, next_arena); - if(in_arena(n->m_val.tag)) - n->m_val.tag = _relocated(n->m_val.tag, next_arena); - if(in_arena(n->m_val.anchor)) - n->m_val.anchor = _relocated(n->m_val.anchor, next_arena); - } - for(TagDirective &C4_RESTRICT td : m_tag_directives) - { - if(in_arena(td.prefix)) - td.prefix = _relocated(td.prefix, next_arena); - if(in_arena(td.handle)) - td.handle = _relocated(td.handle, next_arena); - } -} - - -//----------------------------------------------------------------------------- -void Tree::reserve(id_type cap) -{ - if(cap > m_cap) - { - NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)cap, m_buf); - if(m_buf) - { - memcpy(buf, m_buf, (size_t)m_cap * sizeof(NodeData)); - _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap); - } - id_type first = m_cap, del = cap - m_cap; - m_cap = cap; - m_buf = buf; - _clear_range(first, del); - if(m_free_head != NONE) - { - _RYML_CB_ASSERT(m_callbacks, m_buf != nullptr); - _RYML_CB_ASSERT(m_callbacks, m_free_tail != NONE); - m_buf[m_free_tail].m_next_sibling = first; - m_buf[first].m_prev_sibling = m_free_tail; - m_free_tail = cap-1; - } - else - { - _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE); - m_free_head = first; - m_free_tail = cap-1; - } - _RYML_CB_ASSERT(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap)); - _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap)); - - if( ! m_size) - _claim_root(); - } -} - - -//----------------------------------------------------------------------------- -void Tree::clear() -{ - _clear_range(0, m_cap); - m_size = 0; - if(m_buf) - { - _RYML_CB_ASSERT(m_callbacks, m_cap >= 0); - m_free_head = 0; - m_free_tail = m_cap-1; - _claim_root(); - } - else - { - m_free_head = NONE; - m_free_tail = NONE; - } - for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i) - m_tag_directives[i] = {}; -} - -void Tree::_claim_root() -{ - id_type r = _claim(); - _RYML_CB_ASSERT(m_callbacks, r == 0); - _set_hierarchy(r, NONE, NONE); -} - - -//----------------------------------------------------------------------------- -void Tree::_clear_range(id_type first, id_type num) -{ - if(num == 0) - return; // prevent overflow when subtracting - _RYML_CB_ASSERT(m_callbacks, first >= 0 && first + num <= m_cap); - memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this - for(id_type i = first, e = first + num; i < e; ++i) - { - _clear(i); - NodeData *n = m_buf + i; - n->m_prev_sibling = i - 1; - n->m_next_sibling = i + 1; - } - m_buf[first + num - 1].m_next_sibling = NONE; -} - -C4_SUPPRESS_WARNING_GCC_POP - - -//----------------------------------------------------------------------------- -void Tree::_release(id_type i) -{ - _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap); - - _rem_hierarchy(i); - _free_list_add(i); - _clear(i); - - --m_size; -} - -//----------------------------------------------------------------------------- -// add to the front of the free list -void Tree::_free_list_add(id_type i) -{ - _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap); - NodeData &C4_RESTRICT w = m_buf[i]; - - w.m_parent = NONE; - w.m_next_sibling = m_free_head; - w.m_prev_sibling = NONE; - if(m_free_head != NONE) - m_buf[m_free_head].m_prev_sibling = i; - m_free_head = i; - if(m_free_tail == NONE) - m_free_tail = m_free_head; -} - -void Tree::_free_list_rem(id_type i) -{ - if(m_free_head == i) - m_free_head = _p(i)->m_next_sibling; - _rem_hierarchy(i); -} - -//----------------------------------------------------------------------------- -id_type Tree::_claim() -{ - if(m_free_head == NONE || m_buf == nullptr) - { - id_type sz = 2 * m_cap; - sz = sz ? sz : 16; - reserve(sz); - _RYML_CB_ASSERT(m_callbacks, m_free_head != NONE); - } - - _RYML_CB_ASSERT(m_callbacks, m_size < m_cap); - _RYML_CB_ASSERT(m_callbacks, m_free_head >= 0 && m_free_head < m_cap); - - id_type ichild = m_free_head; - NodeData *child = m_buf + ichild; - - ++m_size; - m_free_head = child->m_next_sibling; - if(m_free_head == NONE) - { - m_free_tail = NONE; - _RYML_CB_ASSERT(m_callbacks, m_size == m_cap); - } - - _clear(ichild); - - return ichild; -} - -//----------------------------------------------------------------------------- - -C4_SUPPRESS_WARNING_GCC_PUSH -C4_SUPPRESS_WARNING_CLANG_PUSH -C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference") -#if defined(__GNUC__) -#if (__GNUC__ >= 6) -C4_SUPPRESS_WARNING_GCC("-Wnull-dereference") -#endif -#if (__GNUC__ > 9) -C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak") -#endif -#endif - -void Tree::_set_hierarchy(id_type ichild, id_type iparent, id_type iprev_sibling) -{ - _RYML_CB_ASSERT(m_callbacks, ichild >= 0 && ichild < m_cap); - _RYML_CB_ASSERT(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap)); - _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap)); - - NodeData *C4_RESTRICT child = _p(ichild); - - child->m_parent = iparent; - child->m_prev_sibling = NONE; - child->m_next_sibling = NONE; - - if(iparent == NONE) - { - _RYML_CB_ASSERT(m_callbacks, ichild == 0); - _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE); - } - - if(iparent == NONE) - return; - - id_type inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent); - NodeData *C4_RESTRICT parent = get(iparent); - NodeData *C4_RESTRICT psib = get(iprev_sibling); - NodeData *C4_RESTRICT nsib = get(inext_sibling); - - if(psib) - { - _RYML_CB_ASSERT(m_callbacks, next_sibling(iprev_sibling) == id(nsib)); - child->m_prev_sibling = id(psib); - psib->m_next_sibling = id(child); - _RYML_CB_ASSERT(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE); - } - - if(nsib) - { - _RYML_CB_ASSERT(m_callbacks, prev_sibling(inext_sibling) == id(psib)); - child->m_next_sibling = id(nsib); - nsib->m_prev_sibling = id(child); - _RYML_CB_ASSERT(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE); - } - - if(parent->m_first_child == NONE) - { - _RYML_CB_ASSERT(m_callbacks, parent->m_last_child == NONE); - parent->m_first_child = id(child); - parent->m_last_child = id(child); - } - else - { - if(child->m_next_sibling == parent->m_first_child) - parent->m_first_child = id(child); - - if(child->m_prev_sibling == parent->m_last_child) - parent->m_last_child = id(child); - } -} - -C4_SUPPRESS_WARNING_GCC_POP -C4_SUPPRESS_WARNING_CLANG_POP - - -//----------------------------------------------------------------------------- -void Tree::_rem_hierarchy(id_type i) -{ - _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap); - - NodeData &C4_RESTRICT w = m_buf[i]; - - // remove from the parent - if(w.m_parent != NONE) - { - NodeData &C4_RESTRICT p = m_buf[w.m_parent]; - if(p.m_first_child == i) - { - p.m_first_child = w.m_next_sibling; - } - if(p.m_last_child == i) - { - p.m_last_child = w.m_prev_sibling; - } - } - - // remove from the used list - if(w.m_prev_sibling != NONE) - { - NodeData *C4_RESTRICT prev = get(w.m_prev_sibling); - prev->m_next_sibling = w.m_next_sibling; - } - if(w.m_next_sibling != NONE) - { - NodeData *C4_RESTRICT next = get(w.m_next_sibling); - next->m_prev_sibling = w.m_prev_sibling; - } -} - -//----------------------------------------------------------------------------- -/** @cond dev */ -id_type Tree::_do_reorder(id_type *node, id_type count) -{ - // swap this node if it's not in place - if(*node != count) - { - _swap(*node, count); - *node = count; - } - ++count; // bump the count from this node - - // now descend in the hierarchy - for(id_type i = first_child(*node); i != NONE; i = next_sibling(i)) - { - // this child may have been relocated to a different index, - // so get an updated version - count = _do_reorder(&i, count); - } - return count; -} -/** @endcond */ - -void Tree::reorder() -{ - id_type r = root_id(); - _do_reorder(&r, 0); -} - - -//----------------------------------------------------------------------------- -/** @cond dev */ -void Tree::_swap(id_type n_, id_type m_) -{ - _RYML_CB_ASSERT(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE); - _RYML_CB_ASSERT(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE); - NodeType tn = type(n_); - NodeType tm = type(m_); - if(tn != NOTYPE && tm != NOTYPE) - { - _swap_props(n_, m_); - _swap_hierarchy(n_, m_); - } - else if(tn == NOTYPE && tm != NOTYPE) - { - _copy_props(n_, m_); - _free_list_rem(n_); - _copy_hierarchy(n_, m_); - _clear(m_); - _free_list_add(m_); - } - else if(tn != NOTYPE && tm == NOTYPE) - { - _copy_props(m_, n_); - _free_list_rem(m_); - _copy_hierarchy(m_, n_); - _clear(n_); - _free_list_add(n_); - } - else - { - C4_NEVER_REACH(); - } -} - -//----------------------------------------------------------------------------- -void Tree::_swap_hierarchy(id_type ia, id_type ib) -{ - if(ia == ib) return; - - for(id_type i = first_child(ia); i != NONE; i = next_sibling(i)) - { - if(i == ib || i == ia) - continue; - _p(i)->m_parent = ib; - } - - for(id_type i = first_child(ib); i != NONE; i = next_sibling(i)) - { - if(i == ib || i == ia) - continue; - _p(i)->m_parent = ia; - } - - auto & C4_RESTRICT a = *_p(ia); - auto & C4_RESTRICT b = *_p(ib); - auto & C4_RESTRICT pa = *_p(a.m_parent); - auto & C4_RESTRICT pb = *_p(b.m_parent); - - if(&pa == &pb) - { - if((pa.m_first_child == ib && pa.m_last_child == ia) - || - (pa.m_first_child == ia && pa.m_last_child == ib)) - { - std::swap(pa.m_first_child, pa.m_last_child); - } - else - { - bool changed = false; - if(pa.m_first_child == ia) - { - pa.m_first_child = ib; - changed = true; - } - if(pa.m_last_child == ia) - { - pa.m_last_child = ib; - changed = true; - } - if(pb.m_first_child == ib && !changed) - { - pb.m_first_child = ia; - } - if(pb.m_last_child == ib && !changed) - { - pb.m_last_child = ia; - } - } - } - else - { - if(pa.m_first_child == ia) - pa.m_first_child = ib; - if(pa.m_last_child == ia) - pa.m_last_child = ib; - if(pb.m_first_child == ib) - pb.m_first_child = ia; - if(pb.m_last_child == ib) - pb.m_last_child = ia; - } - std::swap(a.m_first_child , b.m_first_child); - std::swap(a.m_last_child , b.m_last_child); - - if(a.m_prev_sibling != ib && b.m_prev_sibling != ia && - a.m_next_sibling != ib && b.m_next_sibling != ia) - { - if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib) - _p(a.m_prev_sibling)->m_next_sibling = ib; - if(a.m_next_sibling != NONE && a.m_next_sibling != ib) - _p(a.m_next_sibling)->m_prev_sibling = ib; - if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia) - _p(b.m_prev_sibling)->m_next_sibling = ia; - if(b.m_next_sibling != NONE && b.m_next_sibling != ia) - _p(b.m_next_sibling)->m_prev_sibling = ia; - std::swap(a.m_prev_sibling, b.m_prev_sibling); - std::swap(a.m_next_sibling, b.m_next_sibling); - } - else - { - if(a.m_next_sibling == ib) // n will go after m - { - _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling == ia); - if(a.m_prev_sibling != NONE) - { - _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ib); - _p(a.m_prev_sibling)->m_next_sibling = ib; - } - if(b.m_next_sibling != NONE) - { - _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ia); - _p(b.m_next_sibling)->m_prev_sibling = ia; - } - id_type ns = b.m_next_sibling; - b.m_prev_sibling = a.m_prev_sibling; - b.m_next_sibling = ia; - a.m_prev_sibling = ib; - a.m_next_sibling = ns; - } - else if(a.m_prev_sibling == ib) // m will go after n - { - _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling == ia); - if(b.m_prev_sibling != NONE) - { - _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ia); - _p(b.m_prev_sibling)->m_next_sibling = ia; - } - if(a.m_next_sibling != NONE) - { - _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ib); - _p(a.m_next_sibling)->m_prev_sibling = ib; - } - id_type ns = b.m_prev_sibling; - a.m_prev_sibling = b.m_prev_sibling; - a.m_next_sibling = ib; - b.m_prev_sibling = ia; - b.m_next_sibling = ns; - } - else - { - C4_NEVER_REACH(); - } - } - _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ia); - _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ia); - _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ib); - _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ib); - - if(a.m_parent != ib && b.m_parent != ia) - { - std::swap(a.m_parent, b.m_parent); - } - else - { - if(a.m_parent == ib && b.m_parent != ia) - { - a.m_parent = b.m_parent; - b.m_parent = ia; - } - else if(a.m_parent != ib && b.m_parent == ia) - { - b.m_parent = a.m_parent; - a.m_parent = ib; - } - else - { - C4_NEVER_REACH(); - } - } -} - -//----------------------------------------------------------------------------- -void Tree::_copy_hierarchy(id_type dst_, id_type src_) -{ - auto const& C4_RESTRICT src = *_p(src_); - auto & C4_RESTRICT dst = *_p(dst_); - auto & C4_RESTRICT prt = *_p(src.m_parent); - for(id_type i = src.m_first_child; i != NONE; i = next_sibling(i)) - { - _p(i)->m_parent = dst_; - } - if(src.m_prev_sibling != NONE) - { - _p(src.m_prev_sibling)->m_next_sibling = dst_; - } - if(src.m_next_sibling != NONE) - { - _p(src.m_next_sibling)->m_prev_sibling = dst_; - } - if(prt.m_first_child == src_) - { - prt.m_first_child = dst_; - } - if(prt.m_last_child == src_) - { - prt.m_last_child = dst_; - } - dst.m_parent = src.m_parent; - dst.m_first_child = src.m_first_child; - dst.m_last_child = src.m_last_child; - dst.m_prev_sibling = src.m_prev_sibling; - dst.m_next_sibling = src.m_next_sibling; -} - -//----------------------------------------------------------------------------- -void Tree::_swap_props(id_type n_, id_type m_) -{ - NodeData &C4_RESTRICT n = *_p(n_); - NodeData &C4_RESTRICT m = *_p(m_); - std::swap(n.m_type, m.m_type); - std::swap(n.m_key, m.m_key); - std::swap(n.m_val, m.m_val); -} -/** @endcond */ - -//----------------------------------------------------------------------------- -void Tree::move(id_type node, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, node != after); - _RYML_CB_ASSERT(m_callbacks, ! is_root(node)); - _RYML_CB_ASSERT(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node))); - - _rem_hierarchy(node); - _set_hierarchy(node, parent(node), after); -} - -//----------------------------------------------------------------------------- - -void Tree::move(id_type node, id_type new_parent, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, node != after); - _RYML_CB_ASSERT(m_callbacks, new_parent != NONE); - _RYML_CB_ASSERT(m_callbacks, new_parent != node); - _RYML_CB_ASSERT(m_callbacks, new_parent != after); - _RYML_CB_ASSERT(m_callbacks, ! is_root(node)); - - _rem_hierarchy(node); - _set_hierarchy(node, new_parent, after); -} - -id_type Tree::move(Tree *src, id_type node, id_type new_parent, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, src != nullptr); - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, new_parent != NONE); - _RYML_CB_ASSERT(m_callbacks, new_parent != after); - - id_type dup = duplicate(src, node, new_parent, after); - src->remove(node); - return dup; -} - -void Tree::set_root_as_stream() -{ - id_type root = root_id(); - if(is_stream(root)) - return; - // don't use _add_flags() because it's checked and will fail - if(!has_children(root)) - { - if(is_val(root)) - { - _p(root)->m_type.add(SEQ); - id_type next_doc = append_child(root); - _copy_props_wo_key(next_doc, root); - _p(next_doc)->m_type.add(DOC); - _p(next_doc)->m_type.rem(SEQ); - } - _p(root)->m_type = STREAM; - return; - } - _RYML_CB_ASSERT(m_callbacks, !has_key(root)); - id_type next_doc = append_child(root); - _copy_props_wo_key(next_doc, root); - _add_flags(next_doc, DOC); - for(id_type prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; ) - { - if(ch == next_doc) - break; - move(ch, next_doc, prev); - prev = ch; - ch = next; - next = next_sibling(next); - } - _p(root)->m_type = STREAM; -} - - -//----------------------------------------------------------------------------- -void Tree::remove_children(id_type node) -{ - _RYML_CB_ASSERT(m_callbacks, get(node) != nullptr); - #if __GNUC__ >= 6 - C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference") - #endif - id_type ich = get(node)->m_first_child; - #if __GNUC__ >= 6 - C4_SUPPRESS_WARNING_GCC_POP - #endif - while(ich != NONE) - { - remove_children(ich); - _RYML_CB_ASSERT(m_callbacks, get(ich) != nullptr); - id_type next = get(ich)->m_next_sibling; - _release(ich); - if(ich == get(node)->m_last_child) - break; - ich = next; - } -} - -bool Tree::change_type(id_type node, NodeType type) -{ - _RYML_CB_ASSERT(m_callbacks, type.is_val() || type.is_map() || type.is_seq()); - _RYML_CB_ASSERT(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1); - _RYML_CB_ASSERT(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key())); - NodeData *d = _p(node); - if(type.is_map() && is_map(node)) - return false; - else if(type.is_seq() && is_seq(node)) - return false; - else if(type.is_val() && is_val(node)) - return false; - d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type; - remove_children(node); - return true; -} - - -//----------------------------------------------------------------------------- -id_type Tree::duplicate(id_type node, id_type parent, id_type after) -{ - return duplicate(this, node, parent, after); -} - -id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, src != nullptr); - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, parent != NONE); - _RYML_CB_ASSERT(m_callbacks, ! src->is_root(node)); - - id_type copy = _claim(); - - _copy_props(copy, src, node); - _set_hierarchy(copy, parent, after); - duplicate_children(src, node, copy, NONE); - - return copy; -} - -//----------------------------------------------------------------------------- -id_type Tree::duplicate_children(id_type node, id_type parent, id_type after) -{ - return duplicate_children(this, node, parent, after); -} - -id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, src != nullptr); - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, parent != NONE); - _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after)); - - id_type prev = after; - for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i)) - { - prev = duplicate(src, i, parent, prev); - } - - return prev; -} - -//----------------------------------------------------------------------------- -void Tree::duplicate_contents(id_type node, id_type where) -{ - duplicate_contents(this, node, where); -} - -void Tree::duplicate_contents(Tree const *src, id_type node, id_type where) -{ - _RYML_CB_ASSERT(m_callbacks, src != nullptr); - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, where != NONE); - _copy_props_wo_key(where, src, node); - duplicate_children(src, node, where, last_child(where)); -} - -//----------------------------------------------------------------------------- -id_type Tree::duplicate_children_no_rep(id_type node, id_type parent, id_type after) -{ - return duplicate_children_no_rep(this, node, parent, after); -} - -id_type Tree::duplicate_children_no_rep(Tree const *src, id_type node, id_type parent, id_type after) -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, parent != NONE); - _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after)); - - // don't loop using pointers as there may be a relocation - - // find the position where "after" is - id_type after_pos = NONE; - if(after != NONE) - { - for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i)) - { - if(i == after) - { - after_pos = icount; - break; - } - } - _RYML_CB_ASSERT(m_callbacks, after_pos != NONE); - } - - // for each child to be duplicated... - id_type prev = after; - for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i)) - { - _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev); - _RYML_CB_CHECK(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i))); - if(is_seq(parent)) - { - _c4dbgpf("duplicate_no_rep: {} is seq", parent); - prev = duplicate(src, i, parent, prev); - } - else - { - _c4dbgpf("duplicate_no_rep: {} is map", parent); - _RYML_CB_ASSERT(m_callbacks, is_map(parent)); - // does the parent already have a node with key equal to that of the current duplicate? - id_type dstnode_dup = NONE, dstnode_dup_pos = NONE; - { - csubstr srckey = src->key(i); - for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j)) - { - if(key(j) == srckey) - { - _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j); - dstnode_dup = j; - dstnode_dup_pos = jcount; - break; - } - } - } - _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos); - if(dstnode_dup == NONE) // there is no repetition; just duplicate - { - _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev); - prev = duplicate(src, i, parent, prev); - } - else // yes, there is a repetition - { - if(after_pos != NONE && dstnode_dup_pos <= after_pos) - { - // the dst duplicate is located before the node which will be inserted, - // and will be overridden by the duplicate. So replace it. - _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i); - if(prev == dstnode_dup) - prev = prev_sibling(dstnode_dup); - remove(dstnode_dup); - prev = duplicate(src, i, parent, prev); - } - else if(prev == NONE) - { - _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup); - // first iteration with prev = after = NONE and dstnode_dupetition - prev = dstnode_dup; - } - else if(dstnode_dup != prev) - { - // dstnode_dup is located after the node which will be inserted - // and overrides it. So move the dstnode_dup into this node's place. - _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev); - move(dstnode_dup, prev); - prev = dstnode_dup; - } - } // there's a dstnode_dupetition - } - } - - return prev; -} - - -//----------------------------------------------------------------------------- - -void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node) -{ - _RYML_CB_ASSERT(m_callbacks, src != nullptr); - if(src_node == NONE) - src_node = src->root_id(); - if(dst_node == NONE) - dst_node = root_id(); - _RYML_CB_ASSERT(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node)); - if(src->has_val(src_node)) - { - type_bits mask_src = ~STYLE; // keep the existing style if it is already a val - if( ! has_val(dst_node)) - { - if(has_children(dst_node)) - remove_children(dst_node); - mask_src |= VAL_STYLE; // copy the src style - } - if(src->is_keyval(src_node)) - { - _copy_props(dst_node, src, src_node, mask_src); - } - else - { - _RYML_CB_ASSERT(m_callbacks, src->is_val(src_node)); - _copy_props_wo_key(dst_node, src, src_node, mask_src); - } - } - else if(src->is_seq(src_node)) - { - if( ! is_seq(dst_node)) - { - if(has_children(dst_node)) - remove_children(dst_node); - _clear_type(dst_node); - if(src->has_key(src_node)) - to_seq(dst_node, src->key(src_node)); - else - to_seq(dst_node); - _p(dst_node)->m_type = src->_p(src_node)->m_type; - } - for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch)) - { - id_type dch = append_child(dst_node); - _copy_props_wo_key(dch, src, sch); - merge_with(src, sch, dch); - } - } - else - { - _RYML_CB_ASSERT(m_callbacks, src->is_map(src_node)); - if( ! is_map(dst_node)) - { - if(has_children(dst_node)) - remove_children(dst_node); - _clear_type(dst_node); - if(src->has_key(src_node)) - to_map(dst_node, src->key(src_node)); - else - to_map(dst_node); - _p(dst_node)->m_type = src->_p(src_node)->m_type; - } - for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch)) - { - id_type dch = find_child(dst_node, src->key(sch)); - if(dch == NONE) - { - dch = append_child(dst_node); - _copy_props(dch, src, sch); - } - merge_with(src, sch, dch); - } - } -} - - -//----------------------------------------------------------------------------- - -void Tree::resolve(bool clear_anchors) -{ - if(m_size == 0) - return; - ReferenceResolver rr; - resolve(&rr, clear_anchors); -} - -void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors) -{ - if(m_size == 0) - return; - rr->resolve(this, clear_anchors); -} - - -//----------------------------------------------------------------------------- - -id_type Tree::num_children(id_type node) const -{ - id_type count = 0; - for(id_type i = first_child(node); i != NONE; i = next_sibling(i)) - ++count; - return count; -} - -id_type Tree::child(id_type node, id_type pos) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - id_type count = 0; - for(id_type i = first_child(node); i != NONE; i = next_sibling(i)) - { - if(count++ == pos) - return i; - } - return NONE; -} - -id_type Tree::child_pos(id_type node, id_type ch) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - id_type count = 0; - for(id_type i = first_child(node); i != NONE; i = next_sibling(i)) - { - if(i == ch) - return count; - ++count; - } - return NONE; -} - -#if defined(__clang__) -# pragma clang diagnostic push -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# if __GNUC__ >= 6 -# pragma GCC diagnostic ignored "-Wnull-dereference" -# endif -# if __GNUC__ > 9 -# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" -# endif -#endif - -id_type Tree::find_child(id_type node, csubstr const& name) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - _RYML_CB_ASSERT(m_callbacks, is_map(node)); - if(get(node)->m_first_child == NONE) - { - _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child == NONE); - return NONE; - } - else - { - _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child != NONE); - } - for(id_type i = first_child(node); i != NONE; i = next_sibling(i)) - { - if(_p(i)->m_key.scalar == name) - { - return i; - } - } - return NONE; -} - -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - -namespace { -id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0) -{ - maxdepth = currdepth > maxdepth ? currdepth : maxdepth; - for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child)) - { - const id_type d = depth_desc_(t, child, currdepth+1, maxdepth); - maxdepth = d > maxdepth ? d : maxdepth; - } - return maxdepth; -} -} - -id_type Tree::depth_desc(id_type node) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - return depth_desc_(*this, node); -} - -id_type Tree::depth_asc(id_type node) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - id_type depth = 0; - while(!is_root(node)) - { - ++depth; - node = parent(node); - } - return depth; -} - -bool Tree::is_ancestor(id_type node, id_type ancestor) const -{ - _RYML_CB_ASSERT(m_callbacks, node != NONE); - id_type p = parent(node); - while(p != NONE) - { - if(p == ancestor) - return true; - p = parent(p); - } - return false; -} - - -//----------------------------------------------------------------------------- - -void Tree::to_val(id_type node, csubstr val, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node)); - _set_flags(node, VAL|more_flags); - _p(node)->m_key.clear(); - _p(node)->m_val = val; -} - -void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node)); - _set_flags(node, KEYVAL|more_flags); - _p(node)->m_key = key; - _p(node)->m_val = val; -} - -void Tree::to_map(id_type node, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node)); // parent must not have children with keys - _set_flags(node, MAP|more_flags); - _p(node)->m_key.clear(); - _p(node)->m_val.clear(); -} - -void Tree::to_map(id_type node, csubstr key, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node)); - _set_flags(node, KEY|MAP|more_flags); - _p(node)->m_key = key; - _p(node)->m_val.clear(); -} - -void Tree::to_seq(id_type node, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_seq(node)); - _set_flags(node, SEQ|more_flags); - _p(node)->m_key.clear(); - _p(node)->m_val.clear(); -} - -void Tree::to_seq(id_type node, csubstr key, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node)); - _set_flags(node, KEY|SEQ|more_flags); - _p(node)->m_key = key; - _p(node)->m_val.clear(); -} - -void Tree::to_doc(id_type node, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _set_flags(node, DOC|more_flags); - _p(node)->m_key.clear(); - _p(node)->m_val.clear(); -} - -void Tree::to_stream(id_type node, type_bits more_flags) -{ - _RYML_CB_ASSERT(m_callbacks, ! has_children(node)); - _set_flags(node, STREAM|more_flags); - _p(node)->m_key.clear(); - _p(node)->m_val.clear(); -} - - -//----------------------------------------------------------------------------- - -void Tree::clear_style(id_type node, bool recurse) -{ - NodeData *C4_RESTRICT d = _p(node); - d->m_type.clear_style(); - if(!recurse) - return; - for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child)) - clear_style(child, recurse); -} - -void Tree::set_style_conditionally(id_type node, - NodeType type_mask, - NodeType rem_style_flags, - NodeType add_style_flags, - bool recurse) -{ - NodeData *C4_RESTRICT d = _p(node); - if((d->m_type & type_mask) == type_mask) - { - d->m_type &= ~(NodeType)rem_style_flags; - d->m_type |= (NodeType)add_style_flags; - } - if(!recurse) - return; - for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child)) - set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse); -} - - -//----------------------------------------------------------------------------- -id_type Tree::num_tag_directives() const -{ - // this assumes we have a very small number of tag directives - for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i) - if(m_tag_directives[i].handle.empty()) - return i; - return RYML_MAX_TAG_DIRECTIVES; -} - -void Tree::clear_tag_directives() -{ - for(TagDirective &td : m_tag_directives) - td = {}; -} - -id_type Tree::add_tag_directive(TagDirective const& td) -{ - _RYML_CB_CHECK(m_callbacks, !td.handle.empty()); - _RYML_CB_CHECK(m_callbacks, !td.prefix.empty()); - _RYML_CB_CHECK(m_callbacks, td.handle.begins_with('!')); - _RYML_CB_CHECK(m_callbacks, td.handle.ends_with('!')); - // https://yaml.org/spec/1.2.2/#rule-ns-word-char - _RYML_CB_CHECK(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos); - id_type pos = num_tag_directives(); - _RYML_CB_CHECK(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES); - m_tag_directives[pos] = td; - return pos; -} - -namespace { -bool _create_tag_directive_from_str(csubstr directive_, TagDirective *td, Tree *tree) -{ - _RYML_CB_CHECK(tree->callbacks(), directive_.begins_with("%TAG ")); - if(!td->create_from_str(directive_)) - { - _RYML_CB_ERR(tree->callbacks(), "invalid tag directive"); - } - td->next_node_id = tree->size(); - if(!tree->empty()) - { - const id_type prev = tree->size() - 1; - if(tree->is_root(prev) && tree->type(prev) != NOTYPE && !tree->is_stream(prev)) - ++td->next_node_id; - } - _c4dbgpf("%TAG: handle={} prefix={} next_node={}", td->handle, td->prefix, td->next_node_id); - return true; -} -} // namespace - -bool Tree::add_tag_directive(csubstr directive_) -{ - TagDirective td; - if(_create_tag_directive_from_str(directive_, &td, this)) - { - add_tag_directive(td); - return true; - } - return false; -} - -size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const -{ - // lookup from the end. We want to find the first directive that - // matches the tag and has a target node id leq than the given - // node_id. - for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != (id_type)-1; --i) - { - auto const& td = m_tag_directives[i]; - if(td.handle.empty()) - continue; - if(tag.begins_with(td.handle) && td.next_node_id <= node_id) - return td.transform(tag, output, m_callbacks); - } - if(tag.begins_with('!')) - { - if(is_custom_tag(tag)) - { - _RYML_CB_ERR(m_callbacks, "tag directive not found"); - } - } - return 0; // return 0 to signal that the tag is local and cannot be resolved -} - -namespace { -csubstr _transform_tag(Tree *t, csubstr tag, id_type node) -{ - _c4dbgpf("[{}] resolving tag ~~~{}~~~", node, tag); - size_t required_size = t->resolve_tag(substr{}, tag, node); - if(!required_size) - { - if(tag.begins_with("!<")) - tag = tag.sub(1); - _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, tag); - return tag; - } - const char *prev_arena = t->arena().str;(void)prev_arena; - substr buf = t->alloc_arena(required_size); - _RYML_CB_ASSERT(t->m_callbacks, t->arena().str == prev_arena); - size_t actual_size = t->resolve_tag(buf, tag, node); - _RYML_CB_ASSERT(t->m_callbacks, actual_size <= required_size); - _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, buf.first(actual_size)); - return buf.first(actual_size); -} -void _resolve_tags(Tree *t, id_type node) -{ - NodeData *C4_RESTRICT d = t->_p(node); - if(d->m_type & KEYTAG) - d->m_key.tag = _transform_tag(t, d->m_key.tag, node); - if(d->m_type & VALTAG) - d->m_val.tag = _transform_tag(t, d->m_val.tag, node); - for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child)) - _resolve_tags(t, child); -} -size_t _count_resolved_tags_size(Tree const* t, id_type node) -{ - size_t sz = 0; - NodeData const* C4_RESTRICT d = t->_p(node); - if(d->m_type & KEYTAG) - sz += t->resolve_tag(substr{}, d->m_key.tag, node); - if(d->m_type & VALTAG) - sz += t->resolve_tag(substr{}, d->m_val.tag, node); - for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child)) - sz += _count_resolved_tags_size(t, child); - return sz; -} -void _normalize_tags(Tree *t, id_type node) -{ - NodeData *C4_RESTRICT d = t->_p(node); - if(d->m_type & KEYTAG) - d->m_key.tag = normalize_tag(d->m_key.tag); - if(d->m_type & VALTAG) - d->m_val.tag = normalize_tag(d->m_val.tag); - for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child)) - _normalize_tags(t, child); -} -void _normalize_tags_long(Tree *t, id_type node) -{ - NodeData *C4_RESTRICT d = t->_p(node); - if(d->m_type & KEYTAG) - d->m_key.tag = normalize_tag_long(d->m_key.tag); - if(d->m_type & VALTAG) - d->m_val.tag = normalize_tag_long(d->m_val.tag); - for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child)) - _normalize_tags_long(t, child); -} -} // namespace - -void Tree::resolve_tags() -{ - if(empty()) - return; - size_t needed_size = _count_resolved_tags_size(this, root_id()); - if(needed_size) - reserve_arena(arena_size() + needed_size); - _resolve_tags(this, root_id()); -} - -void Tree::normalize_tags() -{ - if(empty()) - return; - _normalize_tags(this, root_id()); -} - -void Tree::normalize_tags_long() -{ - if(empty()) - return; - _normalize_tags_long(this, root_id()); -} - - -//----------------------------------------------------------------------------- - -csubstr Tree::lookup_result::resolved() const -{ - csubstr p = path.first(path_pos); - if(p.ends_with('.')) - p = p.first(p.len-1); - return p; -} - -csubstr Tree::lookup_result::unresolved() const -{ - return path.sub(path_pos); -} - -void Tree::_advance(lookup_result *r, size_t more) -{ - r->path_pos += more; - if(r->path.sub(r->path_pos).begins_with('.')) - ++r->path_pos; -} - -Tree::lookup_result Tree::lookup_path(csubstr path, id_type start) const -{ - if(start == NONE) - start = root_id(); - lookup_result r(path, start); - if(path.empty()) - return r; - _lookup_path(&r); - if(r.target == NONE && r.closest == start) - r.closest = NONE; - return r; -} - -id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start) -{ - id_type target = _lookup_path_or_create(path, start); - if(parent_is_map(target)) - to_keyval(target, key(target), default_value); - else - to_val(target, default_value); - return target; -} - -id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start) -{ - id_type target = _lookup_path_or_create(path, start); - merge_with(src, src_node, target); - return target; -} - -id_type Tree::_lookup_path_or_create(csubstr path, id_type start) -{ - if(start == NONE) - start = root_id(); - lookup_result r(path, start); - _lookup_path(&r); - if(r.target != NONE) - { - C4_ASSERT(r.unresolved().empty()); - return r.target; - } - _lookup_path_modify(&r); - return r.target; -} - -void Tree::_lookup_path(lookup_result *r) const -{ - C4_ASSERT( ! r->unresolved().empty()); - _lookup_path_token parent{"", type(r->closest)}; - id_type node; - do - { - node = _next_node(r, &parent); - if(node != NONE) - r->closest = node; - if(r->unresolved().empty()) - { - r->target = node; - return; - } - } while(node != NONE); -} - -void Tree::_lookup_path_modify(lookup_result *r) -{ - C4_ASSERT( ! r->unresolved().empty()); - _lookup_path_token parent{"", type(r->closest)}; - id_type node; - do - { - node = _next_node_modify(r, &parent); - if(node != NONE) - r->closest = node; - if(r->unresolved().empty()) - { - r->target = node; - return; - } - } while(node != NONE); -} - -id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const -{ - _lookup_path_token token = _next_token(r, *parent); - if( ! token) - return NONE; - - id_type node = NONE; - csubstr prev = token.value; - if(token.type == MAP || token.type == SEQ) - { - _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('[')); - //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE); - _RYML_CB_ASSERT(m_callbacks, is_map(r->closest)); - node = find_child(r->closest, token.value); - } - else if(token.type == KEYVAL) - { - _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty()); - if(is_map(r->closest)) - node = find_child(r->closest, token.value); - } - else if(token.type == KEY) - { - _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']')); - token.value = token.value.offs(1, 1).trim(' '); - id_type idx = 0; - _RYML_CB_CHECK(m_callbacks, from_chars(token.value, &idx)); - node = child(r->closest, idx); - } - else - { - C4_NEVER_REACH(); - } - - if(node != NONE) - { - *parent = token; - } - else - { - csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos); - r->path_pos -= prev.len; - if(p.begins_with('.')) - r->path_pos -= 1u; - } - - return node; -} - -id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent) -{ - _lookup_path_token token = _next_token(r, *parent); - if( ! token) - return NONE; - - id_type node = NONE; - if(token.type == MAP || token.type == SEQ) - { - _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('[')); - //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE); - if( ! is_container(r->closest)) - { - if(has_key(r->closest)) - to_map(r->closest, key(r->closest)); - else - to_map(r->closest); - } - else - { - if(is_map(r->closest)) - node = find_child(r->closest, token.value); - else - { - id_type pos = NONE; - _RYML_CB_CHECK(m_callbacks, c4::atox(token.value, &pos)); - _RYML_CB_ASSERT(m_callbacks, pos != NONE); - node = child(r->closest, pos); - } - } - if(node == NONE) - { - _RYML_CB_ASSERT(m_callbacks, is_map(r->closest)); - node = append_child(r->closest); - NodeData *n = _p(node); - n->m_key.scalar = token.value; - n->m_type.add(KEY); - } - } - else if(token.type == KEYVAL) - { - _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty()); - if(is_map(r->closest)) - { - node = find_child(r->closest, token.value); - if(node == NONE) - node = append_child(r->closest); - } - else - { - _RYML_CB_ASSERT(m_callbacks, !is_seq(r->closest)); - _add_flags(r->closest, MAP); - node = append_child(r->closest); - } - NodeData *n = _p(node); - n->m_key.scalar = token.value; - n->m_val.scalar = ""; - n->m_type.add(KEYVAL); - } - else if(token.type == KEY) - { - _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']')); - token.value = token.value.offs(1, 1).trim(' '); - id_type idx; - if( ! from_chars(token.value, &idx)) - return NONE; - if( ! is_container(r->closest)) - { - if(has_key(r->closest)) - { - csubstr k = key(r->closest); - _clear_type(r->closest); - to_seq(r->closest, k); - } - else - { - _clear_type(r->closest); - to_seq(r->closest); - } - } - _RYML_CB_ASSERT(m_callbacks, is_container(r->closest)); - node = child(r->closest, idx); - if(node == NONE) - { - _RYML_CB_ASSERT(m_callbacks, num_children(r->closest) <= idx); - for(id_type i = num_children(r->closest); i <= idx; ++i) - { - node = append_child(r->closest); - if(i < idx) - { - if(is_map(r->closest)) - to_keyval(node, /*"~"*/{}, /*"~"*/{}); - else if(is_seq(r->closest)) - to_val(node, /*"~"*/{}); - } - } - } - } - else - { - C4_NEVER_REACH(); - } - - _RYML_CB_ASSERT(m_callbacks, node != NONE); - *parent = token; - return node; -} - -/* types of tokens: - * - seeing "map." ---> "map"/MAP - * - finishing "scalar" ---> "scalar"/KEYVAL - * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY) - * - seeing "[n]" ---> "[n]"/KEY - */ -Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const -{ - csubstr unres = r->unresolved(); - if(unres.empty()) - return {}; - - // is it an indexation like [0], [1], etc? - if(unres.begins_with('[')) - { - size_t pos = unres.find(']'); - if(pos == csubstr::npos) - return {}; - csubstr idx = unres.first(pos + 1); - _advance(r, pos + 1); - return {idx, KEY}; - } - - // no. so it must be a name - size_t pos = unres.first_of(".["); - if(pos == csubstr::npos) - { - _advance(r, unres.len); - NodeType t; - if(( ! parent) || parent.type.is_seq()) - return {unres, VAL}; - return {unres, KEYVAL}; - } - - // it's either a map or a seq - _RYML_CB_ASSERT(m_callbacks, unres[pos] == '.' || unres[pos] == '['); - if(unres[pos] == '.') - { - _RYML_CB_ASSERT(m_callbacks, pos != 0); - _advance(r, pos + 1); - return {unres.first(pos), MAP}; - } - - _RYML_CB_ASSERT(m_callbacks, unres[pos] == '['); - _advance(r, pos); - return {unres.first(pos), SEQ}; -} - - -} // namespace yml -} // namespace c4 - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -#include "c4/yml/event_handler_tree.hpp" -#include "c4/yml/parse_engine.def.hpp" -#include "c4/yml/parse.hpp" - -namespace c4 { -namespace yml { - -Location Tree::location(Parser const& parser, id_type node) const -{ - // try hard to avoid getting the location from a null string. - Location loc; - if(_location_from_node(parser, node, &loc, 0)) - return loc; - return parser.val_location(parser.source().str); -} - -bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const -{ - if(has_key(node)) - { - csubstr k = key(node); - if(C4_LIKELY(k.str != nullptr)) - { - _RYML_CB_ASSERT(m_callbacks, k.is_sub(parser.source())); - _RYML_CB_ASSERT(m_callbacks, parser.source().is_super(k)); - *loc = parser.val_location(k.str); - return true; - } - } - - if(has_val(node)) - { - csubstr v = val(node); - if(C4_LIKELY(v.str != nullptr)) - { - _RYML_CB_ASSERT(m_callbacks, v.is_sub(parser.source())); - _RYML_CB_ASSERT(m_callbacks, parser.source().is_super(v)); - *loc = parser.val_location(v.str); - return true; - } - } - - if(is_container(node)) - { - if(_location_from_cont(parser, node, loc)) - return true; - } - - if(type(node) != NOTYPE && level == 0) - { - // try the prev sibling - { - const id_type prev = prev_sibling(node); - if(prev != NONE) - { - if(_location_from_node(parser, prev, loc, level+1)) - return true; - } - } - // try the next sibling - { - const id_type next = next_sibling(node); - if(next != NONE) - { - if(_location_from_node(parser, next, loc, level+1)) - return true; - } - } - // try the parent - { - const id_type parent = this->parent(node); - if(parent != NONE) - { - if(_location_from_node(parser, parent, loc, level+1)) - return true; - } - } - } - return false; -} - -bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const -{ - _RYML_CB_ASSERT(m_callbacks, is_container(node)); - if(!is_stream(node)) - { - const char *node_start = _p(node)->m_val.scalar.str; // this was stored in the container - if(has_children(node)) - { - id_type child = first_child(node); - if(has_key(child)) - { - // when a map starts, the container was set after the key - csubstr k = key(child); - if(k.str && node_start > k.str) - node_start = k.str; - } - } - *loc = parser.val_location(node_start); - return true; - } - else // it's a stream - { - *loc = parser.val_location(parser.source().str); // just return the front of the buffer - } - return true; -} - -} // namespace yml -} // namespace c4 - - -C4_SUPPRESS_WARNING_GCC_CLANG_POP -C4_SUPPRESS_WARNING_MSVC_POP diff --git a/3rdparty/rapidyaml/src/c4/yml/version.cpp b/3rdparty/rapidyaml/src/c4/yml/version.cpp deleted file mode 100644 index c54c1f4fd0..0000000000 --- a/3rdparty/rapidyaml/src/c4/yml/version.cpp +++ /dev/null @@ -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 diff --git a/PCSX2_qt.sln b/PCSX2_qt.sln index 69bd9b42aa..c8587e55af 100644 --- a/PCSX2_qt.sln +++ b/PCSX2_qt.sln @@ -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} diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index 0f7204ca53..acd266f71f 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -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) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b676f4db25..d1bad4494f 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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) diff --git a/common/YAML.cpp b/common/YAML.cpp index fc878604dc..8aee5b278d 100644 --- a/common/YAML.cpp +++ b/common/YAML.cpp @@ -3,8 +3,11 @@ #include "YAML.h" +#include "Assertions.h" + +#include "c4/yml/error.def.hpp" // for ryml::err_basic_format etc + #include -#include struct RapidYAMLContext { @@ -18,6 +21,47 @@ std::optional 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(&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(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(&context); callbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location location, void* user_data) { RapidYAMLContext* context = static_cast(user_data); @@ -25,6 +69,7 @@ std::optional 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); diff --git a/common/YAML.h b/common/YAML.h index 9bbf7d423f..fe5a8cb4cd 100644 --- a/common/YAML.h +++ b/common/YAML.h @@ -5,9 +5,8 @@ #include "Error.h" +#include "ryml.hpp" #include "ryml_std.hpp" -#include "ryml.hpp" -#include "ryml.hpp" #include diff --git a/common/common.vcxproj b/common/common.vcxproj index 0c50e99bb3..257f863a7f 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -36,7 +36,6 @@ %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd - %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include Use PrecompiledHeader.h PrecompiledHeader.h diff --git a/common/vsprops/LinkPCSX2Deps.props b/common/vsprops/LinkPCSX2Deps.props index a890440e96..f986272cd1 100644 --- a/common/vsprops/LinkPCSX2Deps.props +++ b/common/vsprops/LinkPCSX2Deps.props @@ -4,7 +4,7 @@ $(DepsLibDir);%(AdditionalLibraryDirectories) - %(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib + %(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib;ryml.lib %(AdditionalDependencies);kddockwidgets-qt6d.lib; %(AdditionalDependencies);kddockwidgets-qt6.lib; @@ -27,6 +27,7 @@ + diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 3c9a8f6240..be64e4c878 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -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 $,kddockwidgets-qt6d.dll,kddockwidgets-qt6.dll> ${DEPS_TO_COPY} diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index 43a72be4c3..6946144a09 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -17,8 +17,6 @@ #include "common/YAML.h" #include -#include "ryml_std.hpp" -#include "ryml.hpp" #include "fmt/format.h" #include "fmt/ranges.h" #include diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index 4490cad0cf..5520881124 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -43,7 +43,6 @@ %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\simpleini\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libzip\msvc;$(SolutionDir)3rdparty\libzip\lib %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\cpuinfo\include - %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rcheevos\include;$(SolutionDir)3rdparty\rainterface %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\soundtouch\soundtouch @@ -983,9 +982,6 @@ {bf74c473-dc04-44b3-92e8-4145f4e77342} - - {de9653b6-17dd-356a-9ee0-28a731772587} - {88fb34ec-845e-4f21-a552-f1573b9ed167} @@ -1035,4 +1031,4 @@ - \ No newline at end of file +