Deps: Update rapidyaml to v0.11.1

This commit is contained in:
chaoticgd
2026-03-29 18:16:14 +01:00
committed by Ty
parent ade5762a45
commit 0beb18c9e1
99 changed files with 151 additions and 34503 deletions
@@ -36,6 +36,7 @@ ZSTD=1.5.7
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
@@ -72,6 +73,7 @@ eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
@@ -107,7 +109,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check --strict SHASUMS
@@ -349,6 +352,15 @@ cmake --build build --parallel
ninja -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
@@ -24,6 +24,7 @@ LZ4=1.10.0
ZSTD=1.5.7
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2025.4
SHADERC_GLSLANG=7a47e2531cb334982b2a2dd8513dca0a3de4373d
@@ -49,6 +50,7 @@ c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
EOF
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
@@ -67,7 +69,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check --strict SHASUMS
@@ -175,6 +178,15 @@ cmake --build build --parallel
ninja -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building shaderc..."
rm -fr "shaderc-$SHADERC"
tar xf "shaderc-$SHADERC.tar.gz"
@@ -0,0 +1,23 @@
{
"name": "rapidyaml",
"buildsystem": "cmake-ninja",
"builddir": true,
"config-opts": [
"-DBUILD_SHARED_LIBS=ON"
],
"build-options": {
"strip": true
},
"sources": [
{
"type": "git",
"url": "https://github.com/biojppm/rapidyaml.git",
"tag": "v0.11.1",
"commit": "119b6042064d3828819e428e32e5a0f3035d5643"
}
],
"cleanup": [
"/include",
"/lib/cmake"
]
}
@@ -35,6 +35,7 @@
"modules/25-plutosvg.json",
"modules/26-libpng.json",
"modules/27-qtapng.json",
"modules/28-rapidyaml.json",
{
"name": "pcsx2",
"buildsystem": "cmake-ninja",
@@ -79,4 +80,3 @@
}
]
}
@@ -59,6 +59,7 @@ MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
@@ -105,6 +106,7 @@ b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
@@ -137,7 +139,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check --strict SHASUMS
@@ -427,6 +430,15 @@ make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build
make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Cleaning up..."
cd ..
rm -rf deps-build
@@ -36,6 +36,7 @@ MOLTENVK=1.4.1
KDDOCKWIDGETS=2.4.0
PLUTOVG=1.3.2
PLUTOSVG=0.0.7
RAPIDYAML=0.11.1
SHADERC=2026.1
SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
@@ -81,6 +82,7 @@ b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
9d9938269adc25e9a9b84650338b87d130cf469d82685fffc028c325279619c1 rapidyaml-$RAPIDYAML-src.tgz
245002feccbe7f8361b223545a5654cea69780745886872d7efff50a38d96c66 shaderc-$SHADERC.tar.gz
bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
@@ -113,7 +115,8 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz" \
-O "https://github.com/biojppm/rapidyaml/releases/download/v$RAPIDYAML/rapidyaml-$RAPIDYAML-src.tgz"
fi
shasum -a 256 --check --strict SHASUMS
@@ -370,6 +373,15 @@ make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Building RapidYAML..."
rm -fr "rapidyaml-$RAPIDYAML-src"
tar xf "rapidyaml-$RAPIDYAML-src.tgz"
cd "rapidyaml-$RAPIDYAML-src"
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -B build
make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Cleaning up..."
cd ..
rm -rf deps-build
@@ -72,6 +72,7 @@ set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
@@ -101,6 +102,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile: "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" 0027fc24f947c48dbded13ada7d280be221eb651644e23a8a476f0f1f0a079dd || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
@@ -322,6 +324,15 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Building RapidYAML..."
rmdir /S /Q "rapidyaml-%RAPIDYAML%-src"
%SEVENZIP% x "rapidyaml-%RAPIDYAML%-src.zip" || goto error
cd "rapidyaml-%RAPIDYAML%-src" || goto error
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Unpacking Agility SDK
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
@@ -89,6 +89,7 @@ set ZSTD=1.5.7
set KDDOCKWIDGETS=2.4.0
set PLUTOVG=1.3.2
set PLUTOSVG=0.0.7
set RAPIDYAML=0.11.1
set SHADERC=2026.1
set SHADERC_GLSLANG=f0bd0257c308b9a26562c1a30c4748a0219cc951
@@ -128,6 +129,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" d5edab9a0c4d1b78ba6fe55b425eeef9fefba7d2a101e889d70fd21d481e6cb1 || goto error
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 30054b74abdf0ba35bf2cb435b6e49fcb6d62a8e78a240a018c36aa60dba765f || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 3ac59c8216d367ab7858684d39c8faf872a64150aeb139335f4e083c5f79dde0 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 42a30acca4a35955370ed8ff6e54b823b4d4a5a86571baec1203d3fce87da447 || goto error
@@ -481,6 +483,15 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo "Building RapidYAML..."
rmdir /S /Q "rapidyaml-%RAPIDYAML%-src"
%SEVENZIP% x "rapidyaml-%RAPIDYAML%-src.zip" || goto error
cd "rapidyaml-%RAPIDYAML%-src" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Unpacking Agility SDK
rmdir /S /Q "agility-sdk-%AGILITYSDK%"
%SEVENZIP% x -o"agility-sdk-%AGILITYSDK%" "agility-sdk-%AGILITYSDK%.nupkg" || goto error
-91
View File
@@ -1,91 +0,0 @@
add_library(pcsx2-rapidyaml
include/c4/base64.hpp
include/c4/blob.hpp
include/c4/charconv.hpp
include/c4/compiler.hpp
include/c4/config.hpp
include/c4/cpu.hpp
include/c4/dump.hpp
include/c4/error.hpp
include/c4/export.hpp
include/c4/format.hpp
include/c4/language.hpp
include/c4/memory_util.hpp
include/c4/platform.hpp
include/c4/preprocessor.hpp
include/c4/std/std.hpp
include/c4/std/std_fwd.hpp
include/c4/std/string.hpp
include/c4/std/string_fwd.hpp
include/c4/std/string_view.hpp
include/c4/std/tuple.hpp
include/c4/std/vector.hpp
include/c4/std/vector_fwd.hpp
include/c4/substr.hpp
include/c4/substr_fwd.hpp
include/c4/szconv.hpp
include/c4/types.hpp
include/c4/utf.hpp
include/c4/windows.hpp
include/c4/windows_pop.hpp
include/c4/windows_push.hpp
include/c4/yml/common.hpp
include/c4/yml/detail/dbgprint.hpp
include/c4/yml/detail/stack.hpp
include/c4/yml/emit.def.hpp
include/c4/yml/emit.hpp
include/c4/yml/event_handler_stack.hpp
include/c4/yml/event_handler_tree.hpp
include/c4/yml/filter_processor.hpp
include/c4/yml/fwd.hpp
include/c4/yml/export.hpp
include/c4/yml/node.hpp
include/c4/yml/node_type.hpp
include/c4/yml/parse.hpp
include/c4/yml/parse_engine.def.hpp
include/c4/yml/parse_engine.hpp
include/c4/yml/parser_state.hpp
include/c4/yml/reference_resolver.hpp
include/c4/yml/preprocess.hpp
include/c4/yml/std/map.hpp
include/c4/yml/std/std.hpp
include/c4/yml/std/string.hpp
include/c4/yml/std/vector.hpp
include/c4/yml/tag.hpp
include/c4/yml/tree.hpp
include/c4/yml/version.hpp
include/c4/yml/writer.hpp
include/c4/yml/yml.hpp
include/ryml.hpp
include/ryml_std.hpp
src/c4/base64.cpp
src/c4/error.cpp
src/c4/format.cpp
src/c4/language.cpp
src/c4/memory_util.cpp
src/c4/utf.cpp
src/c4/yml/common.cpp
src/c4/yml/node.cpp
src/c4/yml/parse.cpp
src/c4/yml/preprocess.cpp
src/c4/yml/tree.cpp
src/c4/yml/node_type.cpp
src/c4/yml/reference_resolver.cpp
src/c4/yml/tag.cpp
src/c4/yml/version.cpp
)
target_include_directories(pcsx2-rapidyaml PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/../fast_float/include"
)
target_include_directories(pcsx2-rapidyaml INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_compile_definitions(pcsx2-rapidyaml PUBLIC
"C4_NO_DEBUG_BREAK"
)
add_library(rapidyaml::rapidyaml ALIAS pcsx2-rapidyaml)
-141
View File
@@ -1,141 +0,0 @@
#ifndef _C4_BASE64_HPP_
#define _C4_BASE64_HPP_
/** @file base64.hpp encoding/decoding for base64.
* @see https://en.wikipedia.org/wiki/Base64
* @see https://www.base64encode.org/
* */
#include "c4/charconv.hpp"
#include "c4/blob.hpp"
namespace c4 {
/** @defgroup doc_base64 Base64 encoding/decoding
* @see https://en.wikipedia.org/wiki/Base64
* @see https://www.base64encode.org/
* @{ */
/** check that the given buffer is a valid base64 encoding
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT bool base64_valid(csubstr encoded);
/** base64-encode binary data.
* @param encoded [out] output buffer for encoded data
* @param data [in] the input buffer with the binary data
*
* @return the number of bytes needed to return the output (ie the
* required size for @p encoded). No writes occur beyond the end of
* the output buffer, so it is safe to do a speculative call where the
* encoded buffer is empty, or maybe too small. The caller should
* ensure that the returned size is smaller than the size of the
* encoded buffer.
*
* @note the result depends on endianness. If transfer between
* little/big endian systems is desired, the caller should normalize
* @p data before encoding.
*
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT size_t base64_encode(substr encoded, cblob data);
/** decode the base64 encoding in the given buffer
* @param encoded [in] the encoded base64
* @param data [out] the output buffer
*
* @return the number of bytes needed to return the output (ie the
* required size for @p data). No writes occur beyond the end of the
* output buffer, so it is safe to do a speculative call where the
* data buffer is empty, or maybe too small. The caller should ensure
* that the returned size is smaller than the size of the data buffer.
*
* @note the result depends on endianness. If transfer between
* little/big endian systems is desired, the caller should normalize
* @p data after decoding.
*
* @see https://en.wikipedia.org/wiki/Base64 */
C4CORE_EXPORT size_t base64_decode(csubstr encoded, blob data);
/** @} */ // base64
namespace fmt {
/** @addtogroup doc_format_specifiers
* @{ */
/** @defgroup doc_base64_fmt Base64
* @{ */
template<typename CharOrConstChar>
struct base64_wrapper_
{
blob_<CharOrConstChar> data;
base64_wrapper_() : data() {}
base64_wrapper_(blob_<CharOrConstChar> blob) : data(blob) {}
};
/** a tag type to mark a payload as base64-encoded */
using const_base64_wrapper = base64_wrapper_<cbyte>;
/** a tag type to mark a payload to be encoded as base64 */
using base64_wrapper = base64_wrapper_<byte>;
/** mark a variable to be written in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE const_base64_wrapper cbase64(Args const& C4_RESTRICT ...args)
{
return const_base64_wrapper(cblob(args...));
}
/** mark a csubstr to be written in base64 format */
C4_ALWAYS_INLINE const_base64_wrapper cbase64(csubstr s)
{
return const_base64_wrapper(cblob(s.str, s.len));
}
/** mark a variable to be written in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE const_base64_wrapper base64(Args const& C4_RESTRICT ...args)
{
return const_base64_wrapper(cblob(args...));
}
/** mark a csubstr to be written in base64 format */
C4_ALWAYS_INLINE const_base64_wrapper base64(csubstr s)
{
return const_base64_wrapper(cblob(s.str, s.len));
}
/** mark a variable to be read in base64 format */
template<class ...Args>
C4_ALWAYS_INLINE base64_wrapper base64(Args &... args)
{
return base64_wrapper(blob(args...));
}
/** mark a variable to be read in base64 format */
C4_ALWAYS_INLINE base64_wrapper base64(substr s)
{
return base64_wrapper(blob(s.str, s.len));
}
/** @} */ // base64_fmt
/** @} */ // format_specifiers
} // namespace fmt
/** write a variable in base64 format
* @ingroup doc_to_chars */
inline size_t to_chars(substr buf, fmt::const_base64_wrapper b)
{
return base64_encode(buf, b.data);
}
/** read a variable in base64 format
* @ingroup doc_from_chars */
inline size_t from_chars(csubstr buf, fmt::base64_wrapper *b)
{
return base64_decode(buf, b->data);
}
} // namespace c4
#endif /* _C4_BASE64_HPP_ */
-71
View File
@@ -1,71 +0,0 @@
#ifndef _C4_BLOB_HPP_
#define _C4_BLOB_HPP_
#include "c4/types.hpp"
#include "c4/error.hpp"
/** @file blob.hpp Mutable and immutable binary data blobs.
*/
namespace c4 {
template<class T>
struct blob_;
namespace detail {
template<class T> struct is_blob_type : std::integral_constant<bool, false> {};
template<class T> struct is_blob_type<blob_<T>> : std::integral_constant<bool, true> {};
template<class T> struct is_blob_value_type : std::integral_constant<bool, (std::is_fundamental<T>::value || std::is_trivially_copyable<T>::value)> {};
} // namespace
// NOLINTBEGIN(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
template<class T>
struct blob_
{
static_assert(std::is_same<T, byte>::value || std::is_same<T, cbyte>::value, "must be either byte or cbyte");
static_assert(sizeof(T) == 1u, "must be either byte or cbyte");
public:
T * buf;
size_t len;
public:
C4_ALWAYS_INLINE blob_() noexcept = default;
C4_ALWAYS_INLINE blob_(blob_ const& that) noexcept = default;
C4_ALWAYS_INLINE blob_(blob_ && that) noexcept = default;
C4_ALWAYS_INLINE blob_& operator=(blob_ && that) noexcept = default;
C4_ALWAYS_INLINE blob_& operator=(blob_ const& that) noexcept = default;
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> const& that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> && that) noexcept : buf(that.buf), len(that.len) {} // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> && that) noexcept { buf = that.buf; len = that.len; } // NOLINT
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> const& that) noexcept { buf = that.buf; len = that.len; } // NOLINT
C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {} // NOLINT
#define _C4_REQUIRE_BLOBTYPE(ty) class=typename std::enable_if<((!detail::is_blob_type<ty>::value) && (detail::is_blob_value_type<ty>::value)), T>::type
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast<T*>(&var)), len(sizeof(U)) {} // NOLINT
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); } // NOLINT
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast<T*>(&var); len = sizeof(U); return *this; } // NOLINT
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast<T*>(arr)), len(sizeof(U) * N) {} // NOLINT
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast<T*>(arr); len = sizeof(U) * N; return *this; } // NOLINT
#undef _C4_REQUIRE_BLOBTYPE
};
// NOLINTEND(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
/** an immutable binary blob */
using cblob = blob_<cbyte>;
/** a mutable binary blob */
using blob = blob_< byte>;
C4_MUST_BE_TRIVIAL_COPY(blob);
C4_MUST_BE_TRIVIAL_COPY(cblob);
} // namespace c4
#endif // _C4_BLOB_HPP_
-168
View File
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Very good intro:
@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
See also:
@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="c4::basic_substring&lt;*&gt;">
<DisplayString>{str,[len]} (sz={len})</DisplayString>
<StringView>str,[len]</StringView>
<Expand>
<Item Name="[size]">len</Item>
<ArrayItems>
<Size>len</Size>
<ValuePointer>str</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::span&lt;*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::spanrs&lt;*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- display span<char>/span<const char> as a string too -->
<Type Name="c4::span&lt;char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::span&lt;const char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- display spanrs<char>/spanrs<const char> as a string too -->
<Type Name="c4::spanrs&lt;char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="c4::spanrs&lt;const char,*&gt;">
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
<StringView>m_ptr,[m_size]</StringView>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- =========================================================================================== -->
<Type Name="c4::string_impl&lt;*,*,*,*&gt;">
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]} (sz={(($T3*)this)->m_size})</DisplayString>
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
<Expand>
<Synthetic Name="m_str">
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]}</DisplayString>
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
</Synthetic>
<Synthetic Name="m_size">
<DisplayString>{(($T3*)this)->m_size}</DisplayString>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_substring&lt;*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_substringrs&lt;*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
<Synthetic Name="[capacity]">
<DisplayString>{m_capacity}</DisplayString>
</Synthetic>
<Synthetic Name="[full]">
<DisplayString>{m_str,[m_capacity]}</DisplayString>
<StringView>m_str,[m_capacity]</StringView>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::basic_string&lt;*,*,*&gt;">
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
<StringView>m_str,[m_size]</StringView>
<Expand>
<Synthetic Name="[size]">
<DisplayString>{m_size}</DisplayString>
</Synthetic>
<Synthetic Name="[full]">
<DisplayString>{m_str,[m_capacity]}</DisplayString>
<StringView>m_str,[m_capacity]</StringView>
</Synthetic>
</Expand>
</Type>
<!-- enum symbols -->
<Type Name="c4::EnumSymbols&lt;*&gt;::Sym">
<DisplayString>{value} - {name}</DisplayString>
<Expand>
<Item Name="[value]">value</Item>
<Item Name="[name]">name</Item>
</Expand>
</Type>
<Type Name="c4::EnumSymbols&lt;*&gt;">
<DisplayString>{m_symbols,[m_num]} (sz={m_num})</DisplayString>
<Expand>
<Item Name="[size]">m_num</Item>
<ArrayItems>
<Size>m_num</Size>
<ValuePointer>m_symbols</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
File diff suppressed because it is too large Load Diff
-120
View File
@@ -1,120 +0,0 @@
#ifndef _C4_COMPILER_HPP_
#define _C4_COMPILER_HPP_
/** @file compiler.hpp Provides compiler information macros
* @ingroup basic_headers */
#include "c4/platform.hpp"
// Compilers:
// C4_MSVC
// Visual Studio 2022: MSVC++ 17, 1930
// Visual Studio 2019: MSVC++ 16, 1920
// Visual Studio 2017: MSVC++ 15
// Visual Studio 2015: MSVC++ 14
// Visual Studio 2013: MSVC++ 13
// Visual Studio 2013: MSVC++ 12
// Visual Studio 2012: MSVC++ 11
// Visual Studio 2010: MSVC++ 10
// Visual Studio 2008: MSVC++ 09
// Visual Studio 2005: MSVC++ 08
// C4_CLANG
// C4_GCC
// C4_ICC (intel compiler)
/** @see http://sourceforge.net/p/predef/wiki/Compilers/ for a list of compiler identifier macros */
/** @see https://msdn.microsoft.com/en-us/library/b0084kay.aspx for VS2013 predefined macros */
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_MSVC
# define C4_MSVC_VERSION_2022 17
# define C4_MSVC_VERSION_2019 16
# define C4_MSVC_VERSION_2017 15
# define C4_MSVC_VERSION_2015 14
# define C4_MSVC_VERSION_2013 12
# define C4_MSVC_VERSION_2012 11
# if _MSC_VER >= 1930
# define C4_MSVC_VERSION C4_MSVC_VERSION_2022 // visual studio 2022
# define C4_MSVC_2022
# elif _MSC_VER >= 1920
# define C4_MSVC_VERSION C4_MSVC_VERSION_2019 // visual studio 2019
# define C4_MSVC_2019
# elif _MSC_VER >= 1910
# define C4_MSVC_VERSION C4_MSVC_VERSION_2017 // visual studio 2017
# define C4_MSVC_2017
# elif _MSC_VER == 1900
# define C4_MSVC_VERSION C4_MSVC_VERSION_2015 // visual studio 2015
# define C4_MSVC_2015
# elif _MSC_VER == 1800
# error "MSVC version not supported"
# define C4_MSVC_VERSION C4_MSVC_VERSION_2013 // visual studio 2013
# define C4_MSVC_2013
# elif _MSC_VER == 1700
# error "MSVC version not supported"
# define C4_MSVC_VERSION C4_MSVC_VERSION_2012 // visual studio 2012
# define C4_MSVC_2012
# elif _MSC_VER == 1600
# error "MSVC version not supported"
# define C4_MSVC_VERSION 10 // visual studio 2010
# define C4_MSVC_2010
# elif _MSC_VER == 1500
# error "MSVC version not supported"
# define C4_MSVC_VERSION 09 // visual studio 2008
# define C4_MSVC_2008
# elif _MSC_VER == 1400
# error "MSVC version not supported"
# define C4_MSVC_VERSION 08 // visual studio 2005
# define C4_MSVC_2005
# else
# error "MSVC version not supported"
# endif // _MSC_VER
#else
# define C4_MSVC_VERSION 0 // visual studio not present
# define C4_GCC_LIKE
# ifdef __INTEL_COMPILER // check ICC before checking GCC, as ICC defines __GNUC__ too
# define C4_ICC
# define C4_ICC_VERSION __INTEL_COMPILER
# elif defined(__APPLE_CC__)
# define C4_XCODE
# if defined(__clang__)
# define C4_CLANG
# ifndef __apple_build_version__
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
# else
# define C4_CLANG_VERSION __apple_build_version__
# endif
# else
# define C4_XCODE_VERSION __APPLE_CC__
# endif
# elif defined(__clang__)
# define C4_CLANG
# ifndef __apple_build_version__
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
# else
# define C4_CLANG_VERSION __apple_build_version__
# endif
# elif defined(__GNUC__)
# ifdef __MINGW32__
# define C4_MINGW
# endif
# define C4_GCC
# if defined(__GNUC_PATCHLEVEL__)
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
# else
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, 0)
# endif
# if __GNUC__ < 5
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 8
// provided by cmake sub-project
# include "c4/gcc-4.8.hpp"
# else
// we do not support GCC < 4.8:
// * misses std::is_trivially_copyable
// * misses std::align
// * -Wshadow has false positives when a local function parameter has the same name as a method
# error "GCC < 4.8 is not supported"
# endif
# endif
# endif
#endif // defined(C4_WIN) && defined(_MSC_VER)
#endif /* _C4_COMPILER_HPP_ */
-39
View File
@@ -1,39 +0,0 @@
#ifndef _C4_CONFIG_HPP_
#define _C4_CONFIG_HPP_
/** @defgroup basic_headers Basic headers
* @brief Headers providing basic macros, platform+cpu+compiler information,
* C++ facilities and basic typedefs. */
/** @file config.hpp Contains configuration defines and includes the basic_headers.
* @ingroup basic_headers */
//#define C4_DEBUG
#define C4_ERROR_SHOWS_FILELINE
//#define C4_ERROR_SHOWS_FUNC
//#define C4_ERROR_THROWS_EXCEPTION
//#define C4_NO_ALLOC_DEFAULTS
//#define C4_REDEFINE_CPPNEW
#ifndef C4_SIZE_TYPE
# define C4_SIZE_TYPE size_t
#endif
#ifndef C4_STR_SIZE_TYPE
# define C4_STR_SIZE_TYPE C4_SIZE_TYPE
#endif
#ifndef C4_TIME_TYPE
# define C4_TIME_TYPE double
#endif
#include "c4/export.hpp"
#include "c4/preprocessor.hpp"
#include "c4/platform.hpp"
#include "c4/cpu.hpp"
#include "c4/compiler.hpp"
#include "c4/language.hpp"
#include "c4/types.hpp"
#endif // _C4_CONFIG_HPP_
-205
View File
@@ -1,205 +0,0 @@
#ifndef _C4_CPU_HPP_
#define _C4_CPU_HPP_
/** @file cpu.hpp Provides processor information macros
* @ingroup basic_headers */
// see also https://sourceforge.net/p/predef/wiki/Architectures/
// see also https://sourceforge.net/p/predef/wiki/Endianness/
// see also https://github.com/googlesamples/android-ndk/blob/android-mk/hello-jni/jni/hello-jni.c
// see also http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
#ifdef __ORDER_LITTLE_ENDIAN__
# define _C4EL __ORDER_LITTLE_ENDIAN__
#else
# define _C4EL 1234
#endif
#ifdef __ORDER_BIG_ENDIAN__
# define _C4EB __ORDER_BIG_ENDIAN__
#else
# define _C4EB 4321
#endif
// mixed byte order (eg, PowerPC or ia64)
#define _C4EM 1111 // NOLINT
// NOTE: to find defined macros in a platform,
// g++ <flags> -dM -E - </dev/null | sort
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
# define C4_CPU_X86_64
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EL
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define C4_CPU_X86
# define C4_WORDSIZE 4
# define C4_BYTE_ORDER _C4EL
#elif defined(__arm__) || defined(_M_ARM) \
|| defined(__TARGET_ARCH_ARM) || defined(__aarch64__) || defined(_M_ARM64)
# if defined(__aarch64__) || defined(_M_ARM64)
# define C4_CPU_ARM64
# define C4_CPU_ARMV8
# define C4_WORDSIZE 8
# else
# define C4_CPU_ARM
# define C4_WORDSIZE 4
# if defined(__ARM_ARCH_8__) || defined(__ARM_ARCH_8A__) \
|| (defined(__ARCH_ARM) && __ARCH_ARM >= 8) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 8)
# define C4_CPU_ARMV8
# elif defined(__ARM_ARCH_7__) || defined(_ARM_ARCH_7) \
|| defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) \
|| defined(__ARM_ARCH_7EM__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 7) \
|| (defined(_M_ARM) && _M_ARM >= 7)
# define C4_CPU_ARMV7
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) \
|| defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_6KZ__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 6)
# define C4_CPU_ARMV6
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 5) \
|| defined(__ARM_ARCH_5TEJ__) \
|| defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5T__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 5)
# define C4_CPU_ARMV5
# elif (defined(__ARM_ARCH) && __ARM_ARCH == 4) \
|| defined(__ARM_ARCH_4T__) \
|| defined(__ARM_ARCH_4__) \
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 4)
# define C4_CPU_ARMV4
# else
# error "unknown CPU architecture: ARM"
# endif
# endif
# if defined(__ARMEL__) || defined(__LITTLE_ENDIAN__) || defined(__AARCH64EL__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
|| defined(_MSC_VER) // winarm64 does not provide any of the above macros,
// but advises little-endianess:
// https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170
// So if it is visual studio compiling, we'll assume little endian.
# define C4_BYTE_ORDER _C4EL
# elif defined(__ARMEB__) || defined(__BIG_ENDIAN__) || defined(__AARCH64EB__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
# define C4_BYTE_ORDER _C4EB
# elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_PDP_ENDIAN__)
# define C4_BYTE_ORDER _C4EM
# else
# error "unknown endianness"
# endif
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define C4_CPU_IA64
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EM
// itanium is bi-endian - check byte order below
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \
|| defined(_M_MPPC) || defined(_M_PPC)
# if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
# define C4_CPU_PPC64
# define C4_WORDSIZE 8
# else
# define C4_CPU_PPC
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EM
// ppc is bi-endian - check byte order below
#elif defined(__s390x__) || defined(__zarch__) || defined(__SYSC_ZARCH_)
# define C4_CPU_S390_X
# define C4_WORDSIZE 8
# define C4_BYTE_ORDER _C4EB
#elif defined(__xtensa__) || defined(__XTENSA__)
# define C4_CPU_XTENSA
# define C4_WORDSIZE 4
// not sure about this...
# if defined(__XTENSA_EL__) || defined(__xtensa_el__)
# define C4_BYTE_ORDER _C4EL
# else
# define C4_BYTE_ORDER _C4EB
# endif
#elif defined(__riscv)
# if __riscv_xlen == 64
# define C4_CPU_RISCV64
# define C4_WORDSIZE 8
# else
# define C4_CPU_RISCV32
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EL
#elif defined(__EMSCRIPTEN__)
# define C4_BYTE_ORDER _C4EL
# define C4_WORDSIZE 4
#elif defined(__loongarch__)
# if defined(__loongarch64)
# define C4_CPU_LOONGARCH64
# define C4_WORDSIZE 8
# else
# define C4_CPU_LOONGARCH
# define C4_WORDSIZE 4
# endif
# define C4_BYTE_ORDER _C4EL
#elif defined(__mips__) || defined(_mips) || defined(mips)
# if defined(__mips)
# if __mips == 64
# define C4_CPU_MIPS64
# define C4_WORDSIZE 8
# elif __mips == 32
# define C4_CPU_MIPS32
# define C4_WORDSIZE 4
# endif
# elif defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
# define C4_CPU_MIPS64
# define C4_WORDSIZE 8
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
# define C4_CPU_MIPS32
# define C4_WORDSIZE 4
# else
# error "unknown mips architecture"
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define C4_BYTE_ORDER _C4EB
# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define C4_BYTE_ORDER _C4EL
# else
# error "unknown mips endianness"
# endif
#elif defined(__sparc__) || defined(__sparc) || defined(sparc)
# if defined(__arch64__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 64) || (defined(__LP64__) && __LP64__)
# define C4_CPU_SPARC64
# define C4_WORDSIZE 8
# elif defined(__arch32__) || (defined(__SIZE_WIDTH__) && __SIZE_WIDTH__ == 32) || (defined(__LP32__) && __LP32__)
# define C4_CPU_SPARC32
# define C4_WORDSIZE 4
# else
# error "unknown sparc architecture"
# endif
# define C4_BYTE_ORDER _C4EB
#elif defined(SWIG)
# error "please define CPU architecture macros when compiling with swig"
#else
# error "unknown CPU architecture"
#endif
#define C4_LITTLE_ENDIAN (C4_BYTE_ORDER == _C4EL)
#define C4_BIG_ENDIAN (C4_BYTE_ORDER == _C4EB)
#define C4_MIXED_ENDIAN (C4_BYTE_ORDER == _C4EM)
#endif /* _C4_CPU_HPP_ */
-798
View File
@@ -1,798 +0,0 @@
#ifndef C4_DUMP_HPP_
#define C4_DUMP_HPP_
#include <c4/substr.hpp>
/** @file dump.hpp This file provides functions to dump several
* arguments as strings to a user-provided function sink, for example
* to implement a type-safe printf()-like function (where the sink
* would just be a plain call to putchars()). The function sink can be
* passed either by dynamic dispatching or by static dispatching (as a
* template argument). There are analogs to @ref c4::cat() (@ref
* c4::cat_dump() and @ref c4::cat_dump_resume()), @ref c4::catsep()
* (@ref catsetp_dump() and @ref catsep_dump_resume()) and @ref
* c4::format() (@ref c4::format_dump() and @ref
* c4::format_dump_resume()). The analogs have two types: immediate
* and resuming. An analog of immediate type cannot be retried when
* the work buffer is too small; this means that successful dumps in
* the first (successful) arguments will be dumped again in the
* subsequent attempt to call. An analog of resuming type will only
* ever dump as-yet-undumped arguments, through the use of @ref
* DumpResults return type. */
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup dump_building_blocks Basic building blocks for dumping.
*
* The basic building block: given an argument and a
* buffer, serialize the argument to the buffer using @ref
* c4::to_chars(), and dump the buffer to the provided sink
* function. When the argument is a string, no serialization is
* performed, and the argument is dumped directly to the sink.
*
* @{ */
/** Type of the function to be used as the sink. This function
* receives as its argument the string with characters to send to the
* sink.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
* */
using SinkPfn = void (*)(csubstr str);
/** a traits class to use in SFINAE with @ref c4::dump() to select if
* a type is treated as string type (which is dumped directly to the
* sink, using to_csubstr()), or if the type is treated as a value,
* which is first serialized to a buffer using to_chars(), and then
* the serialization serialized as */
template<class T> struct dump_directly : public std::false_type {};
template<> struct dump_directly<csubstr> : public std::true_type {};
template<> struct dump_directly< substr> : public std::true_type {};
template<> struct dump_directly<const char*> : public std::true_type {};
template<> struct dump_directly< char*> : public std::true_type {};
template<size_t N> struct dump_directly<const char (&)[N]> : public std::true_type {};
template<size_t N> struct dump_directly< char (&)[N]> : public std::true_type {};
template<size_t N> struct dump_directly<const char[N]> : public std::true_type {};
template<size_t N> struct dump_directly< char[N]> : public std::true_type {};
/** Dump a string-type object to the (statically dispatched) sink. The
* string is dumped directly, without any intermediate serialization.
*
* @return the number of bytes needed to serialize the string-type
* object, which is always 0 because there is no serialization
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
*
* @see dump_directly<T>
*/
template<SinkPfn sinkfn, class Arg>
inline auto dump(substr buf, Arg const& a)
-> typename std::enable_if<dump_directly<Arg>::value, size_t>::type
{
C4_ASSERT(!buf.overlaps(a));
C4_UNUSED(buf);
// dump directly, no need to serialize to the buffer
sinkfn(to_csubstr(a));
return 0; // no space was used in the buffer
}
/** Dump a string-type object to the (dynamically dispatched)
* sink. The string is dumped directly, without any intermediate
* serialization to the buffer.
*
* @return the number of bytes needed to serialize the string-type
* object, which is always 0 because there is no serialization
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @warning the string passed to the sink may have zero length. If the
* user sink uses memcpy(), the call to memcpy() should be defended
* with a check for zero length (calling memcpy with zero length is
* undefined behavior).
*
* @see dump_directly<T>
* */
template<class SinkFn, class Arg>
inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a)
-> typename std::enable_if<dump_directly<Arg>::value, size_t>::type
{
C4_UNUSED(buf);
C4_ASSERT(!buf.overlaps(a));
// dump directly, no need to serialize to the buffer
std::forward<SinkFn>(sinkfn)(to_csubstr(a));
return 0; // no space was used in the buffer
}
/** Dump a value to the sink. Given an argument @p a and a buffer @p
* buf, serialize the argument to the buffer using @ref to_chars(),
* and then dump the buffer to the (statically dispatched) sink
* function passed as the template argument. If the buffer is too
* small to serialize the argument, the sink function is not called.
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @see dump_directly<T>
*
* @return the number of characters required to serialize the
* argument. */
template<SinkPfn sinkfn, class Arg>
inline auto dump(substr buf, Arg const& a)
-> typename std::enable_if<!dump_directly<Arg>::value, size_t>::type
{
// serialize to the buffer
const size_t sz = to_chars(buf, a);
// dump the buffer to the sink
if(C4_LIKELY(sz <= buf.len))
{
// NOTE: don't do this:
//sinkfn(buf.first(sz));
// ... but do this instead:
sinkfn({buf.str, sz});
// ... this is needed because Release builds for armv5 and
// armv6 were failing for the first call, with the wrong
// buffer being passed into the function (!)
}
return sz;
}
/** Dump a value to the sink. Given an argument @p a and a buffer @p
* buf, serialize the argument to the buffer using @ref
* c4::to_chars(), and then dump the buffer to the (dynamically
* dispatched) sink function, passed as @p sinkfn. If the buffer is too
* small to serialize the argument, the sink function is not called.
*
* @note the argument is considered a value when @ref
* dump_directly<Arg> is a false type, which is the default. To enable
* the argument to be treated as a string type, which is dumped
* directly to the sink without intermediate serialization, define
* dump_directly<T> to a true type.
*
* @see @ref dump_directly<T>
*
* @return the number of characters required to serialize the
* argument. */
template<class SinkFn, class Arg>
inline auto dump(SinkFn &&sinkfn, substr buf, Arg const& a)
-> typename std::enable_if<!dump_directly<Arg>::value, size_t>::type
{
// serialize to the buffer
const size_t sz = to_chars(buf, a);
// dump the buffer to the sink
if(C4_LIKELY(sz <= buf.len))
{
// NOTE: don't do this:
//std::forward<SinkFn>(sinkfn)(buf.first(sz));
// ... but do this instead:
std::forward<SinkFn>(sinkfn)({buf.str, sz});
// ... this is needed because Release builds for armv5 and
// armv6 were failing for the first call, with the wrong
// buffer being passed into the function (!)
}
return sz;
}
/** An opaque type used by resumeable dump functions like @ref
* cat_dump_resume(), @ref catsep_dump_resume() or @ref
* format_dump_resume(). */
struct DumpResults
{
enum : size_t { noarg = (size_t)-1 };
size_t bufsize = 0;
size_t lastok = noarg;
bool success_until(size_t expected) const { return lastok == noarg ? false : lastok >= expected; }
bool write_arg(size_t arg) const { return lastok == noarg || arg > lastok; }
size_t argfail() const { return lastok + 1; }
};
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup cat_dump Dump several arguments to a sink,
* concatenated. This is the analog to @ref c4::cat(), with the
* significant difference that each argument is immediately sent to
* the sink (resulting in multiple calls to the sink function, once
* per argument), whereas equivalent usage of c4::cat() would first
* serialize all the arguments to the buffer, and then call the sink
* once at the end. As a consequence, the size needed for the buffer
* is only the maximum of the size needed for the arguments, whereas
* with c4::cat(), the size needed for the buffer would be the sum of
* the size needed for the arguments. When the size of dump
*
* @{ */
/// @cond dev
// terminates the variadic recursion
template<class SinkFn>
size_t cat_dump(SinkFn &&, substr) // NOLINT
{
return 0;
}
// terminates the variadic recursion
template<SinkPfn sinkfn>
size_t cat_dump(substr) // NOLINT
{
return 0;
}
/// @endcond
/** Dump several arguments to the (dynamically dispatched) sink
* function, as if through c4::cat(). For each argument, @ref dump()
* is called with the buffer and sink. If any of the arguments is too
* large for the buffer, no subsequent argument is sent to the sink,
* (but all the arguments are still processed to compute the size
* required for the buffer). This function can be safely called with an
* empty buffer.
*
* @return the size required for the buffer, which is the maximum size
* across all arguments
*
* @note subsequent calls with the same set of arguments will dump
* again the first successful arguments. If each argument must only be
* sent once to the sink (for example with printf-like behavior), use
* instead @ref cat_dump_resume(). */
template<class SinkFn, class Arg, class... Args>
size_t cat_dump(SinkFn &&sinkfn, substr buf, Arg const& a, Args const& ...more)
{
const size_t size_for_a = dump(std::forward<SinkFn>(sinkfn), buf, a);
if(C4_UNLIKELY(size_for_a > buf.len))
buf.len = 0; // ensure no more calls to the sink
const size_t size_for_more = cat_dump(std::forward<SinkFn>(sinkfn), buf, more...);
return size_for_more > size_for_a ? size_for_more : size_for_a;
}
/** Dump several arguments to the (statically dispatched) sink
* function, as if through c4::cat(). For each argument, @ref dump()
* is called with the buffer and sink. If any of the arguments is too
* large for the buffer, no subsequent argument is sent to the sink,
* (but all the arguments are still processed to compute the size
* required for the buffer). This function can be safely called with an
* empty buffer.
*
* @return the size required for the buffer, which is the maximum size
* across all arguments
*
* @note subsequent calls with the same set of arguments will dump
* again the first successful arguments. If each argument must only be
* sent once to the sink (for example with printf-like behavior), use
* instead @ref cat_dump_resume(). */
template<SinkPfn sinkfn, class Arg, class... Args>
size_t cat_dump(substr buf, Arg const& a, Args const& ...more)
{
const size_t size_for_a = dump<sinkfn>(buf, a);
if(C4_UNLIKELY(size_for_a > buf.len))
buf.len = 0; // ensure no more calls to the sink
const size_t size_for_more = cat_dump<sinkfn>(buf, more...);
return size_for_more > size_for_a ? size_for_more : size_for_a;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminates the variadic recursion
template<SinkPfn sinkfn>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, DumpResults results, substr)
{
return results;
}
// terminates the variadic recursion
template<class SinkFn>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(size_t, SinkFn &&, DumpResults results, substr) // NOLINT
{
return results;
}
template<SinkPfn sinkfn, class Arg, class... Args>
DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
size_t sz = dump<sinkfn>(buf, a); // yield to the specialized function
if(currarg == results.lastok + 1 && sz <= buf.len)
results.lastok = currarg;
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
}
return detail::cat_dump_resume<sinkfn>(currarg + 1u, results, buf, more...);
}
template<class SinkFn, class Arg, class... Args>
DumpResults cat_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), buf, a); // yield to the specialized function
if(currarg == results.lastok + 1 && sz <= buf.len)
results.lastok = currarg;
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
}
return detail::cat_dump_resume(currarg + 1u, std::forward<SinkFn>(sinkfn), results, buf, more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
return detail::cat_dump_resume<sinkfn>(0u, DumpResults{}, buf, a, more...);
}
template<class SinkFn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(SinkFn &&sinkfn, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
return detail::cat_dump_resume(0u, std::forward<SinkFn>(sinkfn), DumpResults{}, buf, a, more...);
}
template<SinkPfn sinkfn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(results.bufsize > buf.len)
return results;
return detail::cat_dump_resume<sinkfn>(0u, results, buf, a, more...);
}
template<class SinkFn, class Arg, class... Args>
C4_ALWAYS_INLINE DumpResults cat_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& ...more)
{
if(results.bufsize > buf.len)
return results;
return detail::cat_dump_resume(0u, std::forward<SinkFn>(sinkfn), results, buf, a, more...);
}
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
// terminate the recursion
template<class SinkFn, class Sep>
size_t catsep_dump(SinkFn &&, substr, Sep const& C4_RESTRICT) // NOLINT
{
return 0;
}
// terminate the recursion
template<SinkPfn sinkfn, class Sep>
size_t catsep_dump(substr, Sep const& C4_RESTRICT) // NOLINT
{
return 0;
}
/// @endcond
/** take the function pointer as a function argument */
template<class SinkFn, class Sep, class Arg, class... Args>
size_t catsep_dump(SinkFn &&sinkfn, substr buf, Sep const& sep, Arg const& a, Args const& ...more)
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), buf, a);
if(C4_UNLIKELY(sz > buf.len))
buf.len = 0; // ensure no more calls
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
{
size_t szsep = dump(std::forward<SinkFn>(sinkfn), buf, sep);
if(C4_UNLIKELY(szsep > buf.len))
buf.len = 0; // ensure no more calls
sz = sz > szsep ? sz : szsep;
}
size_t size_for_more = catsep_dump(std::forward<SinkFn>(sinkfn), buf, sep, more...);
return size_for_more > sz ? size_for_more : sz;
}
/** take the function pointer as a template argument */
template<SinkPfn sinkfn, class Sep, class Arg, class... Args>
size_t catsep_dump(substr buf, Sep const& sep, Arg const& a, Args const& ...more)
{
size_t sz = dump<sinkfn>(buf, a);
if(C4_UNLIKELY(sz > buf.len))
buf.len = 0; // ensure no more calls
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
{
size_t szsep = dump<sinkfn>(buf, sep);
if(C4_UNLIKELY(szsep > buf.len))
buf.len = 0; // ensure no more calls
sz = sz > szsep ? sz : szsep;
}
size_t size_for_more = catsep_dump<sinkfn>(buf, sep, more...);
return size_for_more > sz ? size_for_more : sz;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
template<SinkPfn sinkfn, class Arg>
void catsep_dump_resume_(size_t currarg, DumpResults *C4_RESTRICT results, substr *buf, Arg const& a)
{
if(C4_LIKELY(results->write_arg(currarg)))
{
size_t sz = dump<sinkfn>(*buf, a);
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
if(C4_LIKELY(sz <= buf->len))
results->lastok = currarg;
else
buf->len = 0;
}
}
template<class SinkFn, class Arg>
void catsep_dump_resume_(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
{
if(C4_LIKELY(results->write_arg(currarg)))
{
size_t sz = dump(std::forward<SinkFn>(sinkfn), *buf, a);
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
if(C4_LIKELY(sz <= buf->len))
results->lastok = currarg;
else
buf->len = 0;
}
}
template<SinkPfn sinkfn, class Sep, class Arg>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const&, Arg const& a)
{
detail::catsep_dump_resume_<sinkfn>(currarg, results, buf, a);
}
template<class SinkFn, class Sep, class Arg>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const&, Arg const& a)
{
detail::catsep_dump_resume_(currarg, std::forward<SinkFn>(sinkfn), results, buf, a);
}
template<SinkPfn sinkfn, class Sep, class Arg, class... Args>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& sep, Arg const& a, Args const& ...more)
{
detail::catsep_dump_resume_<sinkfn>(currarg , results, buf, a);
detail::catsep_dump_resume_<sinkfn>(currarg + 1u, results, buf, sep);
detail::catsep_dump_resume <sinkfn>(currarg + 2u, results, buf, sep, more...);
}
template<class SinkFn, class Sep, class Arg, class... Args>
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& sep, Arg const& a, Args const& ...more)
{
detail::catsep_dump_resume_(currarg , std::forward<SinkFn>(sinkfn), results, buf, a);
detail::catsep_dump_resume_(currarg + 1u, std::forward<SinkFn>(sinkfn), results, buf, sep);
detail::catsep_dump_resume (currarg + 2u, std::forward<SinkFn>(sinkfn), results, buf, sep, more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(substr buf, Sep const& sep, Args const& ...args)
{
DumpResults results;
detail::catsep_dump_resume<sinkfn>(0u, &results, &buf, sep, args...);
return results;
}
template<class SinkFn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(SinkFn &&sinkfn, substr buf, Sep const& sep, Args const& ...args)
{
DumpResults results;
detail::catsep_dump_resume(0u, std::forward<SinkFn>(sinkfn), &results, &buf, sep, args...);
return results;
}
template<SinkPfn sinkfn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumpResults results, substr buf, Sep const& sep, Args const& ...args)
{
detail::catsep_dump_resume<sinkfn>(0u, &results, &buf, sep, args...);
return results;
}
template<class SinkFn, class Sep, class... Args>
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, Sep const& sep, Args const& ...args)
{
detail::catsep_dump_resume(0u, std::forward<SinkFn>(sinkfn), &results, &buf, sep, args...);
return results;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminate the recursion
C4_ALWAYS_INLINE size_t _format_dump_compute_size()
{
return 0u;
}
template<class T>
C4_ALWAYS_INLINE auto _format_dump_compute_size(T const&)
-> typename std::enable_if<dump_directly<T>::value, size_t>::type
{
return 0u; // no buffer needed
}
template<class T>
C4_ALWAYS_INLINE auto _format_dump_compute_size(T const& v)
-> typename std::enable_if<!dump_directly<T>::value, size_t>::type
{
return to_chars(substr{}, v);
}
template<class Arg, class... Args>
size_t _format_dump_compute_size(Arg const& a, Args const& ...more)
{
const size_t sz = _format_dump_compute_size(a); // don't call to_chars() directly
const size_t rest = _format_dump_compute_size(more...);
return sz > rest ? sz : rest;
}
} // namespace detail
// terminate the recursion
template<class SinkFn>
C4_ALWAYS_INLINE size_t format_dump(SinkFn &&sinkfn, substr, csubstr fmt)
{
// we can dump without using buf, so no need to check it
std::forward<SinkFn>(sinkfn)(fmt);
return 0u;
}
// terminate the recursion
/** take the function pointer as a template argument */
template<SinkPfn sinkfn>
C4_ALWAYS_INLINE size_t format_dump(substr, csubstr fmt)
{
// we can dump without using buf, so no need to check it
sinkfn(fmt);
return 0u;
}
/// @endcond
/** take the function pointer as a function argument */
template<class SinkFn, class Arg, class... Args>
C4_NO_INLINE size_t format_dump(SinkFn &&sinkfn, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we can dump without using buf
// but we'll only dump if the buffer is ok
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_UNLIKELY(pos == csubstr::npos))
{
std::forward<SinkFn>(sinkfn)(fmt);
return 0u;
}
std::forward<SinkFn>(sinkfn)(fmt.first(pos)); // we can dump without using buf
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
pos = dump(std::forward<SinkFn>(sinkfn), buf, a); // reuse pos to get needed_size
// dump no more if the buffer was exhausted
size_t size_for_more;
if(C4_LIKELY(pos <= buf.len))
size_for_more = format_dump(std::forward<SinkFn>(sinkfn), buf, fmt, more...);
else
size_for_more = detail::_format_dump_compute_size(more...);
return size_for_more > pos ? size_for_more : pos;
}
/** take the function pointer as a template argument */
template<SinkPfn sinkfn, class Arg, class... Args>
C4_NO_INLINE size_t format_dump(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& ...more)
{
// we can dump without using buf
// but we'll only dump if the buffer is ok
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_UNLIKELY(pos == csubstr::npos))
{
sinkfn(fmt);
return 0u;
}
sinkfn(fmt.first(pos)); // we can dump without using buf
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
pos = dump<sinkfn>(buf, a); // reuse pos to get needed_size
// dump no more if the buffer was exhausted
size_t size_for_more;
if(C4_LIKELY(pos <= buf.len))
size_for_more = format_dump<sinkfn>(buf, fmt, more...);
else
size_for_more = detail::_format_dump_compute_size(more...);
return size_for_more > pos ? size_for_more : pos;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
namespace detail {
// terminate the recursion
template<SinkPfn sinkfn>
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr, csubstr fmt)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
// we can dump without using buf
sinkfn(fmt);
results.lastok = currarg;
}
return results;
}
// terminate the recursion
template<class SinkFn>
DumpResults format_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr, csubstr fmt)
{
if(C4_LIKELY(results.write_arg(currarg)))
{
// we can dump without using buf
std::forward<SinkFn>(sinkfn)(fmt);
results.lastok = currarg;
}
return results;
}
template<SinkPfn sinkfn, class Arg, class... Args>
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we need to process the format even if we're not
// going to print the first arguments because we're resuming
const size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_LIKELY(pos != csubstr::npos))
{
if(C4_LIKELY(results.write_arg(currarg)))
{
sinkfn(fmt.first(pos));
results.lastok = currarg;
}
if(C4_LIKELY(results.write_arg(currarg + 1u)))
{
const size_t len = dump<sinkfn>(buf, a);
results.bufsize = len > results.bufsize ? len : results.bufsize;
if(C4_LIKELY(len <= buf.len))
{
results.lastok = currarg + 1u;
}
else
{
const size_t rest = _format_dump_compute_size(more...);
results.bufsize = rest > results.bufsize ? rest : results.bufsize;
return results;
}
}
}
else
{
if(C4_LIKELY(results.write_arg(currarg)))
{
sinkfn(fmt);
results.lastok = currarg;
}
return results;
}
// NOTE: sparc64 had trouble with reassignment to fmt, and
// was passing the original fmt to the recursion:
//fmt = fmt.sub(pos + 2); // DONT!
return detail::format_dump_resume<sinkfn>(currarg + 2u, results, buf, fmt.sub(pos + 2), more...);
}
template<class SinkFn, class Arg, class... Args>
DumpResults format_dump_resume(size_t currarg, SinkFn &&sinkfn, DumpResults results, substr buf, csubstr fmt, Arg const& a, Args const& ...more)
{
// we need to process the format even if we're not
// going to print the first arguments because we're resuming
const size_t pos = fmt.find("{}"); // @todo use _find_fmt()
if(C4_LIKELY(pos != csubstr::npos))
{
if(C4_LIKELY(results.write_arg(currarg)))
{
std::forward<SinkFn>(sinkfn)(fmt.first(pos));
results.lastok = currarg;
}
if(C4_LIKELY(results.write_arg(currarg + 1u)))
{
const size_t len = dump(std::forward<SinkFn>(sinkfn), buf, a);
results.bufsize = len > results.bufsize ? len : results.bufsize;
if(C4_LIKELY(len <= buf.len))
{
results.lastok = currarg + 1u;
}
else
{
const size_t rest = _format_dump_compute_size(more...);
results.bufsize = rest > results.bufsize ? rest : results.bufsize;
return results;
}
}
}
else
{
if(C4_LIKELY(results.write_arg(currarg)))
{
std::forward<SinkFn>(sinkfn)(fmt);
results.lastok = currarg;
}
return results;
}
// NOTE: sparc64 had trouble with reassignment to fmt, and
// was passing the original fmt to the recursion:
//fmt = fmt.sub(pos + 2); // DONT!
return detail::format_dump_resume(currarg + 2u, std::forward<SinkFn>(sinkfn), results, buf, fmt.sub(pos + 2), more...);
}
} // namespace detail
/// @endcond
template<SinkPfn sinkfn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume<sinkfn>(0u, DumpResults{}, buf, fmt, args...);
}
template<class SinkFn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(SinkFn &&sinkfn, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume(0u, std::forward<SinkFn>(sinkfn), DumpResults{}, buf, fmt, args...);
}
template<SinkPfn sinkfn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(DumpResults results, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume<sinkfn>(0u, results, buf, fmt, args...);
}
template<class SinkFn, class... Args>
C4_ALWAYS_INLINE DumpResults format_dump_resume(SinkFn &&sinkfn, DumpResults results, substr buf, csubstr fmt, Args const& ...args)
{
return detail::format_dump_resume(0u, std::forward<SinkFn>(sinkfn), results, buf, fmt, args...);
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
#endif /* C4_DUMP_HPP_ */
-440
View File
@@ -1,440 +0,0 @@
#ifndef _C4_ERROR_HPP_
#define _C4_ERROR_HPP_
/** @file error.hpp Facilities for error reporting and runtime assertions. */
/** @defgroup error_checking Error checking */
#include "c4/config.hpp"
#ifdef _DOXYGEN_
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
* will throw an exception
* @ingroup error_checking */
# define C4_EXCEPTIONS_ENABLED
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
* will throw an exception
* @see C4_EXCEPTIONS_ENABLED
* @ingroup error_checking */
# define C4_ERROR_THROWS_EXCEPTION
/** evaluates to noexcept when C4_ERROR might be called and
* exceptions are disabled. Otherwise, defaults to nothing.
* @ingroup error_checking */
# define C4_NOEXCEPT
#endif // _DOXYGEN_
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
# define C4_NOEXCEPT
#else
# define C4_NOEXCEPT noexcept
#endif
namespace c4 {
namespace detail {
struct fail_type__ {};
} // detail
} // c4
#define C4_STATIC_ERROR(dummy_type, errmsg) \
static_assert(std::is_same<dummy_type, c4::detail::fail_type__>::value, errmsg)
//-----------------------------------------------------------------------------
#define C4_ASSERT_SAME_TYPE(ty1, ty2) \
C4_STATIC_ASSERT(std::is_same<ty1 C4_COMMA_X ty2>::value)
#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \
C4_STATIC_ASSERT( ! std::is_same<ty1 C4_COMMA_X ty2>::value)
//-----------------------------------------------------------------------------
#ifdef _DOXYGEN_
/** utility macro that triggers a breakpoint when
* the debugger is attached and NDEBUG is not defined.
* @ingroup error_checking */
# define C4_DEBUG_BREAK()
#endif // _DOXYGEN_
#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
# define C4_DEBUG_BREAK()
#else
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wundef"
# if !defined(__APPLE_CC__)
# if __clang_major__ >= 10
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
# endif
# else
# if __clang_major__ >= 13
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
# endif
# endif
# elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wundef"
# endif
# include <c4/ext/debugbreak/debugbreak.h>
# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }
# ifdef __clang__
# pragma clang diagnostic pop
# elif defined(__GNUC__)
# pragma GCC diagnostic pop
# endif
#endif
namespace c4 {
C4CORE_EXPORT bool is_debugger_attached();
} // namespace c4
//-----------------------------------------------------------------------------
#ifdef __clang__
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
* clang requires switching off compiler warnings for pedantic mode.
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
/* GCC also issues a warning for zero-args calls to variadic macros.
* This warning is switched on with -pedantic and apparently there is no
* easy way to turn it off as with clang. But marking this as a system
* header works.
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
* @see http://stackoverflow.com/questions/35587137/ */
# pragma GCC system_header
#endif
//-----------------------------------------------------------------------------
namespace c4 {
typedef enum : uint32_t {
/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().
* Without effect otherwise. */
ON_ERROR_DEBUGBREAK = 0x01u << 0u,
/** when an error happens log a message. */
ON_ERROR_LOG = 0x01u << 1u,
/** when an error happens invoke a callback if it was set with
* set_error_callback(). */
ON_ERROR_CALLBACK = 0x01u << 2u,
/** when an error happens call std::terminate(). */
ON_ERROR_ABORT = 0x01u << 3u,
/** when an error happens and exceptions are enabled throw an exception.
* Without effect otherwise. */
ON_ERROR_THROW = 0x01u << 4u,
/** the default flags. */
ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT
} ErrorFlags_e;
using error_flags = uint32_t;
C4CORE_EXPORT void set_error_flags(error_flags f);
C4CORE_EXPORT error_flags get_error_flags();
using error_callback_type = void (*)(const char* msg, size_t msg_size);
C4CORE_EXPORT void set_error_callback(error_callback_type cb);
C4CORE_EXPORT error_callback_type get_error_callback();
//-----------------------------------------------------------------------------
/** RAII class controling the error settings inside a scope. */
struct ScopedErrorSettings // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
{
error_flags m_flags;
error_callback_type m_callback;
explicit ScopedErrorSettings(error_callback_type cb)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_callback(cb);
}
explicit ScopedErrorSettings(error_flags flags)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_flags(flags);
}
explicit ScopedErrorSettings(error_flags flags, error_callback_type cb)
: m_flags(get_error_flags()),
m_callback(get_error_callback())
{
set_error_flags(flags);
set_error_callback(cb);
}
~ScopedErrorSettings()
{
set_error_flags(m_flags);
set_error_callback(m_callback);
}
};
//-----------------------------------------------------------------------------
/** source location */
struct srcloc;
// watchout: for VS the [[noreturn]] needs to come before other annotations like C4CORE_EXPORT
[[noreturn]] C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);
# define C4_ERROR(msg, ...) \
do { \
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
{ \
C4_DEBUG_BREAK() \
} \
c4::handle_error(C4_SRCLOC(), msg, ## __VA_ARGS__); \
} while(0)
# define C4_WARNING(msg, ...) \
c4::handle_warning(C4_SRCLOC(), msg, ## __VA_ARGS__)
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
struct srcloc
{
const char *file = "";
const char *func = "";
int line = 0;
};
#define C4_SRCLOC() c4::srcloc{__FILE__, C4_PRETTY_FUNC, __LINE__}
#elif defined(C4_ERROR_SHOWS_FILELINE)
struct srcloc
{
const char *file;
int line;
};
#define C4_SRCLOC() c4::srcloc{__FILE__, __LINE__}
#elif ! defined(C4_ERROR_SHOWS_FUNC)
struct srcloc
{
};
#define C4_SRCLOC() c4::srcloc()
#else
# error not implemented
#endif
//-----------------------------------------------------------------------------
// assertions
// Doxygen needs this so that only one definition counts
#ifdef _DOXYGEN_
/** Explicitly enables assertions, independently of NDEBUG status.
* This is meant to allow enabling assertions even when NDEBUG is defined.
* Defaults to undefined.
* @ingroup error_checking */
# define C4_USE_ASSERT
/** assert that a condition is true; this is turned off when NDEBUG
* is defined and C4_USE_ASSERT is not true.
* @ingroup error_checking */
# define C4_ASSERT
/** same as C4_ASSERT(), additionally prints a printf-formatted message
* @ingroup error_checking */
# define C4_ASSERT_MSG
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults
* to noexcept
* @ingroup error_checking */
# define C4_NOEXCEPT_A
#endif // _DOXYGEN_
#ifndef C4_USE_ASSERT
# ifdef NDEBUG
# define C4_USE_ASSERT 0
# else
# define C4_USE_ASSERT 1
# endif
#endif
#if C4_USE_ASSERT
# define C4_ASSERT(cond) C4_CHECK(cond)
# define C4_ASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
# define C4_ASSERT_IF(predicate, cond) if(predicate) { C4_ASSERT(cond); }
# define C4_NOEXCEPT_A C4_NOEXCEPT
#else
# define C4_ASSERT(cond)
# define C4_ASSERT_MSG(cond, /*fmt, */...)
# define C4_ASSERT_IF(predicate, cond)
# define C4_NOEXCEPT_A noexcept
#endif
//-----------------------------------------------------------------------------
// extreme assertions
// Doxygen needs this so that only one definition counts
#ifdef _DOXYGEN_
/** Explicitly enables extreme assertions; this is meant to allow enabling
* assertions even when NDEBUG is defined. Defaults to undefined.
* @ingroup error_checking */
# define C4_USE_XASSERT
/** extreme assertion: can be switched off independently of
* the regular assertion; use for example for bounds checking in hot code.
* Turned on only when C4_USE_XASSERT is defined
* @ingroup error_checking */
# define C4_XASSERT
/** same as C4_XASSERT(), and additionally prints a printf-formatted message
* @ingroup error_checking */
# define C4_XASSERT_MSG
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults to noexcept
* @ingroup error_checking */
# define C4_NOEXCEPT_X
#endif // _DOXYGEN_
#ifndef C4_USE_XASSERT
# define C4_USE_XASSERT C4_USE_ASSERT
#endif
#if C4_USE_XASSERT
# define C4_XASSERT(cond) C4_CHECK(cond)
# define C4_XASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
# define C4_XASSERT_IF(predicate, cond) if(predicate) { C4_XASSERT(cond); }
# define C4_NOEXCEPT_X C4_NOEXCEPT
#else
# define C4_XASSERT(cond)
# define C4_XASSERT_MSG(cond, /*fmt, */...)
# define C4_XASSERT_IF(predicate, cond)
# define C4_NOEXCEPT_X noexcept
#endif
//-----------------------------------------------------------------------------
// checks: never switched-off
/** Check that a condition is true, or raise an error when not
* true. Unlike C4_ASSERT(), this check is not disabled in non-debug
* builds.
* @see C4_ASSERT
* @ingroup error_checking
*
* @todo add constexpr-compatible compile-time assert:
* https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
*/
#define C4_CHECK(cond) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
C4_ERROR("check failed: %s", #cond); \
} \
} while(0)
/** like C4_CHECK(), and additionally log a printf-style message.
* @see C4_CHECK
* @ingroup error_checking */
#define C4_CHECK_MSG(cond, fmt, ...) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
C4_ERROR("check failed: " #cond "\n" fmt, ## __VA_ARGS__); \
} \
} while(0)
//-----------------------------------------------------------------------------
// Common error conditions
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
#define C4_NOT_IMPLEMENTED_MSG(/*msg, */...) C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__)
#define C4_NOT_IMPLEMENTED_IF(condition) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); } } while(0)
#define C4_NOT_IMPLEMENTED_IF_MSG(condition, /*msg, */...) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__); } } while(0)
#define C4_NEVER_REACH() do { C4_ERROR("never reach this point"); C4_UNREACHABLE(); } while(0)
#define C4_NEVER_REACH_MSG(/*msg, */...) do { C4_ERROR("never reach this point: " __VA_ARGS__); C4_UNREACHABLE(); } while(0)
//-----------------------------------------------------------------------------
// helpers for warning suppression
// idea adapted from https://github.com/onqtam/doctest/
// TODO: add C4_MESSAGE() https://stackoverflow.com/questions/18252351/custom-preprocessor-macro-for-a-conditional-pragma-message-xxx?rq=1
#ifdef C4_MSVC
#define C4_SUPPRESS_WARNING_MSVC_PUSH __pragma(warning(push))
#define C4_SUPPRESS_WARNING_MSVC(w) __pragma(warning(disable : w))
#define C4_SUPPRESS_WARNING_MSVC_POP __pragma(warning(pop))
#else // C4_MSVC
#define C4_SUPPRESS_WARNING_MSVC_PUSH
#define C4_SUPPRESS_WARNING_MSVC(w)
#define C4_SUPPRESS_WARNING_MSVC_POP
#endif // C4_MSVC
#ifdef C4_CLANG
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
#define C4_SUPPRESS_WARNING_CLANG_PUSH _Pragma("clang diagnostic push")
#define C4_SUPPRESS_WARNING_CLANG(w) C4_PRAGMA_TO_STR(clang diagnostic ignored w)
#define C4_SUPPRESS_WARNING_CLANG_POP _Pragma("clang diagnostic pop")
#else // C4_CLANG
#define C4_SUPPRESS_WARNING_CLANG_PUSH
#define C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_CLANG_POP
#endif // C4_CLANG
#ifdef C4_GCC
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
#define C4_SUPPRESS_WARNING_GCC_PUSH _Pragma("GCC diagnostic push")
#define C4_SUPPRESS_WARNING_GCC(w) C4_PRAGMA_TO_STR(GCC diagnostic ignored w)
#define C4_SUPPRESS_WARNING_GCC_POP _Pragma("GCC diagnostic pop")
#else // C4_GCC
#define C4_SUPPRESS_WARNING_GCC_PUSH
#define C4_SUPPRESS_WARNING_GCC(w)
#define C4_SUPPRESS_WARNING_GCC_POP
#endif // C4_GCC
#define C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_MSVC_PUSH \
C4_SUPPRESS_WARNING_MSVC(w)
#define C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_CLANG_PUSH \
C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_GCC_PUSH \
C4_SUPPRESS_WARNING_GCC(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_PUSH \
C4_SUPPRESS_WARNING_GCC_PUSH \
C4_SUPPRESS_WARNING_CLANG_PUSH
#define C4_SUPPRESS_WARNING_GCC_CLANG(w) \
C4_SUPPRESS_WARNING_GCC(w) \
C4_SUPPRESS_WARNING_CLANG(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w)
#define C4_SUPPRESS_WARNING_GCC_CLANG_POP \
C4_SUPPRESS_WARNING_GCC_POP \
C4_SUPPRESS_WARNING_CLANG_POP
} // namespace c4
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif /* _C4_ERROR_HPP_ */
-18
View File
@@ -1,18 +0,0 @@
#ifndef C4_EXPORT_HPP_
#define C4_EXPORT_HPP_
#ifdef _WIN32
#ifdef C4CORE_SHARED
#ifdef C4CORE_EXPORTS
#define C4CORE_EXPORT __declspec(dllexport)
#else
#define C4CORE_EXPORT __declspec(dllimport)
#endif
#else
#define C4CORE_EXPORT
#endif
#else
#define C4CORE_EXPORT
#endif
#endif /* C4CORE_EXPORT_HPP_ */
File diff suppressed because it is too large Load Diff
-358
View File
@@ -1,358 +0,0 @@
#ifndef _C4_LANGUAGE_HPP_
#define _C4_LANGUAGE_HPP_
/** @file language.hpp Provides language standard information macros and
* compiler agnostic utility macros: namespace facilities, function attributes,
* variable attributes, etc.
* @ingroup basic_headers */
#include "c4/preprocessor.hpp"
#include "c4/compiler.hpp"
/* Detect C++ standard.
* @see http://stackoverflow.com/a/7132549/5875572 */
#ifndef C4_CPP
# if defined(_MSC_VER) && !defined(__clang__)
# if _MSC_VER >= 1910 // >VS2015: VS2017, VS2019, VS2022
# if (!defined(_MSVC_LANG))
# error _MSVC not defined
# endif
# if _MSVC_LANG >= 201705L
# define C4_CPP 20
# define C4_CPP20
# elif _MSVC_LANG == 201703L
# define C4_CPP 17
# define C4_CPP17
# elif _MSVC_LANG >= 201402L
# define C4_CPP 14
# define C4_CPP14
# elif _MSVC_LANG >= 201103L
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# else
# if _MSC_VER == 1900
# define C4_CPP 14 // VS2015 is c++14 https://devblogs.microsoft.com/cppblog/c111417-features-in-vs-2015-rtm/
# define C4_CPP14
# elif _MSC_VER == 1800 // VS2013
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# endif
# elif defined(__INTEL_COMPILER) // https://software.intel.com/en-us/node/524490
# ifdef __INTEL_CXX20_MODE__ // not sure about this
# define C4_CPP 20
# define C4_CPP20
# elif defined __INTEL_CXX17_MODE__ // not sure about this
# define C4_CPP 17
# define C4_CPP17
# elif defined __INTEL_CXX14_MODE__ // not sure about this
# define C4_CPP 14
# define C4_CPP14
# elif defined __INTEL_CXX11_MODE__
# define C4_CPP 11
# define C4_CPP11
# else
# error C++ lesser than C++11 not supported
# endif
# else
# ifndef __cplusplus
# error __cplusplus is not defined?
# endif
# if __cplusplus == 1
# error cannot handle __cplusplus==1
# elif __cplusplus >= 201709L
# define C4_CPP 20
# define C4_CPP20
# elif __cplusplus >= 201703L
# define C4_CPP 17
# define C4_CPP17
# elif __cplusplus >= 201402L
# define C4_CPP 14
# define C4_CPP14
# elif __cplusplus >= 201103L
# define C4_CPP 11
# define C4_CPP11
# elif __cplusplus >= 199711L
# error C++ lesser than C++11 not supported
# endif
# endif
#else
# ifdef C4_CPP == 20
# define C4_CPP20
# elif C4_CPP == 17
# define C4_CPP17
# elif C4_CPP == 14
# define C4_CPP14
# elif C4_CPP == 11
# define C4_CPP11
# elif C4_CPP == 98
# define C4_CPP98
# error C++ lesser than C++11 not supported
# else
# error C4_CPP must be one of 20, 17, 14, 11, 98
# endif
#endif
#ifdef C4_CPP20
# define C4_CPP17
# define C4_CPP14
# define C4_CPP11
#elif defined(C4_CPP17)
# define C4_CPP14
# define C4_CPP11
#elif defined(C4_CPP14)
# define C4_CPP11
#endif
/** lifted from this answer: http://stackoverflow.com/a/20170989/5875572 */
#if defined(_MSC_VER) && !defined(__clang__)
# if _MSC_VER < 1900
# define C4_CONSTEXPR11
# define C4_CONSTEXPR14
# elif _MSC_VER < 2000
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14
# else
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14 constexpr
# endif
#else
# if __cplusplus < 201103
# define C4_CONSTEXPR11
# define C4_CONSTEXPR14
# elif __cplusplus == 201103
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14
# else
# define C4_CONSTEXPR11 constexpr
# define C4_CONSTEXPR14 constexpr
# endif
#endif // _MSC_VER
#if C4_CPP < 17
#define C4_IF_CONSTEXPR
#define C4_INLINE_CONSTEXPR constexpr
#else
#define C4_IF_CONSTEXPR constexpr
#define C4_INLINE_CONSTEXPR inline constexpr
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# if (defined(_CPPUNWIND) && (_CPPUNWIND == 1))
# define C4_EXCEPTIONS
# endif
#else
# if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
# define C4_EXCEPTIONS
# endif
#endif
#ifdef C4_EXCEPTIONS
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) exc_code
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { exc_code } while(0)
#else
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) setjmp_code
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { setjmp_code } while(0)
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# if defined(_CPPRTTI)
# define C4_RTTI
# endif
#else
# if defined(__GXX_RTTI)
# define C4_RTTI
# endif
#endif
#ifdef C4_RTTI
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_rtti
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_rtti } while(0)
#else
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_no_rtti
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_no_rtti } while(0)
#endif
//------------------------------------------------------------
#define _C4_BEGIN_NAMESPACE(ns) namespace ns {
#define _C4_END_NAMESPACE(ns) }
// MSVC cant handle the C4_FOR_EACH macro... need to fix this
//#define C4_BEGIN_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_BEGIN_NAMESPACE, , __VA_ARGS__)
//#define C4_END_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_END_NAMESPACE, , __VA_ARGS__)
#define C4_BEGIN_NAMESPACE(ns) namespace ns {
#define C4_END_NAMESPACE(ns) }
#define C4_BEGIN_HIDDEN_NAMESPACE namespace /*hidden*/ {
#define C4_END_HIDDEN_NAMESPACE } /* namespace hidden */
//------------------------------------------------------------
#ifndef C4_API
# if defined(_MSC_VER) && !defined(__clang__)
# if defined(C4_EXPORT)
# define C4_API __declspec(dllexport)
# elif defined(C4_IMPORT)
# define C4_API __declspec(dllimport)
# else
# define C4_API
# endif
# else
# define C4_API
# endif
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_RESTRICT __restrict
# define C4_RESTRICT_FN __declspec(restrict)
# define C4_NO_INLINE __declspec(noinline)
# define C4_ALWAYS_INLINE inline __forceinline
/** these are not available in VS AFAIK */
# define C4_CONST
# define C4_PURE
# define C4_FLATTEN
# define C4_HOT /** @todo */
# define C4_COLD /** @todo */
# define C4_ASSUME(...) __assume(__VA_ARGS__)
# define C4_EXPECT(x, y) x /** @todo */
# define C4_LIKELY(x) x
# define C4_UNLIKELY(x) x
# define C4_UNREACHABLE() _c4_msvc_unreachable()
# define C4_ATTR_FORMAT(...) /** */
# define C4_NORETURN [[noreturn]]
# if _MSC_VER >= 1700 // VS2012
# define C4_NODISCARD _Check_return_
# else
# define C4_NODISCARD
# endif
[[noreturn]] __forceinline void _c4_msvc_unreachable() { __assume(false); } ///< https://stackoverflow.com/questions/60802864/emulating-gccs-builtin-unreachable-in-visual-studio
# define C4_UNREACHABLE_AFTER_ERR() /* */
#else
///< @todo assuming gcc-like compiler. check it is actually so.
/** for function attributes in GCC,
* @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes */
/** for __builtin functions in GCC,
* @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */
# define C4_RESTRICT __restrict__
# define C4_RESTRICT_FN __attribute__((restrict))
# define C4_NO_INLINE __attribute__((noinline))
# define C4_ALWAYS_INLINE inline __attribute__((always_inline))
# define C4_CONST __attribute__((const))
# define C4_PURE __attribute__((pure))
/** force inlining of every callee function */
# define C4_FLATTEN __atribute__((flatten))
/** mark a function as hot, ie as having a visible impact in CPU time
* thus making it more likely to inline, etc
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
# define C4_HOT __attribute__((hot))
/** mark a function as cold, ie as NOT having a visible impact in CPU time
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
# define C4_COLD __attribute__((cold))
# define C4_EXPECT(x, y) __builtin_expect(x, y) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
# define C4_LIKELY(x) __builtin_expect(x, 1)
# define C4_UNLIKELY(x) __builtin_expect(x, 0)
# define C4_UNREACHABLE() __builtin_unreachable()
# define C4_ATTR_FORMAT(...) //__attribute__((format (__VA_ARGS__))) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
# define C4_NORETURN __attribute__((noreturn))
# define C4_NODISCARD __attribute__((warn_unused_result))
# define C4_UNREACHABLE_AFTER_ERR() C4_UNREACHABLE()
// C4_ASSUME
// see https://stackoverflow.com/questions/63493968/reproducing-clangs-builtin-assume-for-gcc
// preferred option: C++ standard attribute
# ifdef __has_cpp_attribute
# if __has_cpp_attribute(assume) >= 202207L
# define C4_ASSUME(...) [[assume(__VA_ARGS__)]]
# endif
# endif
// first fallback: compiler intrinsics/attributes for assumptions
# ifndef C4_ASSUME
# if defined(__clang__)
# define C4_ASSUME(...) __builtin_assume(__VA_ARGS__)
# elif defined(__GNUC__)
# if __GNUC__ >= 13
# define C4_ASSUME(...) __attribute__((__assume__(__VA_ARGS__)))
# endif
# endif
# endif
// second fallback: possibly evaluating uses of unreachable()
// Set this to 1 if you want to allow assumptions to possibly evaluate.
# ifndef C4_ASSUME_ALLOW_EVAL
# define C4_ASSUME_ALLOW_EVAL 0
# endif
# if !defined(C4_ASSUME) && (C4_ASSUME_ALLOW_EVAL)
# define C4_ASSUME(...) do { if (!bool(__VA_ARGS__)) C4_UNREACHABLE(); ) while(0)
# endif
// last fallback: define macro as doing nothing
# ifndef C4_ASSUME
# define C4_ASSUME(...)
# endif
#endif
#if C4_CPP >= 14
# define C4_DEPRECATED(msg) [[deprecated(msg)]]
#else
# if defined(_MSC_VER)
# define C4_DEPRECATED(msg) __declspec(deprecated(msg))
# else // defined(__GNUC__) || defined(__clang__)
# define C4_DEPRECATED(msg) __attribute__((deprecated(msg)))
# endif
#endif
#ifdef _MSC_VER
# define C4_FUNC __FUNCTION__
# define C4_PRETTY_FUNC __FUNCSIG__
#else /// @todo assuming gcc-like compiler. check it is actually so.
# define C4_FUNC __FUNCTION__
# define C4_PRETTY_FUNC __PRETTY_FUNCTION__
#endif
/** prevent compiler warnings about a specific var being unused */
#define C4_UNUSED(var) (void)var
#if C4_CPP >= 17
#define C4_STATIC_ASSERT(cond) static_assert(cond)
#else
#define C4_STATIC_ASSERT(cond) static_assert((cond), #cond)
#endif
#define C4_STATIC_ASSERT_MSG(cond, msg) static_assert((cond), #cond ": " msg)
/** @def C4_DONT_OPTIMIZE idea lifted from GoogleBenchmark.
* @see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark_api.h */
namespace c4 {
namespace detail {
#ifdef __GNUC__
# define C4_DONT_OPTIMIZE(var) c4::detail::dont_optimize(var)
template< class T >
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); } // NOLINT
#else
# define C4_DONT_OPTIMIZE(var) c4::detail::use_char_pointer(reinterpret_cast< const char* >(&var))
void use_char_pointer(char const volatile*);
#endif
} // namespace detail
} // namespace c4
/** @def C4_KEEP_EMPTY_LOOP prevent an empty loop from being optimized out.
* @see http://stackoverflow.com/a/7084193/5875572 */
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_KEEP_EMPTY_LOOP { char c; C4_DONT_OPTIMIZE(c); }
#else
# define C4_KEEP_EMPTY_LOOP { asm(""); }
#endif
/** @def C4_VA_LIST_REUSE_MUST_COPY
* @todo <jpmag> I strongly suspect that this is actually only in UNIX platforms. revisit this. */
#ifdef __GNUC__
# define C4_VA_LIST_REUSE_MUST_COPY
#endif
#endif /* _C4_LANGUAGE_HPP_ */
-782
View File
@@ -1,782 +0,0 @@
#ifndef _C4_MEMORY_UTIL_HPP_
#define _C4_MEMORY_UTIL_HPP_
#include "c4/config.hpp"
#include "c4/error.hpp"
#include "c4/compiler.hpp"
#include "c4/cpu.hpp"
#ifdef C4_MSVC
#include <intrin.h>
#endif
#include <string.h>
#if (defined(__GNUC__) && __GNUC__ >= 10) || defined(__has_builtin)
#define _C4_USE_LSB_INTRINSIC(which) __has_builtin(which)
#define _C4_USE_MSB_INTRINSIC(which) __has_builtin(which)
#elif defined(C4_MSVC)
#define _C4_USE_LSB_INTRINSIC(which) true
#define _C4_USE_MSB_INTRINSIC(which) true
#else
// let's try our luck
#define _C4_USE_LSB_INTRINSIC(which) true
#define _C4_USE_MSB_INTRINSIC(which) true
#endif
/** @file memory_util.hpp Some memory utilities. */
// NOLINTBEGIN(google-runtime-int)
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
/** set the given memory to zero */
C4_ALWAYS_INLINE void mem_zero(void* mem, size_t num_bytes)
{
memset(mem, 0, num_bytes);
}
/** set the given memory to zero */
template<class T>
C4_ALWAYS_INLINE void mem_zero(T* mem, size_t num_elms)
{
memset(mem, 0, sizeof(T) * num_elms);
}
/** set the given memory to zero */
template<class T>
C4_ALWAYS_INLINE void mem_zero(T* mem)
{
memset(mem, 0, sizeof(T));
}
C4_ALWAYS_INLINE C4_CONST bool mem_overlaps(void const* a, void const* b, size_t sza, size_t szb)
{
// thanks @timwynants
return (((const char*)b + szb) > a && b < ((const char*)a+sza));
}
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template<class T>
C4_ALWAYS_INLINE C4_CONST bool is_aligned(T *ptr, uintptr_t alignment=alignof(T))
{
return (uintptr_t(ptr) & (alignment - uintptr_t(1))) == uintptr_t(0);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// least significant bit
/** @name msb Compute the least significant bit
* @note the input value must be nonzero
* @note the input type must be unsigned
*/
/** @{ */
// https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
#define _c4_lsb_fallback \
unsigned c = 0; \
v = (v ^ (v - 1)) >> 1; /* Set v's trailing 0s to 1s and zero rest */ \
for(; v; ++c) \
v >>= 1; \
return (unsigned) c
// u8
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
// upcast to use the intrinsic, it's cheaper.
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, (unsigned long)v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u16
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, (unsigned long)v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u32
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctz((unsigned)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u64 in 64bits
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzl)
#if defined(C4_MSVC)
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward64(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctzl((unsigned long)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
// u64 in 32bits
template<class I>
C4_CONSTEXPR14
auto lsb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzll)
#if defined(C4_MSVC)
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanForward64(&bit, v);
return bit;
#else
_c4_lsb_fallback;
#endif
#else
return (unsigned)__builtin_ctzll((unsigned long long)v);
#endif
#else
_c4_lsb_fallback;
#endif
}
#undef _c4_lsb_fallback
/** @} */
namespace detail {
template<class I, I val, unsigned num_bits, bool finished> struct _lsb11;
template<class I, I val, unsigned num_bits>
struct _lsb11<I, val, num_bits, false>
{
enum : unsigned { num = _lsb11<I, (val>>1), num_bits+I(1), (((val>>1)&I(1))!=I(0))>::num };
};
template<class I, I val, unsigned num_bits>
struct _lsb11<I, val, num_bits, true>
{
enum : unsigned { num = num_bits };
};
} // namespace detail
/** TMP version of lsb(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see lsb */
template<class I, I number>
struct lsb11
{
static_assert(number != 0, "lsb: number must be nonzero");
enum : unsigned { value = detail::_lsb11<I, number, 0, ((number&I(1))!=I(0))>::num};
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// most significant bit
/** @name msb Compute the most significant bit
* @note the input value must be nonzero
* @note the input type must be unsigned
*/
/** @{ */
#define _c4_msb8_fallback \
unsigned n = 0; \
if(v & I(0xf0)) v >>= 4, n |= I(4); \
if(v & I(0x0c)) v >>= 2, n |= I(2); \
if(v & I(0x02)) v >>= 1, n |= I(1); \
return n
#define _c4_msb16_fallback \
unsigned n = 0; \
if(v & I(0xff00)) v >>= 8, n |= I(8); \
if(v & I(0x00f0)) v >>= 4, n |= I(4); \
if(v & I(0x000c)) v >>= 2, n |= I(2); \
if(v & I(0x0002)) v >>= 1, n |= I(1); \
return n
#define _c4_msb32_fallback \
unsigned n = 0; \
if(v & I(0xffff0000)) v >>= 16, n |= 16; \
if(v & I(0x0000ff00)) v >>= 8, n |= 8; \
if(v & I(0x000000f0)) v >>= 4, n |= 4; \
if(v & I(0x0000000c)) v >>= 2, n |= 2; \
if(v & I(0x00000002)) v >>= 1, n |= 1; \
return n
#define _c4_msb64_fallback \
unsigned n = 0; \
if(v & I(0xffffffff00000000)) v >>= 32, n |= I(32); \
if(v & I(0x00000000ffff0000)) v >>= 16, n |= I(16); \
if(v & I(0x000000000000ff00)) v >>= 8, n |= I(8); \
if(v & I(0x00000000000000f0)) v >>= 4, n |= I(4); \
if(v & I(0x000000000000000c)) v >>= 2, n |= I(2); \
if(v & I(0x0000000000000002)) v >>= 1, n |= I(1); \
return n
// u8
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, (unsigned long)v);
return bit;
#else
_c4_msb8_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb8_fallback;
#endif
}
// u16
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
// upcast to use the intrinsic, it's cheaper.
// Then remember that the upcast makes it to 31bits
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, (unsigned long)v);
return bit;
#else
_c4_msb16_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb16_fallback;
#endif
}
// u32
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse(&bit, v);
return bit;
#else
_c4_msb32_fallback;
#endif
#else
return 31u - (unsigned)__builtin_clz((unsigned)v);
#endif
#else
_c4_msb32_fallback;
#endif
}
// u64 in 64bits
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clzl)
#ifdef C4_MSVC
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse64(&bit, v);
return bit;
#else
_c4_msb64_fallback;
#endif
#else
return 63u - (unsigned)__builtin_clzl((unsigned long)v);
#endif
#else
_c4_msb64_fallback;
#endif
}
// u64 in 32bits
template<class I>
C4_CONSTEXPR14
auto msb(I v) noexcept
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
{
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
C4_ASSERT(v != 0);
#if _C4_USE_MSB_INTRINSIC(__builtin_clzll)
#ifdef C4_MSVC
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
unsigned long bit;
_BitScanReverse64(&bit, v);
return bit;
#else
_c4_msb64_fallback;
#endif
#else
return 63u - (unsigned)__builtin_clzll((unsigned long long)v);
#endif
#else
_c4_msb64_fallback;
#endif
}
#undef _c4_msb8_fallback
#undef _c4_msb16_fallback
#undef _c4_msb32_fallback
#undef _c4_msb64_fallback
/** @} */
namespace detail {
template<class I, I val, I num_bits, bool finished> struct _msb11;
template<class I, I val, I num_bits>
struct _msb11< I, val, num_bits, false>
{
enum : unsigned { num = _msb11<I, (val>>1), num_bits+I(1), ((val>>1)==I(0))>::num };
};
template<class I, I val, I num_bits>
struct _msb11<I, val, num_bits, true>
{
static_assert(val == 0, "bad implementation");
enum : unsigned { num = (unsigned)(num_bits-1) };
};
} // namespace detail
/** TMP version of msb(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see msb */
template<class I, I number>
struct msb11
{
enum : unsigned { value = detail::_msb11<I, number, 0, (number==I(0))>::num };
};
#undef _C4_USE_LSB_INTRINSIC
#undef _C4_USE_MSB_INTRINSIC
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// there is an implicit conversion below; it happens when E or B are
// narrower than int, and thus any operation will upcast the result to
// int, and then downcast to assign
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wconversion")
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= base;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= base;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, B base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= base;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= base;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class Base, Base base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
B bbase = B(base);
if(exponent >= 0)
{
for(E e = 0; e < exponent; ++e)
r *= bbase;
}
else
{
exponent *= E(-1);
for(E e = 0; e < exponent; ++e)
r /= bbase;
}
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
for(E e = 0; e < exponent; ++e)
r *= base;
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, B base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
for(E e = 0; e < exponent; ++e)
r *= base;
return r;
}
/** integer power; this function is constexpr-14 because of the local
* variables */
template<class B, class Base, Base base, class E>
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
{
C4_STATIC_ASSERT(std::is_integral<E>::value);
B r = B(1);
B bbase = B(base);
for(E e = 0; e < exponent; ++e)
r *= bbase;
return r;
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** return a mask with all bits set [first_bit,last_bit[; this function
* is constexpr-14 because of the local variables */
template<class I>
C4_CONSTEXPR14 I contiguous_mask(I first_bit, I last_bit)
{
I r = 0;
for(I i = first_bit; i < last_bit; ++i)
{
r |= (I(1) << i);
}
return r;
}
namespace detail {
template<class I, I val, I first, I last, bool finished>
struct _ctgmsk11;
template<class I, I val, I first, I last>
struct _ctgmsk11< I, val, first, last, true>
{
enum : I { value = _ctgmsk11<I, val|(I(1)<<first), first+I(1), last, (first+1!=last)>::value };
};
template<class I, I val, I first, I last>
struct _ctgmsk11< I, val, first, last, false>
{
enum : I { value = val };
};
} // namespace detail
/** TMP version of contiguous_mask(); this needs to be implemented with template
* meta-programming because C++11 cannot use a constexpr function with
* local variables
* @see contiguous_mask */
template<class I, I first_bit, I last_bit>
struct contiguous_mask11
{
enum : I { value = detail::_ctgmsk11<I, I(0), first_bit, last_bit, (first_bit!=last_bit)>::value };
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** use Empty Base Class Optimization to reduce the size of a pair of
* potentially empty types*/
namespace detail {
typedef enum {
tpc_same,
tpc_same_empty,
tpc_both_empty,
tpc_first_empty,
tpc_second_empty,
tpc_general
} TightPairCase_e;
template<class First, class Second>
constexpr TightPairCase_e tpc_which_case()
{
return std::is_same<First, Second>::value ?
std::is_empty<First>::value ?
tpc_same_empty
:
tpc_same
:
std::is_empty<First>::value && std::is_empty<Second>::value ?
tpc_both_empty
:
std::is_empty<First>::value ?
tpc_first_empty
:
std::is_empty<Second>::value ?
tpc_second_empty
:
tpc_general
;
}
template<class First, class Second, TightPairCase_e Case>
struct tight_pair
{
private:
First m_first;
Second m_second;
public:
using first_type = First;
using second_type = Second;
tight_pair() : m_first(), m_second() {}
tight_pair(First const& f, Second const& s) : m_first(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_same_empty> : public First
{
static_assert(std::is_same<First, Second>::value, "bad implementation");
using first_type = First;
using second_type = Second;
tight_pair() : First() {}
tight_pair(First const& f, Second const& /*s*/) : First(f) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); } // NOLINT
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); } // NOLINT
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_both_empty> : public First, public Second
{
using first_type = First;
using second_type = Second;
tight_pair() : First(), Second() {}
tight_pair(First const& f, Second const& s) : First(f), Second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_same> : public First
{
Second m_second;
using first_type = First;
using second_type = Second;
tight_pair() : First() {}
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_first_empty> : public First
{
Second m_second;
using first_type = First;
using second_type = Second;
tight_pair() : First(), m_second() {}
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
};
template<class First, class Second>
struct tight_pair<First, Second, tpc_second_empty> : public Second
{
First m_first;
using first_type = First;
using second_type = Second;
tight_pair() : Second(), m_first() {}
tight_pair(First const& f, Second const& s) : Second(s), m_first(f) {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
};
} // namespace detail
template<class First, class Second>
using tight_pair = detail::tight_pair<First, Second, detail::tpc_which_case<First,Second>()>;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
// NOLINTEND(google-runtime-int)
#endif /* _C4_MEMORY_UTIL_HPP_ */
-46
View File
@@ -1,46 +0,0 @@
#ifndef _C4_PLATFORM_HPP_
#define _C4_PLATFORM_HPP_
/** @file platform.hpp Provides platform information macros
* @ingroup basic_headers */
// see also https://sourceforge.net/p/predef/wiki/OperatingSystems/
#if defined(_WIN64)
# define C4_WIN
# define C4_WIN64
#elif defined(_WIN32)
# define C4_WIN
# define C4_WIN32
#elif defined(__ANDROID__)
# define C4_ANDROID
#elif defined(__APPLE__)
# include "TargetConditionals.h"
# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
# define C4_IOS
# elif TARGET_OS_MAC || TARGET_OS_OSX
# define C4_MACOS
# else
# error "Unknown Apple platform"
# endif
#elif defined(__linux__) || defined(__linux)
# define C4_UNIX
# define C4_LINUX
#elif defined(__unix__) || defined(__unix)
# define C4_UNIX
#elif defined(__arm__) || defined(__aarch64__)
# define C4_ARM
#elif defined(__xtensa__) || defined(__XTENSA__)
# define C4_XTENSA
#elif defined(SWIG)
# define C4_SWIG
#else
# error "unknown platform"
#endif
#if defined(__posix) || defined(C4_UNIX) || defined(C4_LINUX)
# define C4_POSIX
#endif
#endif /* _C4_PLATFORM_HPP_ */
-123
View File
@@ -1,123 +0,0 @@
#ifndef _C4_PREPROCESSOR_HPP_
#define _C4_PREPROCESSOR_HPP_
/** @file preprocessor.hpp Contains basic macros and preprocessor utilities.
* @ingroup basic_headers */
#ifdef __clang__
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
* clang requires switching off compiler warnings for pedantic mode.
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
/* GCC also issues a warning for zero-args calls to variadic macros.
* This warning is switched on with -pedantic and apparently there is no
* easy way to turn it off as with clang. But marking this as a system
* header works.
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
* @see http://stackoverflow.com/questions/35587137/ */
# pragma GCC system_header
#endif
#define C4_WIDEN(str) L"" str
#define C4_COUNTOF(arr) (sizeof(arr)/sizeof((arr)[0]))
#define C4_EXPAND(arg) arg
/** useful in some macro calls with template arguments */
#define C4_COMMA ,
/** useful in some macro calls with template arguments
* @see C4_COMMA */
#define C4_COMMA_X C4_COMMA
/** expand and quote */
#define C4_XQUOTE(arg) _C4_XQUOTE(arg)
#define _C4_XQUOTE(arg) C4_QUOTE(arg)
#define C4_QUOTE(arg) #arg
/** expand and concatenate */
#define C4_XCAT(arg1, arg2) _C4_XCAT(arg1, arg2)
#define _C4_XCAT(arg1, arg2) C4_CAT(arg1, arg2)
#define C4_CAT(arg1, arg2) arg1##arg2
#define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch))
/** A preprocessor foreach. Spectacular trick taken from:
* http://stackoverflow.com/a/1872506/5875572
* The first argument is for a macro receiving a single argument,
* which will be called with every subsequent argument. There is
* currently a limit of 32 arguments, and at least 1 must be provided.
*
Example:
@code{.cpp}
struct Example {
int a;
int b;
int c;
};
// define a one-arg macro to be called
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(Example, field)
#define PRN_STRUCT_OFFSETS_(structure, field) printf(C4_XQUOTE(structure) ":" C4_XQUOTE(field)" - offset=%zu\n", offsetof(structure, field));
// now call the macro for a, b and c
C4_FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
@endcode */
#define C4_FOR_EACH(what, ...) C4_FOR_EACH_SEP(what, ;, __VA_ARGS__)
/** same as C4_FOR_EACH(), but use a custom separator between statements.
* If a comma is needed as the separator, use the C4_COMMA macro.
* @see C4_FOR_EACH
* @see C4_COMMA
*/
#define C4_FOR_EACH_SEP(what, sep, ...) _C4_FOR_EACH_(_C4_FOR_EACH_NARG(__VA_ARGS__), what, sep, __VA_ARGS__)
/// @cond dev
#define _C4_FOR_EACH_01(what, sep, x) what(x) sep
#define _C4_FOR_EACH_02(what, sep, x, ...) what(x) sep _C4_FOR_EACH_01(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_03(what, sep, x, ...) what(x) sep _C4_FOR_EACH_02(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_04(what, sep, x, ...) what(x) sep _C4_FOR_EACH_03(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_05(what, sep, x, ...) what(x) sep _C4_FOR_EACH_04(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_06(what, sep, x, ...) what(x) sep _C4_FOR_EACH_05(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_07(what, sep, x, ...) what(x) sep _C4_FOR_EACH_06(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_08(what, sep, x, ...) what(x) sep _C4_FOR_EACH_07(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_09(what, sep, x, ...) what(x) sep _C4_FOR_EACH_08(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_10(what, sep, x, ...) what(x) sep _C4_FOR_EACH_09(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_11(what, sep, x, ...) what(x) sep _C4_FOR_EACH_10(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_12(what, sep, x, ...) what(x) sep _C4_FOR_EACH_11(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_13(what, sep, x, ...) what(x) sep _C4_FOR_EACH_12(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_14(what, sep, x, ...) what(x) sep _C4_FOR_EACH_13(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_15(what, sep, x, ...) what(x) sep _C4_FOR_EACH_14(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_16(what, sep, x, ...) what(x) sep _C4_FOR_EACH_15(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_17(what, sep, x, ...) what(x) sep _C4_FOR_EACH_16(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_18(what, sep, x, ...) what(x) sep _C4_FOR_EACH_17(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_19(what, sep, x, ...) what(x) sep _C4_FOR_EACH_18(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_20(what, sep, x, ...) what(x) sep _C4_FOR_EACH_19(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_21(what, sep, x, ...) what(x) sep _C4_FOR_EACH_20(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_22(what, sep, x, ...) what(x) sep _C4_FOR_EACH_21(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_23(what, sep, x, ...) what(x) sep _C4_FOR_EACH_22(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_24(what, sep, x, ...) what(x) sep _C4_FOR_EACH_23(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_25(what, sep, x, ...) what(x) sep _C4_FOR_EACH_24(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_26(what, sep, x, ...) what(x) sep _C4_FOR_EACH_25(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_27(what, sep, x, ...) what(x) sep _C4_FOR_EACH_26(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_28(what, sep, x, ...) what(x) sep _C4_FOR_EACH_27(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_29(what, sep, x, ...) what(x) sep _C4_FOR_EACH_28(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_30(what, sep, x, ...) what(x) sep _C4_FOR_EACH_29(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_31(what, sep, x, ...) what(x) sep _C4_FOR_EACH_30(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_32(what, sep, x, ...) what(x) sep _C4_FOR_EACH_31(what, sep, __VA_ARGS__)
#define _C4_FOR_EACH_NARG(...) _C4_FOR_EACH_NARG_(__VA_ARGS__, _C4_FOR_EACH_RSEQ_N())
#define _C4_FOR_EACH_NARG_(...) _C4_FOR_EACH_ARG_N(__VA_ARGS__)
#define _C4_FOR_EACH_ARG_N(_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...) N
#define _C4_FOR_EACH_RSEQ_N() 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01
#define _C4_FOR_EACH_(N, what, sep, ...) C4_XCAT(_C4_FOR_EACH_, N)(what, sep, __VA_ARGS__)
/// @endcond
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif /* _C4_PREPROCESSOR_HPP_ */
-11
View File
@@ -1,11 +0,0 @@
#ifndef _C4_STD_STD_HPP_
#define _C4_STD_STD_HPP_
/** @file std.hpp includes all c4-std interop files */
#include "c4/std/vector.hpp"
#include "c4/std/string.hpp"
#include "c4/std/string_view.hpp"
#include "c4/std/tuple.hpp"
#endif // _C4_STD_STD_HPP_
-10
View File
@@ -1,10 +0,0 @@
#ifndef _C4_STD_STD_FWD_HPP_
#define _C4_STD_STD_FWD_HPP_
/** @file std_fwd.hpp includes all c4-std interop fwd files */
#include "c4/std/vector_fwd.hpp"
#include "c4/std/string_fwd.hpp"
//#include "c4/std/tuple_fwd.hpp"
#endif // _C4_STD_STD_FWD_HPP_
-97
View File
@@ -1,97 +0,0 @@
#ifndef _C4_STD_STRING_HPP_
#define _C4_STD_STRING_HPP_
/** @file string.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <string>
namespace c4 {
//-----------------------------------------------------------------------------
/** get a writeable view to an existing std::string.
* When the string is empty, the returned view will be pointing
* at the character with value '\0', but the size will be zero.
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
*/
C4_ALWAYS_INLINE c4::substr to_substr(std::string &s) noexcept
{
#if C4_CPP < 11
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::substr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
/** get a readonly view to an existing std::string.
* When the string is empty, the returned view will be pointing
* at the character with value '\0', but the size will be zero.
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
*/
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string const& s) noexcept
{
#if C4_CPP < 11
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::csubstr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
//-----------------------------------------------------------------------------
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) == 0; }
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) != 0; }
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) >= 0; }
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) > 0; }
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) <= 0; }
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) < 0; }
C4_ALWAYS_INLINE bool operator== (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) == 0; }
C4_ALWAYS_INLINE bool operator!= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) != 0; }
C4_ALWAYS_INLINE bool operator>= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) <= 0; }
C4_ALWAYS_INLINE bool operator> (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) < 0; }
C4_ALWAYS_INLINE bool operator<= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) >= 0; }
C4_ALWAYS_INLINE bool operator< (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) > 0; }
//-----------------------------------------------------------------------------
/** copy an std::string to a writeable string view */
inline size_t to_chars(c4::substr buf, std::string const& s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t len = buf.len < s.size() ? buf.len : s.size();
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len)
{
C4_ASSERT(s.data() != nullptr);
C4_ASSERT(buf.str != nullptr);
memcpy(buf.str, s.data(), len);
}
return s.size(); // return the number of needed chars
}
/** copy a string view to an existing std::string */
inline bool from_chars(c4::csubstr buf, std::string * s)
{
s->resize(buf.len);
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(buf.len)
{
C4_ASSERT(buf.str != nullptr);
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}
} // namespace c4
#endif // _C4_STD_STRING_HPP_
-59
View File
@@ -1,59 +0,0 @@
#ifndef _C4_STD_STRING_FWD_HPP_
#define _C4_STD_STRING_FWD_HPP_
/** @file string_fwd.hpp */
#ifndef DOXYGEN
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr_fwd.hpp"
#endif
#include <cstddef>
// forward declarations for std::string
#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
#include <bits/stringfwd.h> // use the fwd header in glibcxx
#elif defined(_LIBCPP_VERSION) || defined(__APPLE_CC__)
#include <iosfwd> // use the fwd header in stdlibc++
#elif defined(_MSC_VER)
#include "c4/error.hpp"
//! @todo is there a fwd header in msvc?
namespace std {
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4643) // Forward declaring 'char_traits' in namespace std is not permitted by the C++ Standard.
template<typename> struct char_traits;
template<typename> class allocator;
template<typename _CharT, typename _Traits, typename _Alloc> class basic_string;
using string = basic_string<char, char_traits<char>, allocator<char>>;
C4_SUPPRESS_WARNING_MSVC_POP
} /* namespace std */
#else
#error "unknown standard library"
#endif
namespace c4 {
c4::substr to_substr(std::string &s) noexcept;
c4::csubstr to_csubstr(std::string const& s) noexcept;
bool operator== (c4::csubstr ss, std::string const& s);
bool operator!= (c4::csubstr ss, std::string const& s);
bool operator>= (c4::csubstr ss, std::string const& s);
bool operator> (c4::csubstr ss, std::string const& s);
bool operator<= (c4::csubstr ss, std::string const& s);
bool operator< (c4::csubstr ss, std::string const& s);
bool operator== (std::string const& s, c4::csubstr ss);
bool operator!= (std::string const& s, c4::csubstr ss);
bool operator>= (std::string const& s, c4::csubstr ss);
bool operator> (std::string const& s, c4::csubstr ss);
bool operator<= (std::string const& s, c4::csubstr ss);
bool operator< (std::string const& s, c4::csubstr ss);
size_t to_chars(c4::substr buf, std::string const& s);
bool from_chars(c4::csubstr buf, std::string * s);
} // namespace c4
#endif // DOXYGEN
#endif // _C4_STD_STRING_FWD_HPP_
-71
View File
@@ -1,71 +0,0 @@
#ifndef _C4_STD_STRING_VIEW_HPP_
#define _C4_STD_STRING_VIEW_HPP_
/** @file string_view.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/language.hpp"
#endif
#if (C4_CPP >= 17 && defined(__cpp_lib_string_view)) || defined(__DOXYGEN__)
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <string_view>
namespace c4 {
//-----------------------------------------------------------------------------
/** create a csubstr from an existing std::string_view. */
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string_view s) noexcept
{
return c4::csubstr(s.data(), s.size());
}
//-----------------------------------------------------------------------------
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) == 0; }
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) != 0; }
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) >= 0; }
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) > 0; }
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) <= 0; }
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) < 0; }
C4_ALWAYS_INLINE bool operator== (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) == 0; }
C4_ALWAYS_INLINE bool operator!= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) != 0; }
C4_ALWAYS_INLINE bool operator<= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) >= 0; }
C4_ALWAYS_INLINE bool operator< (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) > 0; }
C4_ALWAYS_INLINE bool operator>= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) <= 0; }
C4_ALWAYS_INLINE bool operator> (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) < 0; }
//-----------------------------------------------------------------------------
/** copy an std::string_view to a writeable substr */
inline size_t to_chars(c4::substr buf, std::string_view s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t sz = s.size();
size_t len = buf.len < sz ? buf.len : sz;
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len)
{
C4_ASSERT(s.data() != nullptr);
C4_ASSERT(buf.str != nullptr);
memcpy(buf.str, s.data(), len);
}
return sz; // return the number of needed chars
}
} // namespace c4
#endif // C4_STRING_VIEW_AVAILABLE
#endif // _C4_STD_STRING_VIEW_HPP_
-184
View File
@@ -1,184 +0,0 @@
#ifndef _C4_STD_TUPLE_HPP_
#define _C4_STD_TUPLE_HPP_
/** @file tuple.hpp */
#ifndef C4CORE_SINGLE_HEADER
#include "c4/format.hpp"
#endif
#include <tuple>
/** this is a work in progress */
#undef C4_TUPLE_TO_CHARS
namespace c4 {
#ifdef C4_TUPLE_TO_CHARS
namespace detail {
template< size_t Curr, class... Types >
struct tuple_helper
{
static size_t do_cat(substr buf, std::tuple< Types... > const& tp)
{
size_t num = to_chars(buf, std::get<Curr>(tp));
buf = buf.len >= num ? buf.sub(num) : substr{};
num += tuple_helper< Curr+1, Types... >::do_cat(buf, tp);
return num;
}
static size_t do_uncat(csubstr buf, std::tuple< Types... > & tp)
{
size_t num = from_str_trim(buf, &std::get<Curr>(tp));
if(num == csubstr::npos) return csubstr::npos;
buf = buf.len >= num ? buf.sub(num) : substr{};
num += tuple_helper< Curr+1, Types... >::do_uncat(buf, tp);
return num;
}
template< class Sep >
static size_t do_catsep_more(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
{
size_t ret = to_chars(buf, sep), num = ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = to_chars(buf, std::get<Curr>(tp));
num += ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = tuple_helper< Curr+1, Types... >::do_catsep_more(buf, sep, tp);
num += ret;
return num;
}
template< class Sep >
static size_t do_uncatsep_more(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
{
size_t ret = from_str_trim(buf, &sep), num = ret;
if(ret == csubstr::npos) return csubstr::npos;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = from_str_trim(buf, &std::get<Curr>(tp));
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = tuple_helper< Curr+1, Types... >::do_uncatsep_more(buf, sep, tp);
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
return num;
}
static size_t do_format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
{
auto pos = fmt.find("{}");
if(pos != csubstr::npos)
{
size_t num = to_chars(buf, fmt.sub(0, pos));
size_t out = num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = to_chars(buf, std::get<Curr>(tp));
out += num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = tuple_helper< Curr+1, Types... >::do_format(buf, fmt.sub(pos + 2), tp);
out += num;
return out;
}
else
{
return format(buf, fmt);
}
}
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
{
auto pos = fmt.find("{}");
if(pos != csubstr::npos)
{
size_t num = pos;
size_t out = num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = from_str_trim(buf, &std::get<Curr>(tp));
out += num;
buf = buf.len >= num ? buf.sub(num) : substr{};
num = tuple_helper< Curr+1, Types... >::do_unformat(buf, fmt.sub(pos + 2), tp);
out += num;
return out;
}
else
{
return tuple_helper< sizeof...(Types), Types... >::do_unformat(buf, fmt, tp);
}
}
};
/** @todo VS compilation fails for this class */
template< class... Types >
struct tuple_helper< sizeof...(Types), Types... >
{
static size_t do_cat(substr /*buf*/, std::tuple<Types...> const& /*tp*/) { return 0; }
static size_t do_uncat(csubstr /*buf*/, std::tuple<Types...> & /*tp*/) { return 0; }
template< class Sep > static size_t do_catsep_more(substr /*buf*/, Sep const& /*sep*/, std::tuple<Types...> const& /*tp*/) { return 0; }
template< class Sep > static size_t do_uncatsep_more(csubstr /*buf*/, Sep & /*sep*/, std::tuple<Types...> & /*tp*/) { return 0; }
static size_t do_format(substr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
{
return to_chars(buf, fmt);
}
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
{
return 0;
}
};
} // namespace detail
template< class... Types >
inline size_t cat(substr buf, std::tuple< Types... > const& tp)
{
return detail::tuple_helper< 0, Types... >::do_cat(buf, tp);
}
template< class... Types >
inline size_t uncat(csubstr buf, std::tuple< Types... > & tp)
{
return detail::tuple_helper< 0, Types... >::do_uncat(buf, tp);
}
template< class Sep, class... Types >
inline size_t catsep(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
{
size_t num = to_chars(buf, std::cref(std::get<0>(tp)));
buf = buf.len >= num ? buf.sub(num) : substr{};
num += detail::tuple_helper< 1, Types... >::do_catsep_more(buf, sep, tp);
return num;
}
template< class Sep, class... Types >
inline size_t uncatsep(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
{
size_t ret = from_str_trim(buf, &std::get<0>(tp)), num = ret;
if(ret == csubstr::npos) return csubstr::npos;
buf = buf.len >= ret ? buf.sub(ret) : substr{};
ret = detail::tuple_helper< 1, Types... >::do_uncatsep_more(buf, sep, tp);
if(ret == csubstr::npos) return csubstr::npos;
num += ret;
return num;
}
template< class... Types >
inline size_t format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
{
return detail::tuple_helper< 0, Types... >::do_format(buf, fmt, tp);
}
template< class... Types >
inline size_t unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
{
return detail::tuple_helper< 0, Types... >::do_unformat(buf, fmt, tp);
}
#endif // C4_TUPLE_TO_CHARS
} // namespace c4
#endif /* _C4_STD_TUPLE_HPP_ */
-88
View File
@@ -1,88 +0,0 @@
#ifndef _C4_STD_VECTOR_HPP_
#define _C4_STD_VECTOR_HPP_
/** @file vector.hpp provides conversion and comparison facilities
* from/between std::vector<char> to c4::substr and c4::csubstr.
* @todo add to_span() and friends
*/
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr.hpp"
#endif
#include <vector>
namespace c4 {
//-----------------------------------------------------------------------------
/** get a substr (writeable string view) of an existing std::vector<char> */
template<class Alloc>
c4::substr to_substr(std::vector<char, Alloc> &vec)
{
char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
return c4::substr(data, vec.size());
}
/** get a csubstr (read-only string) view of an existing std::vector<char> */
template<class Alloc>
c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec)
{
const char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
return c4::csubstr(data, vec.size());
}
//-----------------------------------------------------------------------------
// comparisons between substrings and std::vector<char>
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss != to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss == to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss >= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss > to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss <= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss < to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss != to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss == to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss <= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss < to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss >= to_csubstr(s); }
template<class Alloc> C4_ALWAYS_INLINE bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss > to_csubstr(s); }
//-----------------------------------------------------------------------------
/** copy a std::vector<char> to a writeable string view */
template<class Alloc>
inline size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s)
{
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
size_t len = buf.len < s.size() ? buf.len : s.size();
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(len > 0)
{
memcpy(buf.str, s.data(), len);
}
return s.size(); // return the number of needed chars
}
/** copy a string view to an existing std::vector<char> */
template<class Alloc>
inline bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s)
{
s->resize(buf.len);
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
// calling memcpy with null strings is undefined behavior
// and will wreak havoc in calling code's branches.
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(buf.len > 0)
{
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}
} // namespace c4
#endif // _C4_STD_VECTOR_HPP_
-70
View File
@@ -1,70 +0,0 @@
#ifndef _C4_STD_VECTOR_FWD_HPP_
#define _C4_STD_VECTOR_FWD_HPP_
/** @file vector_fwd.hpp */
#include <cstddef>
// NOLINTBEGIN(cert-dcl58-cpp)
// forward declarations for std::vector
#if defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_MSC_VER)
#if defined(_MSC_VER)
__pragma(warning(push))
__pragma(warning(disable : 4643))
#endif
namespace std {
template<typename> class allocator;
#ifdef _GLIBCXX_DEBUG
inline namespace __debug {
template<typename T, typename Alloc> class vector;
}
#else
template<typename T, typename Alloc> class vector;
#endif
} // namespace std
#if defined(_MSC_VER)
__pragma(warning(pop))
#endif
#elif defined(_LIBCPP_ABI_NAMESPACE)
namespace std {
inline namespace _LIBCPP_ABI_NAMESPACE {
template<typename> class allocator;
template<typename T, typename Alloc> class vector;
} // namespace _LIBCPP_ABI_NAMESPACE
} // namespace std
#else
#error "unknown standard library"
#endif
#ifndef C4CORE_SINGLE_HEADER
#include "c4/substr_fwd.hpp"
#endif
namespace c4 {
template<class Alloc> c4::substr to_substr(std::vector<char, Alloc> &vec);
template<class Alloc> c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec);
template<class Alloc> bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s);
template<class Alloc> bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss);
template<class Alloc> size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s);
template<class Alloc> bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s);
} // namespace c4
// NOLINTEND(cert-dcl58-cpp)
#endif // _C4_STD_VECTOR_FWD_HPP_
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
#ifndef _C4_SUBSTR_FWD_HPP_
#define _C4_SUBSTR_FWD_HPP_
#include "c4/export.hpp"
namespace c4 {
#ifndef DOXYGEN
template<class C> struct basic_substring;
using csubstr = C4CORE_EXPORT basic_substring<const char>;
using substr = C4CORE_EXPORT basic_substring<char>;
#endif // !DOXYGEN
} // namespace c4
#endif /* _C4_SUBSTR_FWD_HPP_ */
-68
View File
@@ -1,68 +0,0 @@
#ifndef _C4_SZCONV_HPP_
#define _C4_SZCONV_HPP_
/** @file szconv.hpp utilities to deal safely with narrowing conversions */
#include "c4/config.hpp"
#include "c4/error.hpp"
#include <limits>
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
/** @todo this would be so much easier with calls to numeric_limits::max()... */
template<class SizeOut, class SizeIn>
struct is_narrower_size : std::conditional
<
(std::is_signed<SizeOut>::value == std::is_signed<SizeIn>::value)
?
(sizeof(SizeOut) < sizeof(SizeIn))
:
(
(sizeof(SizeOut) < sizeof(SizeIn))
||
(
(sizeof(SizeOut) == sizeof(SizeIn))
&&
(std::is_signed<SizeOut>::value && std::is_unsigned<SizeIn>::value)
)
),
std::true_type,
std::false_type
>::type
{
static_assert(std::is_integral<SizeIn >::value, "must be integral type");
static_assert(std::is_integral<SizeOut>::value, "must be integral type");
};
/** when SizeOut is wider than SizeIn, assignment can occur without reservations */
template<class SizeOut, class SizeIn>
C4_ALWAYS_INLINE
typename std::enable_if< ! is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
szconv(SizeIn sz) noexcept
{
return static_cast<SizeOut>(sz);
}
/** when SizeOut is narrower than SizeIn, narrowing will occur, so we check
* for overflow. Note that this check is done only if C4_XASSERT is enabled.
* @see C4_XASSERT */
template<class SizeOut, class SizeIn>
C4_ALWAYS_INLINE
typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
szconv(SizeIn sz)
{
C4_XASSERT(sz >= 0);
C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz);
SizeOut szo = static_cast<SizeOut>(sz);
return szo;
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
#endif /* _C4_SZCONV_HPP_ */
-507
View File
@@ -1,507 +0,0 @@
#ifndef _C4_TYPES_HPP_
#define _C4_TYPES_HPP_
#include <stdint.h>
#include <stddef.h>
#include <type_traits>
#if __cplusplus >= 201103L
#include <utility> // for integer_sequence and friends
#endif
#include "c4/preprocessor.hpp"
#include "c4/language.hpp"
/** @file types.hpp basic types, and utility macros and traits for types.
* @ingroup basic_headers */
/** @defgroup types Type utilities */
// NOLINTBEGIN(bugprone-macro-parentheses)
namespace c4 {
/** @defgroup intrinsic_types Intrinsic types
* @ingroup types
* @{ */
using cbyte = const char; /**< a constant byte */
using byte = char; /**< a mutable byte */
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using f32 = float;
using f64 = double;
using ssize_t = typename std::make_signed<size_t>::type;
/** @} */
//--------------------------------------------------
/** @defgroup utility_types Utility types
* @ingroup types
* @{ */
// some tag types
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic push
#if __GNUC__ >= 6
#pragma GCC diagnostic ignored "-Wunused-const-variable"
#endif
#endif
/** a tag type for initializing the containers with variadic arguments a la
* initializer_list, minus the initializer_list overload problems.
*/
struct aggregate_t {};
/** @see aggregate_t */
constexpr const aggregate_t aggregate{};
/** a tag type for specifying the initial capacity of allocatable contiguous storage */
struct with_capacity_t {};
/** @see with_capacity_t */
constexpr const with_capacity_t with_capacity{};
/** a tag type for disambiguating template parameter packs in variadic template overloads */
struct varargs_t {};
/** @see with_capacity_t */
constexpr const varargs_t varargs{};
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
//--------------------------------------------------
/** whether a value should be used in place of a const-reference in argument passing. */
template<class T>
struct cref_uses_val
{
enum { value = (
std::is_scalar<T>::value
||
(
#if C4_CPP >= 20
(std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value)
#else
std::is_pod<T>::value
#endif
&&
sizeof(T) <= sizeof(size_t))) };
};
/** utility macro to override the default behaviour for c4::fastcref<T>
@see fastcref */
#define C4_CREF_USES_VAL(T) \
template<> \
struct cref_uses_val<T> \
{ \
enum { value = true }; \
};
/** Whether to use pass-by-value or pass-by-const-reference in a function argument
* or return type. */
template<class T>
using fastcref = typename std::conditional<c4::cref_uses_val<T>::value, T, T const&>::type;
//--------------------------------------------------
/** Just what its name says. Useful sometimes as a default empty policy class. */
struct EmptyStruct // NOLINT
{
template<class... T> EmptyStruct(T && ...){} // NOLINT
};
/** Just what its name says. Useful sometimes as a default policy class to
* be inherited from. */
struct EmptyStructVirtual // NOLINT
{
virtual ~EmptyStructVirtual() = default;
template<class... T> EmptyStructVirtual(T && ...){} // NOLINT
};
/** */
template<class T>
struct inheritfrom : public T {};
//--------------------------------------------------
// Utilities to make a class obey size restrictions (eg, min size or size multiple of).
// DirectX usually makes this restriction with uniform buffers.
// This is also useful for padding to prevent false-sharing.
/** how many bytes must be added to size such that the result is at least minsize? */
C4_ALWAYS_INLINE constexpr size_t min_remainder(size_t size, size_t minsize) noexcept
{
return size < minsize ? minsize-size : 0;
}
/** how many bytes must be added to size such that the result is a multiple of multipleof? */
C4_ALWAYS_INLINE constexpr size_t mult_remainder(size_t size, size_t multipleof) noexcept
{
return (((size % multipleof) != 0) ? (multipleof-(size % multipleof)) : 0);
}
/* force the following class to be tightly packed. */
#pragma pack(push, 1)
/** pad a class with more bytes at the end.
* @see http://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly */
template<class T, size_t BytesToPadAtEnd>
struct Padded : public T
{
using T::T;
using T::operator=;
Padded(T const& val) : T(val) {}
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
char ___c4padspace___[BytesToPadAtEnd];
};
#pragma pack(pop)
/** When the padding argument is 0, we cannot declare the char[] array. */
template<class T>
struct Padded<T, 0> : public T
{
using T::T;
using T::operator=;
Padded(T const& val) : T(val) {}
Padded(T && val) : T(std::forward<T>(val)) {} // NOLINT
};
/** make T have a size which is at least Min bytes */
template<class T, size_t Min>
using MinSized = Padded<T, min_remainder(sizeof(T), Min)>;
/** make T have a size which is a multiple of Mult bytes */
template<class T, size_t Mult>
using MultSized = Padded<T, mult_remainder(sizeof(T), Mult)>;
/** make T have a size which is simultaneously:
* -bigger or equal than Min
* -a multiple of Mult */
template<class T, size_t Min, size_t Mult>
using MinMultSized = MultSized<MinSized<T, Min>, Mult>;
/** make T be suitable for use as a uniform buffer. (at least with DirectX). */
template<class T>
using UbufSized = MinMultSized<T, 64, 16>;
//-----------------------------------------------------------------------------
#define C4_NO_COPY_CTOR(ty) ty(ty const&) = delete
#define C4_NO_MOVE_CTOR(ty) ty(ty &&) = delete
#define C4_NO_COPY_ASSIGN(ty) ty& operator=(ty const&) = delete
#define C4_NO_MOVE_ASSIGN(ty) ty& operator=(ty &&) = delete
#define C4_DEFAULT_COPY_CTOR(ty) ty(ty const&) noexcept = default
#define C4_DEFAULT_MOVE_CTOR(ty) ty(ty &&) noexcept = default
#define C4_DEFAULT_COPY_ASSIGN(ty) ty& operator=(ty const&) noexcept = default
#define C4_DEFAULT_MOVE_ASSIGN(ty) ty& operator=(ty &&) noexcept = default
#define C4_NO_COPY_OR_MOVE_CTOR(ty) \
C4_NO_COPY_CTOR(ty); \
C4_NO_MOVE_CTOR(ty)
#define C4_NO_COPY_OR_MOVE_ASSIGN(ty) \
C4_NO_COPY_ASSIGN(ty); \
C4_NO_MOVE_ASSIGN(ty)
#define C4_NO_COPY_OR_MOVE(ty) \
C4_NO_COPY_OR_MOVE_CTOR(ty); \
C4_NO_COPY_OR_MOVE_ASSIGN(ty)
#define C4_DEFAULT_COPY_AND_MOVE_CTOR(ty) \
C4_DEFAULT_COPY_CTOR(ty); \
C4_DEFAULT_MOVE_CTOR(ty)
#define C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty) \
C4_DEFAULT_COPY_ASSIGN(ty); \
C4_DEFAULT_MOVE_ASSIGN(ty)
#define C4_DEFAULT_COPY_AND_MOVE(ty) \
C4_DEFAULT_COPY_AND_MOVE_CTOR(ty); \
C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty)
/** @see https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable */
#define C4_MUST_BE_TRIVIAL_COPY(ty) \
static_assert(std::is_trivially_copyable<ty>::value, #ty " must be trivially copyable")
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup traits_types Type traits utilities
* @ingroup types
* @{ */
// http://stackoverflow.com/questions/10821380/is-t-an-instance-of-a-template-in-c
template<template<typename...> class X, typename T> struct is_instance_of_tpl : std::false_type {};
template<template<typename...> class X, typename... Y> struct is_instance_of_tpl<X, X<Y...>> : std::true_type {};
//-----------------------------------------------------------------------------
/** SFINAE. use this macro to enable a template function overload
based on a compile-time condition.
@code
// define an overload for a non-pod type
template<class T, C4_REQUIRE_T(std::is_pod<T>::value)>
void foo() { std::cout << "pod type\n"; }
// define an overload for a non-pod type
template<class T, C4_REQUIRE_T(!std::is_pod<T>::value)>
void foo() { std::cout << "nonpod type\n"; }
struct non_pod
{
non_pod() : name("asdfkjhasdkjh") {}
const char *name;
};
int main()
{
foo<float>(); // prints "pod type"
foo<non_pod>(); // prints "nonpod type"
}
@endcode */
#define C4_REQUIRE_T(cond) typename std::enable_if<cond, bool>::type* = nullptr
/** enable_if for a return type
* @see C4_REQUIRE_T */
#define C4_REQUIRE_R(cond, type_) typename std::enable_if<cond, type_>::type
//-----------------------------------------------------------------------------
/** define a traits class reporting whether a type provides a member typedef */
#define C4_DEFINE_HAS_TYPEDEF(member_typedef) \
template<typename T> \
struct has_##stype \
{ \
private: \
\
typedef char yes; \
typedef struct { char array[2]; } no; \
\
template<typename C> \
static yes _test(typename C::member_typedef*); \
\
template<typename C> \
static no _test(...); \
\
public: \
\
enum { value = (sizeof(_test<T>(0)) == sizeof(yes)) }; \
\
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup type_declarations Type declaration utilities
* @ingroup types
* @{ */
#define _c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I) \
\
using size_type = I; \
using ssize_type = typename std::make_signed<I>::type; \
using difference_type = typename std::make_signed<I>::type; \
\
using value_type = T; \
using pointer = T*; \
using const_pointer = T const*; \
using reference = T&; \
using const_reference = T const&
#define _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I) \
\
using size_type = I; \
using ssize_type = typename std::make_signed<I>::type; \
using difference_type = typename std::make_signed<I>::type; \
\
template<I n> using value_type = typename std::tuple_element< n, std::tuple<interior_types...>>::type; \
template<I n> using pointer = value_type<n>*; \
template<I n> using const_pointer = value_type<n> const*; \
template<I n> using reference = value_type<n>&; \
template<I n> using const_reference = value_type<n> const&
#define _c4_DEFINE_ARRAY_TYPES(T, I) \
\
_c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I); \
\
using iterator = T*; \
using const_iterator = T const*; \
using reverse_iterator = std::reverse_iterator<T*>; \
using const_reverse_iterator = std::reverse_iterator<T const*>
#define _c4_DEFINE_TUPLE_ARRAY_TYPES(interior_types, I) \
\
_c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I); \
\
template<I n> using iterator = value_type<n>*; \
template<I n> using const_iterator = value_type<n> const*; \
template<I n> using reverse_iterator = std::reverse_iterator< value_type<n>*>; \
template<I n> using const_reverse_iterator = std::reverse_iterator< value_type<n> const*>
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup compatility_utilities Backport implementation of some Modern C++ utilities
* @ingroup types
* @{ */
//-----------------------------------------------------------------------------
// index_sequence and friends are available only for C++14 and later.
// A C++11 implementation is provided here.
// This implementation was copied over from clang.
// see http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687
#if __cplusplus > 201103L
using std::integer_sequence;
using std::index_sequence;
using std::make_integer_sequence;
using std::make_index_sequence;
using std::index_sequence_for;
#else
/** C++11 implementation of integer sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class _Tp, _Tp... _Ip>
struct integer_sequence
{
static_assert(std::is_integral<_Tp>::value,
"std::integer_sequence can only be instantiated with an integral type" );
using value_type = _Tp;
static constexpr size_t size() noexcept { return sizeof...(_Ip); }
};
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<size_t... _Ip>
using index_sequence = integer_sequence<size_t, _Ip...>;
/** @cond DONT_DOCUMENT_THIS */
namespace __detail {
template<typename _Tp, size_t ..._Extra>
struct __repeat;
template<typename _Tp, _Tp ..._Np, size_t ..._Extra>
struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...>
{
using type = integer_sequence<_Tp,
_Np...,
sizeof...(_Np) + _Np...,
2 * sizeof...(_Np) + _Np...,
3 * sizeof...(_Np) + _Np...,
4 * sizeof...(_Np) + _Np...,
5 * sizeof...(_Np) + _Np...,
6 * sizeof...(_Np) + _Np...,
7 * sizeof...(_Np) + _Np...,
_Extra...>;
};
template<size_t _Np> struct __parity;
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
template<> struct __make<0> { using type = integer_sequence<size_t>; };
template<> struct __make<1> { using type = integer_sequence<size_t, 0>; };
template<> struct __make<2> { using type = integer_sequence<size_t, 0, 1>; };
template<> struct __make<3> { using type = integer_sequence<size_t, 0, 1, 2>; };
template<> struct __make<4> { using type = integer_sequence<size_t, 0, 1, 2, 3>; };
template<> struct __make<5> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4>; };
template<> struct __make<6> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5>; };
template<> struct __make<7> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6>; };
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<typename _Tp, typename _Up>
struct __convert
{
template<typename> struct __result;
template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...>>
{
using type = integer_sequence<_Up, _Np...>;
};
};
template<typename _Tp>
struct __convert<_Tp, _Tp>
{
template<typename _Up> struct __result
{
using type = _Up;
};
};
template<typename _Tp, _Tp _Np>
using __make_integer_sequence_unchecked = typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
template<class _Tp, _Tp _Ep>
struct __make_integer_sequence
{
static_assert(std::is_integral<_Tp>::value,
"std::make_integer_sequence can only be instantiated with an integral type" );
static_assert(0 <= _Ep, "std::make_integer_sequence input shall not be negative");
typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
};
} // namespace __detail
/** @endcond */
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class _Tp, _Tp _Np>
using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type;
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<size_t _Np>
using make_index_sequence = make_integer_sequence<size_t, _Np>;
/** C++11 implementation of index sequence
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
template<class... _Tp>
using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
#endif
/** @} */
} // namespace c4
// NOLINTEND(bugprone-macro-parentheses)
#endif /* _C4_TYPES_HPP_ */
-73
View File
@@ -1,73 +0,0 @@
#ifndef C4_UTF_HPP_
#define C4_UTF_HPP_
#include "c4/language.hpp"
#include "c4/substr_fwd.hpp"
#include <stddef.h>
#include <stdint.h>
/** @file utf.hpp utilities for UTF and Byte Order Mark */
namespace c4 {
/** @defgroup doc_utf UTF utilities
* @{ */
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark.
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT substr skip_bom(substr s);
/** skip the Byte Order Mark, or get the full string if there is Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT csubstr skip_bom(csubstr s);
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT substr get_bom(substr s);
/** get the Byte Order Mark, or an empty string if there is no Byte Order Mark
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT csubstr get_bom(csubstr s);
/** return the position of the first character not belonging to the
* Byte Order Mark, or 0 if there is no Byte Order Mark.
* @see Implements the Byte Order Marks as described in https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding */
C4CORE_EXPORT size_t first_non_bom(csubstr s);
/** decode the given @p code_point, writing into the output string in
* @p out.
*
* @param out the output string. must have at least 4 bytes (this is
* asserted), and must not have a null string.
*
* @param code_point: must have length in ]0,8], and must not begin
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
*
* @return the part of @p out that was written, which will always be
* at most 4 bytes.
*/
C4CORE_EXPORT substr decode_code_point(substr out, csubstr code_point);
/** decode the given @p code point, writing into the output string @p
* buf, of size @p buflen
*
* @param buf the output string. must have at least 4 bytes (this is
* asserted), and must not be null
*
* @param buflen the length of the output string. must be at least 4
*
* @param code: the code point must have length in ]0,8], and must not begin
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
*
* @return the number of written characters, which will always be
* at most 4 bytes.
*/
C4CORE_EXPORT size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, uint32_t code);
/** @} */
} // namespace c4
#endif // C4_UTF_HPP_
-10
View File
@@ -1,10 +0,0 @@
#ifndef _C4_WINDOWS_HPP_
#define _C4_WINDOWS_HPP_
#if defined(_WIN64) || defined(_WIN32)
#include "c4/windows_push.hpp"
#include <windows.h>
#include "c4/windows_pop.hpp"
#endif
#endif /* _C4_WINDOWS_HPP_ */
-41
View File
@@ -1,41 +0,0 @@
#ifndef _C4_WINDOWS_POP_HPP_
#define _C4_WINDOWS_POP_HPP_
#if defined(_WIN64) || defined(_WIN32)
#ifdef _c4_AMD64_
# undef _c4_AMD64_
# undef _AMD64_
#endif
#ifdef _c4_X86_
# undef _c4_X86_
# undef _X86_
#endif
#ifdef _c4_ARM_
# undef _c4_ARM_
# undef _ARM_
#endif
#ifdef _c4_NOMINMAX
# undef _c4_NOMINMAX
# undef NOMINMAX
#endif
#ifdef NOGDI
# undef _c4_NOGDI
# undef NOGDI
#endif
#ifdef VC_EXTRALEAN
# undef _c4_VC_EXTRALEAN
# undef VC_EXTRALEAN
#endif
#ifdef WIN32_LEAN_AND_MEAN
# undef _c4_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif /* defined(_WIN64) || defined(_WIN32) */
#endif /* _C4_WINDOWS_POP_HPP_ */
-102
View File
@@ -1,102 +0,0 @@
#ifndef _C4_WINDOWS_PUSH_HPP_
#define _C4_WINDOWS_PUSH_HPP_
/** @file windows_push.hpp sets up macros to include windows header files
* without pulling in all of <windows.h>
*
* @see #include windows_pop.hpp to undefine these macros
*
* @see https://aras-p.info/blog/2018/01/12/Minimizing-windows.h/ */
#if defined(_WIN64) || defined(_WIN32)
#if defined(_M_AMD64)
# ifndef _AMD64_
# define _c4_AMD64_
# define _AMD64_
# endif
#elif defined(_M_IX86)
# ifndef _X86_
# define _c4_X86_
# define _X86_
# endif
#elif defined(_M_ARM64)
# ifndef _ARM64_
# define _c4_ARM64_
# define _ARM64_
# endif
#elif defined(_M_ARM)
# ifndef _ARM_
# define _c4_ARM_
# define _ARM_
# endif
#endif
#ifndef NOMINMAX
# define _c4_NOMINMAX
# define NOMINMAX
#endif
#ifndef NOGDI
# define _c4_NOGDI
# define NOGDI
#endif
#ifndef VC_EXTRALEAN
# define _c4_VC_EXTRALEAN
# define VC_EXTRALEAN
#endif
#ifndef WIN32_LEAN_AND_MEAN
# define _c4_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
/* If defined, the following flags inhibit definition
* of the indicated items.
*
* NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
* NOVIRTUALKEYCODES - VK_*
* NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
* NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
* NOSYSMETRICS - SM_*
* NOMENUS - MF_*
* NOICONS - IDI_*
* NOKEYSTATES - MK_*
* NOSYSCOMMANDS - SC_*
* NORASTEROPS - Binary and Tertiary raster ops
* NOSHOWWINDOW - SW_*
* OEMRESOURCE - OEM Resource values
* NOATOM - Atom Manager routines
* NOCLIPBOARD - Clipboard routines
* NOCOLOR - Screen colors
* NOCTLMGR - Control and Dialog routines
* NODRAWTEXT - DrawText() and DT_*
* NOGDI - All GDI defines and routines
* NOKERNEL - All KERNEL defines and routines
* NOUSER - All USER defines and routines
* NONLS - All NLS defines and routines
* NOMB - MB_* and MessageBox()
* NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
* NOMETAFILE - typedef METAFILEPICT
* NOMINMAX - Macros min(a,b) and max(a,b)
* NOMSG - typedef MSG and associated routines
* NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
* NOSCROLL - SB_* and scrolling routines
* NOSERVICE - All Service Controller routines, SERVICE_ equates, etc.
* NOSOUND - Sound driver routines
* NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
* NOWH - SetWindowsHook and WH_*
* NOWINOFFSETS - GWL_*, GCL_*, associated routines
* NOCOMM - COMM driver routines
* NOKANJI - Kanji support stuff.
* NOHELP - Help engine interface.
* NOPROFILER - Profiler interface.
* NODEFERWINDOWPOS - DeferWindowPos routines
* NOMCX - Modem Configuration Extensions
*/
#endif /* defined(_WIN64) || defined(_WIN32) */
#endif /* _C4_WINDOWS_PUSH_HPP_ */
-660
View File
@@ -1,660 +0,0 @@
#ifndef _C4_YML_COMMON_HPP_
#define _C4_YML_COMMON_HPP_
/** @file common.hpp Common utilities and infrastructure used by ryml. */
#include <cstddef>
#include <c4/substr.hpp>
#include <c4/charconv.hpp>
#include <c4/dump.hpp>
#include <c4/yml/export.hpp>
#if defined(C4_MSVC) || defined(C4_MINGW) || defined(_WIN32) || defined(C4_WIN)
#include <malloc.h>
#else
#include <alloca.h>
#endif
//-----------------------------------------------------------------------------
#ifndef RYML_ERRMSG_SIZE
/// size for the error message buffer
#define RYML_ERRMSG_SIZE (1024)
#endif
#ifndef RYML_LOGBUF_SIZE
/// size for the buffer used to format individual values to string
/// while preparing an error message. This is only used for formatting
/// individual values in the message; final messages will be larger
/// than this value (see @ref RYML_ERRMSG_SIZE). This is also used for
/// the detailed debug log messages when RYML_DBG is defined.
#define RYML_LOGBUF_SIZE (256)
#endif
#ifndef RYML_LOGBUF_SIZE_MAX
/// size for the fallback larger log buffer. When @ref
/// RYML_LOGBUF_SIZE is not large enough to convert a value to string,
/// then temporary stack memory is allocated up to
/// RYML_LOGBUF_SIZE_MAX. This limit is in place to prevent a stack
/// overflow. If the printed value requires more than
/// RYML_LOGBUF_SIZE_MAX, the value is silently skipped.
#define RYML_LOGBUF_SIZE_MAX (1024)
#endif
#ifndef RYML_LOCATIONS_SMALL_THRESHOLD
/// threshold at which a location search will revert from linear to
/// binary search.
#define RYML_LOCATIONS_SMALL_THRESHOLD (30)
#endif
//-----------------------------------------------------------------------------
// Specify groups to have a predefined topic order in doxygen:
/** @defgroup doc_quickstart Quickstart
*
* Example code for every feature.
*/
/** @defgroup doc_parse Parse utilities
* @see sample::sample_parse_in_place
* @see sample::sample_parse_in_arena
* @see sample::sample_parse_file
* @see sample::sample_parse_reuse_tree
* @see sample::sample_parse_reuse_parser
* @see sample::sample_parse_reuse_tree_and_parser
* @see sample::sample_location_tracking
*/
/** @defgroup doc_emit Emit utilities
*
* Utilities to emit YAML and JSON, either to a memory buffer or to a
* file or ostream-like class.
*
* @see sample::sample_emit_to_container
* @see sample::sample_emit_to_stream
* @see sample::sample_emit_to_file
* @see sample::sample_emit_nested_node
* @see sample::sample_emit_style
*/
/** @defgroup doc_node_type Node types
*/
/** @defgroup doc_tree Tree utilities
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*
* @see sample::sample_static_trees
* @see sample::sample_location_tracking
*
* @see sample::sample_docs
* @see sample::sample_anchors_and_aliases
* @see sample::sample_tags
*/
/** @defgroup doc_node_classes Node classes
*
* High-level node classes.
*
* @see sample::sample_quick_overview
* @see sample::sample_iterate_trees
* @see sample::sample_create_trees
* @see sample::sample_tree_arena
*/
/** @defgroup doc_callbacks Callbacks for errors and allocation
*
* Functions called by ryml to allocate/free memory and to report
* errors.
*
* @see sample::sample_error_handler
* @see sample::sample_global_allocator
* @see sample::sample_per_tree_allocator
*/
/** @defgroup doc_serialization Serialization/deserialization
*
* Contains information on how to serialize and deserialize
* fundamental types, user scalar types, user container types and
* interop with std scalar/container types.
*
*/
/** @defgroup doc_ref_utils Anchor/Reference utilities
*
* @see sample::sample_anchors_and_aliases
* */
/** @defgroup doc_tag_utils Tag utilities
* @see sample::sample_tags
*/
/** @defgroup doc_preprocessors Preprocessors
*
* Functions for preprocessing YAML prior to parsing.
*/
//-----------------------------------------------------------------------------
// document macros for doxygen
#ifdef __DOXYGEN__ // defined in Doxyfile::PREDEFINED
/** define this macro with a boolean value to enable/disable
* assertions to check preconditions and assumptions throughout the
* codebase; this causes a slowdown of the code, and larger code
* size. By default, this macro is defined unless NDEBUG is defined
* (see C4_USE_ASSERT); as a result, by default this macro is truthy
* only in debug builds. */
# define RYML_USE_ASSERT
/** (Undefined by default) Define this macro to disable ryml's default
* implementation of the callback functions; see @ref c4::yml::Callbacks */
# define RYML_NO_DEFAULT_CALLBACKS
/** (Undefined by default) When this macro is defined (and
* @ref RYML_NO_DEFAULT_CALLBACKS is not defined), the default error
* handler will throw C++ exceptions of type `std::runtime_error`. */
# define RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
/** Conditionally expands to `noexcept` when @ref RYML_USE_ASSERT is 0 and
* is empty otherwise. The user is unable to override this macro. */
# define RYML_NOEXCEPT
#endif
//-----------------------------------------------------------------------------
/** @cond dev*/
#ifndef RYML_USE_ASSERT
# define RYML_USE_ASSERT C4_USE_ASSERT
#endif
#if RYML_USE_ASSERT
# define RYML_ASSERT(cond) RYML_CHECK(cond)
# define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg)
# define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond))
# define _RYML_CB_ASSERT_(cb, cond, loc) _RYML_CB_CHECK((cb), (cond), (loc))
# define RYML_NOEXCEPT
#else
# define RYML_ASSERT(cond)
# define RYML_ASSERT_MSG(cond, msg)
# define _RYML_CB_ASSERT(cb, cond)
# define _RYML_CB_ASSERT_(cb, cond, loc)
# define RYML_NOEXCEPT noexcept
#endif
#define RYML_DEPRECATED(msg) C4_DEPRECATED(msg)
#define RYML_CHECK(cond) \
do { \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK(); \
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define RYML_CHECK_MSG(cond, msg) \
do \
{ \
if(C4_UNLIKELY(!(cond))) \
{ \
RYML_DEBUG_BREAK(); \
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
# define RYML_DEBUG_BREAK() \
do { \
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
{ \
C4_DEBUG_BREAK(); \
} \
} while(0)
#else
# define RYML_DEBUG_BREAK()
#endif
/** @endcond */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
#ifndef RYML_ID_TYPE
/** The type of a node id in the YAML tree. In the future, the default
* will likely change to int32_t, which was observed to be faster.
* @see id_type */
#define RYML_ID_TYPE size_t
#endif
/** The type of a node id in the YAML tree; to override the default
* type, define the macro @ref RYML_ID_TYPE to a suitable integer
* type. */
using id_type = RYML_ID_TYPE;
static_assert(std::is_integral<id_type>::value, "id_type must be an integer type");
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
enum : id_type {
/** an index to none */
NONE = id_type(-1),
};
C4_SUPPRESS_WARNING_GCC_CLANG_POP
enum : size_t {
/** a null string position */
npos = size_t(-1)
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//! holds a position into a source buffer
struct RYML_EXPORT LineCol
{
//! number of bytes from the beginning of the source buffer
size_t offset;
//! line
size_t line;
//! column
size_t col;
LineCol() = default;
//! construct from line and column
LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {}
//! construct from offset, line and column
LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
};
static_assert(std::is_trivially_copyable<LineCol>::value, "LineCol not trivially copyable");
static_assert(std::is_trivially_default_constructible<LineCol>::value, "LineCol not trivially default constructible");
static_assert(std::is_standard_layout<LineCol>::value, "Location not trivial");
//! a source file position
struct RYML_EXPORT Location
{
//! number of bytes from the beginning of the source buffer
size_t offset;
//! line
size_t line;
//! column
size_t col;
//! file name
csubstr name;
operator bool () const { return !name.empty() || line != 0 || offset != 0 || col != 0; }
operator LineCol const& () const { return reinterpret_cast<LineCol const&>(*this); } // NOLINT
Location() = default;
Location( size_t l, size_t c) : offset( ), line(l), col(c), name( ) {}
Location( size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name( ) {}
Location( csubstr n, size_t l, size_t c) : offset( ), line(l), col(c), name(n) {}
Location( csubstr n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(n) {}
Location(const char *n, size_t l, size_t c) : offset( ), line(l), col(c), name(to_csubstr(n)) {}
Location(const char *n, size_t b, size_t l, size_t c) : offset(b), line(l), col(c), name(to_csubstr(n)) {}
};
static_assert(std::is_standard_layout<Location>::value, "Location not trivial");
//-----------------------------------------------------------------------------
/** @addtogroup doc_callbacks
*
* @{ */
struct Callbacks;
/** set the global callbacks for the library; after a call to this
* function, these callbacks will be used by newly created objects
* (unless they are copying older objects with different
* callbacks). If @ref RYML_NO_DEFAULT_CALLBACKS is defined, it is
* mandatory to call this function prior to using any other library
* facility.
*
* @warning This function is NOT thread-safe.
*
* @warning the error callback must never return: see @ref pfn_error
* for more details */
RYML_EXPORT void set_callbacks(Callbacks const& c);
/** get the global callbacks
* @warning This function is not thread-safe. */
RYML_EXPORT Callbacks const& get_callbacks();
/** set the global callbacks back to their defaults ()
* @warning This function is not thread-safe. */
RYML_EXPORT void reset_callbacks();
/** the type of the function used to report errors
*
* @warning When given by the user, this function MUST interrupt
* execution, typically by either throwing an exception, or using
* `std::longjmp()` ([see
* documentation](https://en.cppreference.com/w/cpp/utility/program/setjmp))
* or by calling `std::abort()`. If the function returned, the parser
* would enter into an infinite loop, or the program may crash. */
using pfn_error = void (*) (const char* msg, size_t msg_len, Location location, void *user_data);
/** the type of the function used to allocate memory; ryml will only
* allocate memory through this callback. */
using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data);
/** the type of the function used to free memory; ryml will only free
* memory through this callback. */
using pfn_free = void (*)(void* mem, size_t size, void *user_data);
/** a c-style callbacks class. Can be used globally by the library
* and/or locally by @ref Tree and @ref Parser objects. */
struct RYML_EXPORT Callbacks
{
void * m_user_data;
pfn_allocate m_allocate;
pfn_free m_free;
pfn_error m_error;
/** Construct an object with the default callbacks. If
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, the object will have null
* members.*/
Callbacks() noexcept;
/** Construct an object with the given callbacks.
*
* @param user_data Data to be forwarded in every call to a callback.
*
* @param alloc A pointer to an allocate function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* alloc implementation.
*
* @param free A pointer to a free function. Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default free
* implementation.
*
* @param error A pointer to an error function, which must never
* return (see @ref pfn_error). Unless
* @ref RYML_NO_DEFAULT_CALLBACKS is defined, when this
* parameter is null, will fall back to ryml's default
* error implementation.
*/
Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error);
bool operator!= (Callbacks const& that) const { return !operator==(that); }
bool operator== (Callbacks const& that) const
{
return (m_user_data == that.m_user_data &&
m_allocate == that.m_allocate &&
m_free == that.m_free &&
m_error == that.m_error);
}
};
/** @} */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
typedef enum {
NOBOM,
UTF8,
UTF16LE,
UTF16BE,
UTF32LE,
UTF32BE,
} Encoding_e;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// @cond dev
// BEWARE! MSVC requires that [[noreturn]] appears before RYML_EXPORT
[[noreturn]] RYML_EXPORT void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc);
[[noreturn]] RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc);
[[noreturn]] inline void error(const char *msg, size_t msg_len)
{
error(msg, msg_len, Location{});
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N], Location loc)
{
error(msg, N-1, loc);
}
template<size_t N>
[[noreturn]] inline void error(const char (&msg)[N])
{
error(msg, N-1, Location{});
}
#define _RYML_CB_ERR(cb, msg_literal) \
_RYML_CB_ERR_(cb, msg_literal, c4::yml::Location(__FILE__, 0, __LINE__, 0))
#define _RYML_CB_CHECK(cb, cond) \
_RYML_CB_CHECK_(cb, cond, c4::yml::Location(__FILE__, 0, __LINE__, 0))
#define _RYML_CB_ERR_(cb, msg_literal, loc) \
do \
{ \
const char msg[] = msg_literal; \
RYML_DEBUG_BREAK(); \
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
C4_UNREACHABLE_AFTER_ERR(); \
} while(0)
#define _RYML_CB_CHECK_(cb, cond, loc) \
do \
{ \
if(C4_UNLIKELY(!(cond))) \
{ \
const char msg[] = "check failed: " #cond; \
RYML_DEBUG_BREAK(); \
c4::yml::error((cb), msg, sizeof(msg)-1, loc); \
C4_UNREACHABLE_AFTER_ERR(); \
} \
} while(0)
#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), T, (num), nullptr)
#define _RYML_CB_FREE(cb, buf, T, num) \
do { \
(cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \
(buf) = nullptr; \
} while(0)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
typedef enum {
BLOCK_LITERAL, //!< keep newlines (|)
BLOCK_FOLD //!< replace newline with single space (>)
} BlockStyle_e;
typedef enum {
CHOMP_CLIP, //!< single newline at end (default)
CHOMP_STRIP, //!< no newline at end (-)
CHOMP_KEEP //!< all newlines from end (+)
} BlockChomp_e;
/** Abstracts the fact that a scalar filter result may not fit in the
* intended memory. */
struct FilterResult
{
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
C4_ALWAYS_INLINE size_t required_len() const noexcept { return str.len; }
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
csubstr str;
};
/** Abstracts the fact that a scalar filter result may not fit in the
* intended memory. */
struct FilterResultExtending
{
C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
C4_ALWAYS_INLINE size_t required_len() const noexcept { return reqlen; }
C4_ALWAYS_INLINE csubstr get() const { RYML_ASSERT(valid()); return str; }
csubstr str;
size_t reqlen;
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace detail {
// is there a better way to do this?
template<int8_t signedval, uint8_t unsignedval>
struct _charconstant_t
: public std::conditional<std::is_signed<char>::value,
std::integral_constant<int8_t, static_cast<int8_t>(unsignedval)>,
std::integral_constant<uint8_t, unsignedval>>::type
{};
#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value
} // namespace detail
namespace detail {
struct _SubstrWriter
{
substr buf;
size_t pos;
_SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
void append(csubstr s)
{
C4_ASSERT(!s.overlaps(buf));
C4_ASSERT(s.str || !s.len);
if(s.len && pos + s.len <= buf.len)
{
C4_ASSERT(s.str);
memcpy(buf.str + pos, s.str, s.len);
}
pos += s.len;
}
void append(char c)
{
C4_ASSERT(buf.str);
if(pos < buf.len)
buf.str[pos] = c;
++pos;
}
void append_n(char c, size_t numtimes)
{
C4_ASSERT(buf.str);
if(numtimes && pos + numtimes < buf.len)
memset(buf.str + pos, c, numtimes);
pos += numtimes;
}
size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; }
size_t excess() const { return pos > buf.len ? pos - buf.len : 0; }
//! get the part written so far
csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
//! get the part that is still free to write to (the remainder)
substr rem() const { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
size_t advance(size_t more) { pos += more; return pos; }
};
} // namespace detail
namespace detail {
// dumpfn is a function abstracting prints to terminal (or to string).
template<class DumpFn, class ...Args>
C4_NO_INLINE void _dump(DumpFn &&dumpfn, csubstr fmt, Args&& ...args)
{
DumpResults results;
// try writing everything:
{
// buffer for converting individual arguments. it is defined
// in a child scope to free it in case the buffer is too small
// for any of the arguments.
char writebuf[RYML_LOGBUF_SIZE];
results = format_dump_resume(std::forward<DumpFn>(dumpfn), writebuf, fmt, std::forward<Args>(args)...);
}
// if any of the arguments failed to fit the buffer, allocate a
// larger buffer (up to a limit) and resume writing.
//
// results.bufsize is set to the size of the largest element
// serialized. Eg int(1) will require 1 byte.
if(C4_UNLIKELY(results.bufsize > RYML_LOGBUF_SIZE))
{
const size_t bufsize = results.bufsize <= RYML_LOGBUF_SIZE_MAX ? results.bufsize : RYML_LOGBUF_SIZE_MAX;
#ifdef C4_MSVC
substr largerbuf = {static_cast<char*>(_alloca(bufsize)), bufsize};
#else
substr largerbuf = {static_cast<char*>(alloca(bufsize)), bufsize};
#endif
results = format_dump_resume(std::forward<DumpFn>(dumpfn), results, largerbuf, fmt, std::forward<Args>(args)...);
}
}
template<class ...Args>
C4_NORETURN C4_NO_INLINE void _report_err(Callbacks const& C4_RESTRICT callbacks, csubstr fmt, Args const& C4_RESTRICT ...args)
{
char errmsg[RYML_ERRMSG_SIZE] = {0};
detail::_SubstrWriter writer(errmsg);
auto dumpfn = [&writer](csubstr s){ writer.append(s); };
_dump(dumpfn, fmt, args...);
writer.append('\n');
const size_t len = writer.pos < RYML_ERRMSG_SIZE ? writer.pos : RYML_ERRMSG_SIZE;
callbacks.m_error(errmsg, len, {}, callbacks.m_user_data);
C4_UNREACHABLE_AFTER_ERR();
}
} // namespace detail
inline csubstr _c4prc(const char &C4_RESTRICT c) // pass by reference!
{
switch(c)
{
case '\n': return csubstr("\\n");
case '\t': return csubstr("\\t");
case '\0': return csubstr("\\0");
case '\r': return csubstr("\\r");
case '\f': return csubstr("\\f");
case '\b': return csubstr("\\b");
case '\v': return csubstr("\\v");
case '\a': return csubstr("\\a");
default: return csubstr(&c, 1);
}
}
/// @endcond
C4_SUPPRESS_WARNING_GCC_POP
} // namespace yml
} // namespace c4
#endif /* _C4_YML_COMMON_HPP_ */
-200
View File
@@ -1,200 +0,0 @@
#ifndef C4_YML_DETAIL_CHECKS_HPP_
#define C4_YML_DETAIL_CHECKS_HPP_
#include "c4/yml/tree.hpp"
#ifdef __clang__
# pragma clang diagnostic push
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wtype-limits" // error: comparison of unsigned expression >= 0 is always true
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
#endif
namespace c4 {
namespace yml {
void check_invariants(Tree const& t, id_type node=NONE);
void check_free_list(Tree const& t);
void check_arena(Tree const& t);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_invariants(Tree const& t, id_type node)
{
if(node == NONE)
{
if(t.empty()) return;
node = t.root_id();
}
NodeData const& n = *t._p(node);
#if defined(RYML_DBG) && 0
if(n.m_first_child != NONE || n.m_last_child != NONE)
{
printf("check(%zu): fc=%zu lc=%zu\n", node, n.m_first_child, n.m_last_child);
}
else
{
printf("check(%zu)\n", node);
}
#endif
C4_CHECK(n.m_parent != node);
if(n.m_parent == NONE)
{
C4_CHECK(t.is_root(node));
}
else //if(n.m_parent != NONE)
{
C4_CHECK(t.has_child(n.m_parent, node));
auto const& p = *t._p(n.m_parent);
if(n.m_prev_sibling == NONE)
{
C4_CHECK(p.m_first_child == node);
C4_CHECK(t.first_sibling(node) == node);
}
else
{
C4_CHECK(p.m_first_child != node);
C4_CHECK(t.first_sibling(node) != node);
}
if(n.m_next_sibling == NONE)
{
C4_CHECK(p.m_last_child == node);
C4_CHECK(t.last_sibling(node) == node);
}
else
{
C4_CHECK(p.m_last_child != node);
C4_CHECK(t.last_sibling(node) != node);
}
}
C4_CHECK(n.m_first_child != node);
C4_CHECK(n.m_last_child != node);
if(n.m_first_child != NONE || n.m_last_child != NONE)
{
C4_CHECK(n.m_first_child != NONE);
C4_CHECK(n.m_last_child != NONE);
}
C4_CHECK(n.m_prev_sibling != node);
C4_CHECK(n.m_next_sibling != node);
if(n.m_prev_sibling != NONE)
{
C4_CHECK(t._p(n.m_prev_sibling)->m_next_sibling == node);
C4_CHECK(t._p(n.m_prev_sibling)->m_prev_sibling != node);
}
if(n.m_next_sibling != NONE)
{
C4_CHECK(t._p(n.m_next_sibling)->m_prev_sibling == node);
C4_CHECK(t._p(n.m_next_sibling)->m_next_sibling != node);
}
id_type count = 0;
for(id_type i = n.m_first_child; i != NONE; i = t.next_sibling(i))
{
#if defined(RYML_DBG) && 0
printf("check(%zu): descend to child[%zu]=%zu\n", node, count, i);
#endif
auto const& ch = *t._p(i);
C4_CHECK(ch.m_parent == node);
C4_CHECK(ch.m_next_sibling != i);
++count;
}
C4_CHECK(count == t.num_children(node));
if(n.m_prev_sibling == NONE && n.m_next_sibling == NONE)
{
if(n.m_parent != NONE)
{
C4_CHECK(t.num_children(n.m_parent) == 1);
C4_CHECK(t.num_siblings(node) == 1);
}
}
if(node == t.root_id())
{
C4_CHECK(t.size() == t.m_size);
C4_CHECK(t.capacity() == t.m_cap);
C4_CHECK(t.m_cap == t.m_size + t.slack());
check_free_list(t);
check_arena(t);
}
for(id_type i = t.first_child(node); i != NONE; i = t.next_sibling(i))
{
check_invariants(t, i);
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_free_list(Tree const& t)
{
if(t.m_free_head == NONE)
{
C4_CHECK(t.m_free_tail == t.m_free_head);
return;
}
C4_CHECK(t.m_free_head >= 0 && t.m_free_head < t.m_cap);
C4_CHECK(t.m_free_tail >= 0 && t.m_free_tail < t.m_cap);
auto const& head = *t._p(t.m_free_head);
//auto const& tail = *t._p(t.m_free_tail);
//C4_CHECK(head.m_prev_sibling == NONE);
//C4_CHECK(tail.m_next_sibling == NONE);
id_type count = 0;
for(id_type i = t.m_free_head, prev = NONE; i != NONE; i = t._p(i)->m_next_sibling)
{
auto const& elm = *t._p(i);
if(&elm != &head)
{
C4_CHECK(elm.m_prev_sibling == prev);
}
prev = i;
++count;
}
C4_CHECK(count == t.slack());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void check_arena(Tree const& t)
{
C4_CHECK(t.m_arena.len == 0 || (t.m_arena_pos >= 0 && t.m_arena_pos <= t.m_arena.len));
C4_CHECK(t.arena_size() == t.m_arena_pos);
C4_CHECK(t.arena_slack() + t.m_arena_pos == t.m_arena.len);
}
} /* namespace yml */
} /* namespace c4 */
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif /* C4_YML_DETAIL_CHECKS_HPP_ */
-129
View File
@@ -1,129 +0,0 @@
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#define _C4_YML_DETAIL_DBGPRINT_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "../common.hpp"
#endif
#ifdef RYML_DBG
#include <cstdio>
#endif
//-----------------------------------------------------------------------------
// debug prints
#ifndef RYML_DBG
# define _c4dbgt(fmt, ...)
# define _c4dbgpf(fmt, ...)
# define _c4dbgpf_(fmt, ...)
# define _c4dbgp(msg)
# define _c4dbgp_(msg)
# define _c4dbgq(msg)
# define _c4presc(...)
# define _c4prscalar(msg, scalar, keep_newlines)
#else
# define _c4dbgt(fmt, ...) do { if(_dbg_enabled()) { \
this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__); } } while(0)
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgpf_(fmt, ...) _dbg_printf("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
# define _c4dbgp_(msg) _dbg_printf("{}:{}: " msg , __FILE__, __LINE__ )
# define _c4dbgq(msg) _dbg_printf(msg "\n")
# define _c4presc(...) do { if(_dbg_enabled()) __c4presc(__VA_ARGS__); } while(0)
# define _c4prscalar(msg, scalar, keep_newlines) \
do { \
_c4dbgpf_("{}: [{}]~~~", msg, scalar.len); \
if(_dbg_enabled()) { \
__c4presc((scalar).str, (scalar).len, (keep_newlines)); \
} \
_c4dbgq("~~~"); \
} while(0)
#endif // RYML_DBG
//-----------------------------------------------------------------------------
#ifdef RYML_DBG
#include <c4/dump.hpp>
namespace c4 {
inline bool& _dbg_enabled() { static bool enabled = true; return enabled; }
inline void _dbg_set_enabled(bool yes) { _dbg_enabled() = yes; }
inline void _dbg_dumper(csubstr s)
{
if(s.str)
fwrite(s.str, 1, s.len, stdout);
}
inline substr _dbg_buf() noexcept
{
static char writebuf[2048];
return substr{writebuf, sizeof(writebuf)}; // g++-5 has trouble with return writebuf;
}
template<class ...Args>
C4_NO_INLINE void _dbg_printf(c4::csubstr fmt, Args const& ...args)
{
if(_dbg_enabled())
{
substr buf = _dbg_buf();
const size_t needed_size = c4::format_dump(&_dbg_dumper, buf, fmt, args...);
C4_CHECK(needed_size <= buf.len);
}
}
inline C4_NO_INLINE void __c4presc(const char *s, size_t len, bool keep_newlines=false)
{
RYML_ASSERT(s || !len);
size_t prev = 0;
for(size_t i = 0; i < len; ++i)
{
switch(s[i])
{
case '\n' : _dbg_printf("{}{}{}", csubstr(s+prev, i-prev), csubstr("\\n"), csubstr(keep_newlines ? "\n":"")); prev = i+1; break;
case '\t' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\t")); prev = i+1; break;
case '\0' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\0")); prev = i+1; break;
case '\r' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\r")); prev = i+1; break;
case '\f' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\f")); prev = i+1; break;
case '\b' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\b")); prev = i+1; break;
case '\v' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\v")); prev = i+1; break;
case '\a' : _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\a")); prev = i+1; break;
case '\x1b': _dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\x1b")); prev = i+1; break;
case -0x3e/*0xc2u*/:
if(i+1 < len)
{
if(s[i+1] == -0x60/*0xa0u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\_")); prev = i+1;
}
else if(s[i+1] == -0x7b/*0x85u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\N")); prev = i+1;
}
}
break;
case -0x1e/*0xe2u*/:
if(i+2 < len && s[i+1] == -0x80/*0x80u*/)
{
if(s[i+2] == -0x58/*0xa8u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\L")); prev = i+1;
}
else if(s[i+2] == -0x57/*0xa9u*/)
{
_dbg_printf("{}{}", csubstr(s+prev, i-prev), csubstr("\\P")); prev = i+1;
}
}
break;
}
}
if(len > prev)
_dbg_printf("{}", csubstr(s+prev, len-prev));
}
inline void __c4presc(csubstr s, bool keep_newlines=false)
{
__c4presc(s.str, s.len, keep_newlines);
}
} // namespace c4
#endif // RYML_DBG
#endif /* _C4_YML_DETAIL_DBGPRINT_HPP_ */
-184
View File
@@ -1,184 +0,0 @@
#ifndef C4_YML_DETAIL_PRINT_HPP_
#define C4_YML_DETAIL_PRINT_HPP_
#include "c4/yml/tree.hpp"
#include "c4/yml/node.hpp"
#ifdef RYML_DBG
#define _c4dbg_tree(...) print_tree(__VA_ARGS__)
#define _c4dbg_node(...) print_tree(__VA_ARGS__)
#else
#define _c4dbg_tree(...)
#define _c4dbg_node(...)
#endif
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
inline const char* _container_style_code(Tree const& p, id_type node)
{
if(p.is_container(node))
{
if(p._p(node)->m_type & (FLOW_SL|FLOW_ML))
{
return "[FLOW]";
}
if(p._p(node)->m_type & (BLOCK))
{
return "[BLCK]";
}
}
return "";
}
inline char _scalar_code(NodeType masked)
{
if(masked & (KEY_LITERAL|VAL_LITERAL))
return '|';
if(masked & (KEY_FOLDED|VAL_FOLDED))
return '>';
if(masked & (KEY_SQUO|VAL_SQUO))
return '\'';
if(masked & (KEY_DQUO|VAL_DQUO))
return '"';
if(masked & (KEY_PLAIN|VAL_PLAIN))
return '~';
return '@';
}
inline char _scalar_code_key(NodeType t)
{
return _scalar_code(t & KEY_STYLE);
}
inline char _scalar_code_val(NodeType t)
{
return _scalar_code(t & VAL_STYLE);
}
inline char _scalar_code_key(Tree const& p, id_type node)
{
return _scalar_code_key(p._p(node)->m_type);
}
inline char _scalar_code_val(Tree const& p, id_type node)
{
return _scalar_code_key(p._p(node)->m_type);
}
inline id_type print_node(Tree const& p, id_type node, int level, id_type count, bool print_children)
{
printf("[%zu]%*s[%zu] %p", (size_t)count, (2*level), "", (size_t)node, (void const*)p.get(node));
if(p.is_root(node))
{
printf(" [ROOT]");
}
char typebuf[128];
csubstr typestr = p.type(node).type_str(typebuf);
RYML_CHECK(typestr.str);
printf(" %.*s", (int)typestr.len, typestr.str);
if(p.has_key(node))
{
if(p.has_key_anchor(node))
{
csubstr ka = p.key_anchor(node);
printf(" &%.*s", (int)ka.len, ka.str);
}
if(p.has_key_tag(node))
{
csubstr kt = p.key_tag(node);
printf(" <%.*s>", (int)kt.len, kt.str);
}
const char code = _scalar_code_key(p, node);
csubstr k = p.key(node);
printf(" %c%.*s%c :", code, (int)k.len, k.str, code);
}
if(p.has_val_anchor(node))
{
csubstr a = p.val_anchor(node);
printf(" &%.*s'", (int)a.len, a.str);
}
if(p.has_val_tag(node))
{
csubstr vt = p.val_tag(node);
printf(" <%.*s>", (int)vt.len, vt.str);
}
if(p.has_val(node))
{
const char code = _scalar_code_val(p, node);
csubstr v = p.val(node);
printf(" %c%.*s%c", code, (int)v.len, v.str, code);
}
printf(" (%zu sibs)", (size_t)p.num_siblings(node));
++count;
if(!p.is_container(node))
{
printf("\n");
}
else
{
printf(" (%zu children)\n", (size_t)p.num_children(node));
if(print_children)
{
for(id_type i = p.first_child(node); i != NONE; i = p.next_sibling(i))
{
count = print_node(p, i, level+1, count, print_children);
}
}
}
return count;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void print_node(ConstNodeRef const& p, int level=0)
{
print_node(*p.tree(), p.id(), level, 0, true);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline id_type print_tree(const char *message, Tree const& p, id_type node=NONE)
{
printf("--------------------------------------\n");
if(message != nullptr)
printf("%s:\n", message);
id_type ret = 0;
if(!p.empty())
{
if(node == NONE)
node = p.root_id();
ret = print_node(p, node, 0, 0, true);
}
printf("#nodes=%zu vs #printed=%zu\n", (size_t)p.size(), (size_t)ret);
printf("--------------------------------------\n");
return ret;
}
inline id_type print_tree(Tree const& p, id_type node=NONE)
{
return print_tree(nullptr, p, node);
}
inline void print_tree(ConstNodeRef const& p, int level)
{
print_node(p, level);
for(ConstNodeRef ch : p.children())
{
print_tree(ch, level+1);
}
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} /* namespace yml */
} /* namespace c4 */
#endif /* C4_YML_DETAIL_PRINT_HPP_ */
-291
View File
@@ -1,291 +0,0 @@
#ifndef _C4_YML_DETAIL_STACK_HPP_
#define _C4_YML_DETAIL_STACK_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "../common.hpp"
#endif
#ifdef RYML_DBG
# include <type_traits>
#endif
#include <string.h>
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
namespace detail {
/** A lightweight contiguous stack with Small Storage
* Optimization. This is required because std::vector can throw
* exceptions, and we don't want to enforce any particular error
* mechanism. */
template<class T, id_type N=16>
class stack
{
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");
public:
enum : id_type { sso_size = N };
public:
T m_buf[size_t(N)];
T *C4_RESTRICT m_stack;
id_type m_size;
id_type m_capacity;
Callbacks m_callbacks;
public:
constexpr static bool is_contiguous() { return true; }
stack(Callbacks const& cb)
: m_buf()
, m_stack(m_buf)
, m_size(0)
, m_capacity(N)
, m_callbacks(cb) {}
stack() : stack(get_callbacks()) {}
~stack()
{
_free();
}
stack(stack const& that) RYML_NOEXCEPT : stack(that.m_callbacks)
{
resize(that.m_size);
_cp(&that);
}
stack(stack &&that) noexcept : stack(that.m_callbacks)
{
_mv(&that);
}
stack& operator= (stack const& that) RYML_NOEXCEPT
{
if(&that != this)
{
_cb(that.m_callbacks);
resize(that.m_size);
_cp(&that);
}
return *this;
}
stack& operator= (stack &&that) noexcept
{
_cb(that.m_callbacks);
_mv(&that);
return *this;
}
public:
id_type size() const { return m_size; }
id_type empty() const { return m_size == 0; }
id_type capacity() const { return m_capacity; }
void clear()
{
m_size = 0;
}
void resize(id_type sz)
{
reserve(sz);
m_size = sz;
}
void reserve(id_type sz);
void push(T const& C4_RESTRICT n)
{
_RYML_CB_ASSERT(m_callbacks, (const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
if(m_size == m_capacity)
{
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
reserve(cap);
}
m_stack[m_size] = n;
++m_size;
}
void push_top()
{
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
if(m_size == m_capacity)
{
id_type cap = m_capacity == 0 ? N : 2 * m_capacity;
reserve(cap);
}
m_stack[m_size] = m_stack[m_size - 1];
++m_size;
}
T const& C4_RESTRICT pop()
{
_RYML_CB_ASSERT(m_callbacks, m_size > 0);
--m_size;
return m_stack[m_size];
}
C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
C4_ALWAYS_INLINE T & C4_RESTRICT top() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[m_size - 1]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { _RYML_CB_ASSERT(m_callbacks, m_size > 0); return m_stack[0]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT top(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT top(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[m_size - 1 - i]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT bottom(id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](id_type i) const { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
C4_ALWAYS_INLINE T & C4_RESTRICT operator[](id_type i) { _RYML_CB_ASSERT(m_callbacks, i < m_size); return m_stack[i]; }
public:
using iterator = T *;
using const_iterator = T const *;
iterator begin() { return m_stack; }
iterator end () { return m_stack + m_size; }
const_iterator begin() const { return (const_iterator)m_stack; }
const_iterator end () const { return (const_iterator)m_stack + m_size; }
public:
void _free();
void _cp(stack const* C4_RESTRICT that);
void _mv(stack * that);
void _cb(Callbacks const& cb);
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::reserve(id_type sz)
{
if(sz <= m_size)
return;
if(sz <= N)
{
m_stack = m_buf;
m_capacity = N;
return;
}
T *buf = (T*) m_callbacks.m_allocate((size_t)sz * sizeof(T), m_stack, m_callbacks.m_user_data);
_RYML_CB_ASSERT(m_callbacks, ((uintptr_t)buf % alignof(T)) == 0u);
memcpy(buf, m_stack, (size_t)m_size * sizeof(T));
if(m_stack != m_buf)
{
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
}
m_stack = buf;
m_capacity = sz;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_free()
{
_RYML_CB_ASSERT(m_callbacks, m_stack != nullptr); // this structure cannot be memset() to zero
if(m_stack != m_buf)
{
m_callbacks.m_free(m_stack, (size_t)m_capacity * sizeof(T), m_callbacks.m_user_data);
m_stack = m_buf;
m_size = N;
m_capacity = N;
}
else
{
_RYML_CB_ASSERT(m_callbacks, m_capacity == N);
}
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_cp(stack const* C4_RESTRICT that)
{
if(that->m_stack != that->m_buf)
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
}
else
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
}
memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));
m_size = that->m_size;
m_capacity = that->m_size < N ? N : that->m_size;
m_callbacks = that->m_callbacks;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_mv(stack * that)
{
if(that->m_stack != that->m_buf)
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity > N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
m_stack = that->m_stack;
}
else
{
_RYML_CB_ASSERT(m_callbacks, that->m_capacity <= N);
_RYML_CB_ASSERT(m_callbacks, that->m_size <= that->m_capacity);
memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));
m_stack = m_buf;
}
m_size = that->m_size;
m_capacity = that->m_capacity;
m_callbacks = that->m_callbacks;
// make sure no deallocation happens on destruction
_RYML_CB_ASSERT(m_callbacks, that->m_stack != m_buf);
that->m_stack = that->m_buf;
that->m_capacity = N;
that->m_size = 0;
}
//-----------------------------------------------------------------------------
template<class T, id_type N>
void stack<T, N>::_cb(Callbacks const& cb)
{
if(cb != m_callbacks)
{
_free();
m_callbacks = cb;
}
}
} // namespace detail
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace yml
} // namespace c4
#endif /* _C4_YML_DETAIL_STACK_HPP_ */
File diff suppressed because it is too large Load Diff
-909
View File
@@ -1,909 +0,0 @@
#ifndef _C4_YML_EMIT_HPP_
#define _C4_YML_EMIT_HPP_
/** @file emit.hpp Utilities to emit YAML and JSON. */
#ifndef _C4_YML_WRITER_HPP_
#include "./writer.hpp"
#endif
#ifndef _C4_YML_TREE_HPP_
#include "./tree.hpp"
#endif
#ifndef _C4_YML_NODE_HPP_
#include "./node.hpp"
#endif
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
/** @addtogroup doc_emit
*
* @{
*/
// fwd declarations
template<class Writer> class Emitter;
template<class OStream>
using EmitterOStream = Emitter<WriterOStream<OStream>>;
using EmitterFile = Emitter<WriterFile>;
using EmitterBuf = Emitter<WriterBuf>;
namespace detail {
inline bool is_set_(ConstNodeRef n) { return n.tree() && (n.id() != NONE); }
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Specifies the type of content to emit */
typedef enum {
EMIT_YAML = 0, ///< emit YAML
EMIT_JSON = 1 ///< emit JSON
} EmitType_e;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A lightweight object containing options to be used when emitting. */
struct EmitOptions
{
typedef enum : uint32_t {
DEFAULT_FLAGS = 0u,
JSON_ERR_ON_TAG = 1u << 0u,
JSON_ERR_ON_ANCHOR = 1u << 1u,
_JSON_ERR_MASK = JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
} EmitOptionFlags_e;
public:
/** @name option flags
*
* @{ */
C4_ALWAYS_INLINE EmitOptionFlags_e json_error_flags() const noexcept { return m_option_flags; }
EmitOptions& json_error_flags(EmitOptionFlags_e d) noexcept { m_option_flags = (EmitOptionFlags_e)(d & _JSON_ERR_MASK); return *this; }
/** @} */
public:
/** @name max depth for the emitted tree
*
* This makes the emitter fail when emitting trees exceeding the
* max_depth.
*
* @{ */
C4_ALWAYS_INLINE id_type max_depth() const noexcept { return m_max_depth; }
EmitOptions& max_depth(id_type d) noexcept { m_max_depth = d; return *this; }
static constexpr const id_type max_depth_default = 64;
/** @} */
public:
bool operator== (const EmitOptions& that) const noexcept
{
return m_max_depth == that.m_max_depth &&
m_option_flags == that.m_option_flags;
}
private:
/** @cond dev */
id_type m_max_depth{max_depth_default};
EmitOptionFlags_e m_option_flags{DEFAULT_FLAGS};
/** @endcond */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A stateful emitter, for use with a writer such as @ref WriterBuf,
* @ref WriterFile, or @ref WriterOStream */
template<class Writer>
class Emitter : public Writer
{
public:
/** Construct the emitter and its internal Writer state, using default emit options.
* @param args arguments to be forwarded to the constructor of the writer.
* */
template<class ...Args>
Emitter(Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(), m_flow(false) {}
/** Construct the emitter and its internal Writer state.
*
* @param opts EmitOptions
* @param args arguments to be forwarded to the constructor of the writer.
* */
template<class ...Args>
Emitter(EmitOptions const& opts, Args &&...args) : Writer(std::forward<Args>(args)...), m_tree(), m_opts(opts), m_flow(false) {}
/** emit!
*
* When writing to a buffer, returns a substr of the emitted YAML.
* If the given buffer has insufficient space, the returned substr
* will be null and its size will be the needed space. Whatever
* the size of the buffer, it is guaranteed that no writes are
* done past its end.
*
* When writing to a file, the returned substr will be null, but its
* length will be set to the number of bytes written.
*
* @param type specify what to emit
* @param t the tree to emit
* @param id the id of the node to emit
* @param error_on_excess when true, an error is raised when the
* output buffer is too small for the emitted YAML/JSON
* */
substr emit_as(EmitType_e type, Tree const& t, id_type id, bool error_on_excess);
/** emit starting at the root node */
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true)
{
if(t.empty())
return {};
return this->emit_as(type, t, t.root_id(), error_on_excess);
}
/** emit starting at the given node */
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
}
public:
/** get the emit options for this object */
EmitOptions const& options() const noexcept { return m_opts; }
/** set the max depth for emitted trees (to prevent a stack overflow) */
void max_depth(id_type max_depth) noexcept { m_opts.max_depth(max_depth); }
/** get the max depth for emitted trees (to prevent a stack overflow) */
id_type max_depth() const noexcept { return m_opts.max_depth(); }
private:
Tree const* C4_RESTRICT m_tree;
EmitOptions m_opts;
bool m_flow;
private:
void _emit_yaml(id_type id);
void _do_visit_flow_sl(id_type id, id_type depth, id_type ilevel=0);
void _do_visit_flow_ml(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
void _do_visit_block(id_type id, id_type depth, id_type ilevel=0, id_type do_indent=1);
void _do_visit_block_container(id_type id, id_type depth, id_type next_level, bool do_indent);
void _do_visit_json(id_type id, id_type depth);
private:
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, id_type level);
void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
void _write_doc(id_type id);
void _write_scalar_json_dquo(csubstr s);
void _write_scalar_literal(csubstr s, id_type level, bool as_key);
void _write_scalar_folded(csubstr s, id_type level, bool as_key);
void _write_scalar_squo(csubstr s, id_type level);
void _write_scalar_dquo(csubstr s, id_type level);
void _write_scalar_plain(csubstr s, id_type level);
size_t _write_escaped_newlines(csubstr s, size_t i);
size_t _write_indented_block(csubstr s, size_t i, id_type level);
void _write_tag(csubstr tag)
{
if(!tag.begins_with('!'))
this->Writer::_do_write('!');
this->Writer::_do_write(tag);
}
enum : type_bits {
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|VAL_STYLE) | CONTAINER_STYLE,
_keysc_json = (KEY) | ~(VAL),
_valsc_json = ~(KEY) | (VAL),
};
C4_ALWAYS_INLINE void _writek(id_type id, id_type level) { _write(m_tree->keysc(id), (m_tree->_p(id)->m_type.type & ~_valsc), level); }
C4_ALWAYS_INLINE void _writev(id_type id, id_type level) { _write(m_tree->valsc(id), (m_tree->_p(id)->m_type.type & ~_keysc), level); }
C4_ALWAYS_INLINE void _writek_json(id_type id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
C4_ALWAYS_INLINE void _writev_json(id_type id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
void _indent(id_type level, bool enabled)
{
if(enabled)
this->Writer::_do_write(' ', 2u * (size_t)level);
}
void _indent(id_type level)
{
if(!m_flow)
this->Writer::_do_write(' ', 2u * (size_t)level);
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_file Emit to file
*
* @{
*/
// emit from tree and node id -----------------------
/** (1) emit YAML to the given file, starting at the given node. A null
* file defaults to stdout. Return the number of bytes written. */
inline size_t emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(Tree const& t, id_type id, FILE *f)
{
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file, starting at the given node. A null
* file defaults to stdout. Return the number of bytes written. */
inline size_t emit_json(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(Tree const& t, id_type id, FILE *f)
{
EmitterFile em(f);
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
}
// emit from root -------------------------
/** (1) emit YAML to the given file, starting at the root node. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_yaml(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
{
EmitterFile em(f);
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_json(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
{
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
{
EmitterFile em(f);
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
}
// emit from ConstNodeRef ------------------------
/** (1) emit YAML to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(opts, f);
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(f);
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
}
/** (1) emit JSON to the given file. A null file defaults to stdout.
* Return the number of bytes written. */
inline size_t emit_json(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(opts, f);
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
}
/** (2) like (1), but use default emit options */
inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
{
if(!detail::is_set_(r))
return {};
EmitterFile em(f);
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_ostream Emit to an STL-like ostream
*
* @{
*/
/** emit YAML to an STL-like ostream */
template<class OStream>
inline OStream& operator<< (OStream& s, Tree const& t)
{
EmitterOStream<OStream> em(s);
em.emit_as(EMIT_YAML, t);
return s;
}
/** emit YAML to an STL-like ostream
* @overload */
template<class OStream>
inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
{
if(!detail::is_set_(n))
return s;
EmitterOStream<OStream> em(s);
em.emit_as(EMIT_YAML, n);
return s;
}
/** mark a tree or node to be emitted as yaml when using @ref
* operator<<, with options. For example:
*
* ```cpp
* Tree t = parse_in_arena("{foo: bar}");
* std::cout << t; // emits YAML
* std::cout << as_yaml(t); // emits YAML, same as above
* std::cout << as_yaml(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
* ```
*
* @see @ref operator<< */
struct as_json
{
Tree const* tree;
size_t node;
EmitOptions options;
as_json(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
as_json(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
as_json(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
};
/** mark a tree or node to be emitted as yaml when using @ref
* operator<< . For example:
*
* ```cpp
* Tree t = parse_in_arena("{foo: bar}");
* std::cout << t; // emits YAML
* std::cout << as_json(t); // emits JSON
* std::cout << as_json(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
* ```
*
* @see @ref operator<< */
struct as_yaml
{
Tree const* tree;
size_t node;
EmitOptions options;
as_yaml(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
as_yaml(Tree const& t, size_t id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
as_yaml(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
};
/** emit json to an STL-like stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_json const& j)
{
if(!j.tree || j.node == NONE)
return s;
EmitterOStream<OStream> em(j.options, s);
em.emit_as(EMIT_JSON, *j.tree, j.node, true);
return s;
}
/** emit yaml to an STL-like stream */
template<class OStream>
inline OStream& operator<< (OStream& s, as_yaml const& y)
{
if(!y.tree || y.node == NONE)
return s;
EmitterOStream<OStream> em(y.options, s);
em.emit_as(EMIT_YAML, *y.tree, y.node, true);
return s;
}
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_buffer Emit to memory buffer
*
* @{
*/
// emit from tree and node id -----------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param t the tree to emit.
* @param id the node where to start emitting.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param t the tree to emit.
* @param id the node where to start emitting.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
}
// emit from root -------------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param t the tree; will be emitted from the root node.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, t, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, t, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param t the tree; will be emitted from the root node.
* @param opts emit options.
* @param buf the output buffer.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, t, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
{
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, t, error_on_excess);
}
// emit from ConstNodeRef ------------------------
/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
* @param r the starting node.
* @param buf the output buffer.
* @param opts emit options.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_YAML, r, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(buf);
return em.emit_as(EMIT_YAML, r, error_on_excess);
}
/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
* @param r the starting node.
* @param buf the output buffer.
* @param opts emit options.
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
* @return a substr trimmed to the result in the output buffer. If the buffer is
* insufficient (when error_on_excess is false), the string pointer of the
* result will be set to null, and the length will report the required buffer size. */
inline substr emit_json(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(opts, buf);
return em.emit_as(EMIT_JSON, r, error_on_excess);
}
/** (2) like (1), but use default emit options */
inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
if(!detail::is_set_(r))
return {};
EmitterBuf em(buf);
return em.emit_as(EMIT_JSON, r, error_on_excess);
}
//-----------------------------------------------------------------------------
/** @defgroup doc_emit_to_container Emit to resizeable container
*
* @{
*/
// emit from tree and node id ---------------------------
/** (1) emit+resize: emit YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML. If @p append is
* set to true, the emitted YAML is appended at the end of the container.
*
* @return a substr trimmed to the emitted YAML (excluding the initial contents, when appending) */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
size_t startpos = append ? cont->size() : 0u;
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
substr buf = to_substr(*cont).sub(startpos);
substr ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
cont->resize(startpos + ret.len);
buf = to_substr(*cont).sub(startpos);
ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/true);
}
else
{
cont->resize(startpos + ret.len);
}
return ret;
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
{
return emitrs_yaml(t, id, EmitOptions{}, cont, append);
}
/** (1) emit+resize: emit JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON. If @p append is
* set to true, the emitted YAML is appended at the end of the container.
*
* @return a substr trimmed to the emitted JSON (excluding the initial contents, when appending) */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
const size_t startpos = append ? cont->size() : 0u;
cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
substr buf = to_substr(*cont).sub(startpos);
EmitterBuf em(opts, buf);
substr ret = emit_json(t, id, opts, buf, /*error_on_excess*/false);
if(ret.str == nullptr && ret.len > 0)
{
cont->resize(startpos + ret.len);
buf = to_substr(*cont).sub(startpos);
ret = emit_json(t, id, opts, buf, /*error_on_excess*/true);
}
else
{
cont->resize(startpos + ret.len);
}
return ret;
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
{
return emitrs_json(t, id, EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts={})
{
CharOwningContainer c;
emitrs_yaml(t, id, opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, id_type id, EmitOptions const& opts={})
{
CharOwningContainer c;
emitrs_json(t, id, opts, &c);
return c;
}
// emit from root -------------------------
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted YAML.
* @return a substr trimmed to the new emitted contents. */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_yaml(t, t.root_id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_yaml(t, t.root_id(), EmitOptions{}, cont, append);
}
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like
* container, resizing it as needed to fit the emitted JSON.
* @return a substr trimmed to the new emitted contents. */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_json(t, t.root_id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(Tree const& t, CharOwningContainer * cont, bool append=false)
{
if(t.empty())
return {};
return emitrs_json(t, t.root_id(), EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(Tree const& t, EmitOptions const& opts={})
{
CharOwningContainer c;
if(t.empty())
return c;
emitrs_yaml(t, t.root_id(), opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(Tree const& t, EmitOptions const& opts={})
{
CharOwningContainer c;
if(t.empty())
return c;
emitrs_json(t, t.root_id(), opts, &c);
return c;
}
// emit from ConstNodeRef ------------------------
/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted YAML.
* @return a substr trimmed to the new emitted contents */
template<class CharOwningContainer>
substr emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_yaml(*n.tree(), n.id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_yaml(*n.tree(), n.id(), EmitOptions{}, cont, append);
}
/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like container,
* resizing it as needed to fit the emitted JSON.
* @return a substr trimmed to the new emitted contents */
template<class CharOwningContainer>
substr emitrs_json(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_json(*n.tree(), n.id(), opts, cont, append);
}
/** (2) like (1), but use default emit options */
template<class CharOwningContainer>
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
return emitrs_json(*n.tree(), n.id(), EmitOptions{}, cont, append);
}
/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts={})
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
CharOwningContainer c;
emitrs_yaml(*n.tree(), n.id(), opts, &c);
return c;
}
/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
template<class CharOwningContainer>
CharOwningContainer emitrs_json(ConstNodeRef const& n, EmitOptions const& opts={})
{
if(!detail::is_set_(n))
return {};
_RYML_CB_CHECK(n.tree()->callbacks(), n.readable());
CharOwningContainer c;
emitrs_json(*n.tree(), n.id(), opts, &c);
return c;
}
/** @} */
//-----------------------------------------------------------------------------
/** @cond dev */
#define RYML_DEPRECATE_EMIT \
RYML_DEPRECATED("use emit_yaml() instead. " \
"See https://github.com/biojppm/rapidyaml/issues/120")
#define RYML_DEPRECATE_EMITRS \
RYML_DEPRECATED("use emitrs_yaml() instead. " \
"See https://github.com/biojppm/rapidyaml/issues/120")
// workaround for Qt emit which is a macro;
// see https://github.com/biojppm/rapidyaml/issues/120.
// emit is defined in qobjectdefs.h (as an empty define).
#ifdef emit
#define RYML_TMP_EMIT_
#undef emit
#endif
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, id_type id, FILE *f)
{
return emit_yaml(t, id, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
{
return emit_yaml(t, f);
}
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
{
return emit_yaml(r, f);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, id, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
{
return emit_yaml(t, buf, error_on_excess);
}
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
{
return emit_yaml(r, buf, error_on_excess);
}
#ifdef RYML_TMP_EMIT_
#define emit
#undef RYML_TMP_EMIT_
#endif
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, id_type id, CharOwningContainer * cont)
{
return emitrs_yaml(t, id, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, id_type id)
{
return emitrs_yaml<CharOwningContainer>(t, id);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
{
return emitrs_yaml(t, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
{
return emitrs_yaml<CharOwningContainer>(t);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
{
return emitrs_yaml(n, cont);
}
template<class CharOwningContainer>
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
{
return emitrs_yaml<CharOwningContainer>(n);
}
/** @endcond */
} // namespace yml
} // namespace c4
C4_SUPPRESS_WARNING_GCC_CLANG_POP
#undef RYML_DEPRECATE_EMIT
#undef RYML_DEPRECATE_EMITRS
#include "c4/yml/emit.def.hpp" // NOLINT
#endif /* _C4_YML_EMIT_HPP_ */
@@ -1,194 +0,0 @@
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
#define _C4_YML_EVENT_HANDLER_STACK_HPP_
#ifndef _C4_YML_DETAIL_STACK_HPP_
#include "c4/yml/detail/stack.hpp"
#endif
#ifndef _C4_YML_NODE_TYPE_HPP_
#include "c4/yml/node_type.hpp"
#endif
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#include "c4/yml/detail/dbgprint.hpp"
#endif
#ifndef _C4_YML_PARSER_STATE_HPP_
#include "c4/yml/parser_state.hpp"
#endif
#ifdef RYML_DBG
#ifndef _C4_YML_DETAIL_PRINT_HPP_
#include "c4/yml/detail/print.hpp"
#endif
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_event_handlers
* @{ */
namespace detail {
using pfn_relocate_arena = void (*)(void*, csubstr prev_arena, substr next_arena);
} // detail
/** Use this class a base of implementations of event handler to
* simplify the stack logic. */
template<class HandlerImpl, class HandlerState>
struct EventHandlerStack
{
static_assert(std::is_base_of<ParserState, HandlerState>::value,
"ParserState must be a base of HandlerState");
using state = HandlerState;
using pfn_relocate_arena = detail::pfn_relocate_arena;
public:
detail::stack<state> m_stack;
state *C4_RESTRICT m_curr; ///< current stack level: top of the stack. cached here for easier access.
state *C4_RESTRICT m_parent; ///< parent of the current stack level.
pfn_relocate_arena m_relocate_arena; ///< callback when the arena gets relocated
void * m_relocate_arena_data;
protected:
EventHandlerStack() : m_stack(), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
EventHandlerStack(Callbacks const& cb) : m_stack(cb), m_curr(), m_parent(), m_relocate_arena(), m_relocate_arena_data() {}
protected:
void _stack_start_parse(const char *filename, pfn_relocate_arena relocate_arena, void *relocate_arena_data)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_curr != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, relocate_arena_data != nullptr);
m_curr->start_parse(filename, m_curr->node_id);
m_relocate_arena = relocate_arena;
m_relocate_arena_data = relocate_arena_data;
}
void _stack_finish_parse()
{
}
protected:
void _stack_reset_root()
{
m_stack.clear();
m_stack.push({});
m_parent = nullptr;
m_curr = &m_stack.top();
}
void _stack_reset_non_root()
{
m_stack.clear();
m_stack.push({}); // parent
m_stack.push({}); // node
m_parent = &m_stack.top(1);
m_curr = &m_stack.top();
}
void _stack_push()
{
m_stack.push_top();
m_parent = &m_stack.top(1); // don't use m_curr. watch out for relocations inside the prev push
m_curr = &m_stack.top();
m_curr->reset_after_push();
}
void _stack_pop()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_stack.size() > 1);
m_parent->reset_before_pop(*m_curr);
m_stack.pop();
m_parent = m_stack.size() > 1 ? &m_stack.top(1) : nullptr;
m_curr = &m_stack.top();
#ifdef RYML_DBG
if(m_parent)
_c4dbgpf("popped! top is now node={} (parent={})", m_curr->node_id, m_parent->node_id);
else
_c4dbgpf("popped! top is now node={} @ ROOT", m_curr->node_id);
#endif
}
protected:
// undefined at the end
#define _has_any_(bits) (static_cast<HandlerImpl const* C4_RESTRICT>(this)->template _has_any__<bits>())
bool _stack_should_push_on_begin_doc() const
{
const bool is_root = (m_stack.size() == 1u);
return is_root && (_has_any_(DOC|VAL|MAP|SEQ) || m_curr->has_children);
}
bool _stack_should_pop_on_end_doc() const
{
const bool is_root = (m_stack.size() == 1u);
return !is_root && _has_any_(DOC);
}
protected:
void _stack_relocate_to_new_arena(csubstr prev, substr curr)
{
for(state &st : m_stack)
{
if(st.line_contents.rem.is_sub(prev))
st.line_contents.rem = _stack_relocate_to_new_arena(st.line_contents.rem, prev, curr);
if(st.line_contents.full.is_sub(prev))
st.line_contents.full = _stack_relocate_to_new_arena(st.line_contents.full, prev, curr);
if(st.line_contents.stripped.is_sub(prev))
st.line_contents.stripped = _stack_relocate_to_new_arena(st.line_contents.stripped, prev, curr);
}
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena != nullptr);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_relocate_arena_data != nullptr);
m_relocate_arena(m_relocate_arena_data, prev, curr);
}
substr _stack_relocate_to_new_arena(csubstr s, csubstr prev, substr curr)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, prev.is_super(s));
auto pos = s.str - prev.str;
substr out = {curr.str + pos, s.len};
_RYML_CB_ASSERT(m_stack.m_callbacks, curr.is_super(out));
return out;
}
public:
/** Check whether the current parse tokens are trailing on the
* previous doc, and raise an error if they are. This function is
* called by the parse engine (not the event handler) before a doc
* is started. */
void check_trailing_doc_token() const
{
const bool is_root = (m_stack.size() == 1u);
const bool isndoc = (m_curr->flags & NDOC) != 0;
const bool suspicious = _has_any_(MAP|SEQ|VAL);
_c4dbgpf("target={} isroot={} suspicious={} ndoc={}", m_curr->node_id, is_root, suspicious, isndoc);
if((is_root || _has_any_(DOC)) && suspicious && !isndoc)
_RYML_CB_ERR_(m_stack.m_callbacks, "parse error", m_curr->pos);
}
protected:
#undef _has_any_
};
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#endif /* _C4_YML_EVENT_HANDLER_STACK_HPP_ */
-768
View File
@@ -1,768 +0,0 @@
#ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
#define _C4_YML_EVENT_HANDLER_TREE_HPP_
#ifndef _C4_YML_TREE_HPP_
#include "c4/yml/tree.hpp"
#endif
#ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
#include "c4/yml/event_handler_stack.hpp"
#endif
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable code
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_event_handlers
* @{ */
/** @cond dev */
struct EventHandlerTreeState : public ParserState
{
NodeData *tr_data;
};
/** @endcond */
/** The event handler to create a ryml @ref Tree. See the
* documentation for @ref doc_event_handlers, which has important
* notes about the event model used by rapidyaml. */
struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
{
/** @name types
* @{ */
using state = EventHandlerTreeState;
/** @} */
public:
/** @cond dev */
Tree *C4_RESTRICT m_tree;
id_type m_id;
size_t m_num_directives;
bool m_yaml_directive;
#ifdef RYML_DBG
#define _enable_(bits) _enable__<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
#define _disable_(bits) _disable__<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
#else
#define _enable_(bits) _enable__<bits>()
#define _disable_(bits) _disable__<bits>()
#endif
#define _has_any_(bits) _has_any__<bits>()
/** @endcond */
public:
/** @name construction and resetting
* @{ */
EventHandlerTree() : EventHandlerStack(), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
EventHandlerTree(Callbacks const& cb) : EventHandlerStack(cb), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
EventHandlerTree(Tree *tree, id_type id) : EventHandlerStack(tree->callbacks()), m_tree(tree), m_id(id), m_num_directives(), m_yaml_directive()
{
reset(tree, id);
}
void reset(Tree *tree, id_type id)
{
if(C4_UNLIKELY(!tree))
_RYML_CB_ERR(m_stack.m_callbacks, "null tree");
if(C4_UNLIKELY(id >= tree->capacity()))
_RYML_CB_ERR(tree->callbacks(), "invalid node");
if(C4_UNLIKELY(!tree->is_root(id)))
if(C4_UNLIKELY(tree->is_map(tree->parent(id))))
if(C4_UNLIKELY(!tree->has_key(id)))
_RYML_CB_ERR(tree->callbacks(), "destination node belongs to a map and has no key");
m_tree = tree;
m_id = id;
if(m_tree->is_root(id))
{
_stack_reset_root();
_reset_parser_state(m_curr, id, m_tree->root_id());
}
else
{
_stack_reset_non_root();
_reset_parser_state(m_parent, id, m_tree->parent(id));
_reset_parser_state(m_curr, id, id);
}
m_num_directives = 0;
m_yaml_directive = false;
}
/** @} */
public:
/** @name parse events
* @{ */
void start_parse(const char* filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
}
void finish_parse()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree != nullptr);
if(m_num_directives && !m_tree->is_stream(m_tree->root_id()))
_RYML_CB_ERR_(m_stack.m_callbacks, "directives cannot be used without a document", {});
this->_stack_finish_parse();
/* This pointer is temporary. Remember that:
*
* - this handler object may be held by the user
* - it may be used with a temporary tree inside the parse function
* - when the parse function returns the temporary tree, its address
* will change
*
* As a result, the user could try to read the tree from m_tree, and
* end up reading the stale temporary object.
*
* So it is better to clear it here; then the user will get an obvious
* segfault if reading from m_tree. */
m_tree = nullptr;
}
void cancel_parse()
{
m_tree = nullptr;
}
/** @} */
public:
/** @name YAML stream events */
/** @{ */
C4_ALWAYS_INLINE void begin_stream() const noexcept { /*nothing to do*/ }
C4_ALWAYS_INLINE void end_stream() const noexcept { /*nothing to do*/ }
/** @} */
public:
/** @name YAML document events */
/** @{ */
/** implicit doc start (without ---) */
void begin_doc()
{
_c4dbgp("begin_doc");
if(_stack_should_push_on_begin_doc())
{
_c4dbgp("push!");
_set_root_as_stream();
_push();
_enable_(DOC);
}
}
/** implicit doc end (without ...) */
void end_doc()
{
_c4dbgp("end_doc");
if(_stack_should_pop_on_end_doc())
{
_remove_speculative();
_c4dbgp("pop!");
_pop();
}
}
/** explicit doc start, with --- */
void begin_doc_expl()
{
_c4dbgp("begin_doc_expl");
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id);
if(!m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
{
_c4dbgp("ensure stream");
_set_root_as_stream();
id_type first = m_tree->first_child(m_tree->root_id());
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u);
if(m_tree->has_children(first) || m_tree->is_val(first))
{
_c4dbgp("push!");
_push();
}
else
{
_c4dbgp("tweak");
_push();
_remove_speculative();
m_curr->node_id = m_tree->last_child(m_tree->root_id());
m_curr->tr_data = m_tree->_p(m_curr->node_id);
}
}
else
{
_c4dbgp("push!");
_push();
}
_enable_(DOC);
}
/** explicit doc end, with ... */
void end_doc_expl()
{
_c4dbgp("end_doc_expl");
_remove_speculative();
if(_stack_should_pop_on_end_doc())
{
_c4dbgp("pop!");
_pop();
}
m_yaml_directive = false;
}
/** @} */
public:
/** @name YAML map events */
/** @{ */
void begin_map_key_flow()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_map_key_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_map_val_flow()
{
_c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(MAP|FLOW_SL);
_save_loc();
_push();
}
void begin_map_val_block()
{
_c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(MAP|BLOCK);
_save_loc();
_push();
}
void end_map()
{
_pop();
_c4dbgpf("node[{}]: end_map_val", m_curr->node_id);
}
/** @} */
public:
/** @name YAML seq events */
/** @{ */
void begin_seq_key_flow()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_seq_key_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
void begin_seq_val_flow()
{
_c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(SEQ|FLOW_SL);
_save_loc();
_push();
}
void begin_seq_val_block()
{
_c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
_RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
_enable_(SEQ|BLOCK);
_save_loc();
_push();
}
void end_seq()
{
_pop();
_c4dbgpf("node[{}]: end_seq_val", m_curr->node_id);
}
/** @} */
public:
/** @name YAML structure events */
/** @{ */
void add_sibling()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id));
NodeData const* prev = m_tree->m_buf; // watchout against relocation of the tree nodes
_set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
if(prev != m_tree->m_buf)
_refresh_after_relocation();
_c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
}
/** set the previous val as the first key of a new map, with flow style.
*
* See the documentation for @ref doc_event_handlers, which has
* important notes about this event.
*/
void actually_val_is_first_key_of_new_map_flow()
{
if(C4_UNLIKELY(m_tree->is_container(m_curr->node_id)))
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id));
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id));
_RYML_CB_ASSERT(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id));
const NodeData tmp = _val2key_(*m_curr->tr_data);
_disable_(_VALMASK|VAL_STYLE);
m_curr->tr_data->m_val = {};
begin_map_val_flow();
m_curr->tr_data->m_type = tmp.m_type;
m_curr->tr_data->m_key = tmp.m_key;
}
/** like its flow counterpart, but this function can only be
* called after the end of a flow-val at root or doc level.
*
* See the documentation for @ref doc_event_handlers, which has
* important notes about this event.
*/
void actually_val_is_first_key_of_new_map_block()
{
_RYML_CB_ERR_(m_stack.m_callbacks, "ryml trees cannot handle containers as keys", m_curr->pos);
}
/** @} */
public:
/** @name YAML scalar events */
/** @{ */
C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
{
_c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
m_curr->tr_data->m_key.scalar = {};
_enable_(KEY|KEY_PLAIN|KEYNIL);
}
C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
{
_c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
m_curr->tr_data->m_val.scalar = {};
_enable_(VAL|VAL_PLAIN|VALNIL);
}
C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_PLAIN);
}
C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_PLAIN);
}
C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_DQUO);
}
C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_DQUO);
}
C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_SQUO);
}
C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_SQUO);
}
C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_LITERAL);
}
C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_LITERAL);
}
C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_key.scalar = scalar;
_enable_(KEY|KEY_FOLDED);
}
C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
{
_c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
m_curr->tr_data->m_val.scalar = scalar;
_enable_(VAL|VAL_FOLDED);
}
C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
{
_enable_(KEY_UNFILT);
}
C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
{
_enable_(VAL_UNFILT);
}
/** @} */
public:
/** @name YAML anchor/reference events */
/** @{ */
void set_key_anchor(csubstr anchor)
{
_c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(KEYREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(KEYANCH);
m_curr->tr_data->m_key.anchor = anchor;
}
void set_val_anchor(csubstr anchor)
{
_c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(VALREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(VALANCH);
m_curr->tr_data->m_val.anchor = anchor;
}
void set_key_ref(csubstr ref)
{
_c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(KEYANCH)))
_RYML_CB_ERR_(m_tree->callbacks(), "key cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
_enable_(KEY|KEYREF);
m_curr->tr_data->m_key.anchor = ref.sub(1);
m_curr->tr_data->m_key.scalar = ref;
}
void set_val_ref(csubstr ref)
{
_c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(VALANCH)))
_RYML_CB_ERR_(m_tree->callbacks(), "val cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), ref.begins_with('*'));
_enable_(VAL|VALREF);
m_curr->tr_data->m_val.anchor = ref.sub(1);
m_curr->tr_data->m_val.scalar = ref;
}
/** @} */
public:
/** @name YAML tag events */
/** @{ */
void set_key_tag(csubstr tag) noexcept
{
_c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
_enable_(KEYTAG);
m_curr->tr_data->m_key.tag = tag;
}
void set_val_tag(csubstr tag) noexcept
{
_c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
_enable_(VALTAG);
m_curr->tr_data->m_val.tag = tag;
}
/** @} */
public:
/** @name YAML directive events */
/** @{ */
C4_NO_INLINE void add_directive(csubstr directive)
{
_c4dbgpf("% directive! {}", directive);
_RYML_CB_ASSERT(m_tree->callbacks(), directive.begins_with('%'));
if(directive.begins_with("%TAG"))
{
if(C4_UNLIKELY(!m_tree->add_tag_directive(directive)))
_RYML_CB_ERR_(m_stack.m_callbacks, "failed to add directive", m_curr->pos);
}
else if(directive.begins_with("%YAML"))
{
_c4dbgpf("%YAML directive! ignoring...: {}", directive);
if(C4_UNLIKELY(m_yaml_directive))
_RYML_CB_ERR_(m_stack.m_callbacks, "multiple yaml directives", m_curr->pos);
m_yaml_directive = true;
}
else
{
_c4dbgpf("unknown directive! ignoring... {}", directive);
}
++m_num_directives;
}
/** @} */
public:
/** @name arena functions */
/** @{ */
substr alloc_arena(size_t len)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
csubstr prev = m_tree->arena();
substr out = m_tree->alloc_arena(len);
substr curr = m_tree->arena();
if(curr.str != prev.str)
_stack_relocate_to_new_arena(prev, curr);
return out;
}
substr alloc_arena(size_t len, substr *relocated)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
csubstr prev = m_tree->arena();
if(!prev.is_super(*relocated))
return alloc_arena(len);
substr out = alloc_arena(len);
substr curr = m_tree->arena();
if(curr.str != prev.str)
*relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
return out;
}
/** @} */
public:
/** @cond dev */
void _reset_parser_state(state* st, id_type parse_root, id_type node)
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_set_state_(st, node);
const NodeType type = m_tree->type(node);
#ifdef RYML_DBG
char flagbuf[80];
_c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
#endif
if(type == NOTYPE)
{
_c4dbgpf("node[{}] is notype", node);
if(m_tree->is_root(parse_root))
{
_c4dbgpf("node[{}] is root", node);
st->flags |= RUNK|RTOP;
}
else
{
_c4dbgpf("node[{}] is not root. setting USTY", node);
st->flags |= USTY;
}
}
else if(type.is_map())
{
_c4dbgpf("node[{}] is map", node);
st->flags |= RMAP|USTY;
}
else if(type.is_seq())
{
_c4dbgpf("node[{}] is map", node);
st->flags |= RSEQ|USTY;
}
else if(type.has_key())
{
_c4dbgpf("node[{}] has key. setting USTY", node);
st->flags |= USTY;
}
else
{
_RYML_CB_ERR(m_tree->callbacks(), "cannot append to node");
}
if(type.is_doc())
{
_c4dbgpf("node[{}] is doc", node);
st->flags |= RDOC;
}
#ifdef RYML_DBG
_c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
#endif
}
/** push a new parent, add a child to the new parent, and set the
* child as the current node */
void _push()
{
_stack_push();
NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
m_curr->tr_data = m_tree->_p(m_curr->node_id);
if(prev != m_tree->m_buf)
_refresh_after_relocation();
_c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
}
/** end the current scope */
void _pop()
{
_remove_speculative_with_parent();
_stack_pop();
}
public:
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept
{
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type | bits);
}
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept
{
m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type & (~bits));
}
template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool _has_any__() const noexcept
{
return (m_curr->tr_data->m_type.type & bits) != 0;
}
public:
C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
{
s->node_id = id;
s->tr_data = m_tree->_p(id);
}
void _refresh_after_relocation()
{
_c4dbgp("tree: refreshing stack data after tree data relocation");
for(auto &st : m_stack)
st.tr_data = m_tree->_p(st.node_id);
}
void _set_root_as_stream()
{
_c4dbgp("set root as stream");
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->root_id() == 0u);
_RYML_CB_ASSERT(m_tree->callbacks(), m_curr->node_id == 0u);
const bool hack = !m_tree->has_children(m_curr->node_id) && !m_tree->is_val(m_curr->node_id);
if(hack)
m_tree->_p(m_tree->root_id())->m_type.add(VAL);
m_tree->set_root_as_stream();
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()));
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())));
if(hack)
m_tree->_p(m_tree->first_child(m_tree->root_id()))->m_type.rem(VAL);
_set_state_(m_curr, m_tree->root_id());
}
static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
{
NodeData r = d;
r.m_key = d.m_val;
r.m_val = {};
r.m_type = d.m_type;
static_assert((_VALMASK >> 1u) == _KEYMASK, "required for this function to work");
static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
r.m_type.type = ((d.m_type.type & (_VALMASK|VAL_STYLE)) >> 1u);
r.m_type.type = (r.m_type.type & ~(_VALMASK|VAL_STYLE));
r.m_type.type = (r.m_type.type | KEY);
return r;
}
void _remove_speculative()
{
_c4dbgp("remove speculative node");
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
if(m_tree->has_parent(last_added))
if(m_tree->_p(last_added)->m_type == NOTYPE)
m_tree->remove(last_added);
}
void _remove_speculative_with_parent()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_parent(last_added));
if(m_tree->_p(last_added)->m_type == NOTYPE)
{
_c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
m_tree->remove(last_added);
}
}
C4_ALWAYS_INLINE void _save_loc()
{
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
}
#undef _enable_
#undef _disable_
#undef _has_any_
/** @endcond */
};
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
C4_SUPPRESS_WARNING_MSVC_POP
#endif /* _C4_YML_EVENT_HANDLER_TREE_HPP_ */
-18
View File
@@ -1,18 +0,0 @@
#ifndef C4_YML_EXPORT_HPP_
#define C4_YML_EXPORT_HPP_
#ifdef _WIN32
#ifdef RYML_SHARED
#ifdef RYML_EXPORTS
#define RYML_EXPORT __declspec(dllexport)
#else
#define RYML_EXPORT __declspec(dllimport)
#endif
#else
#define RYML_EXPORT
#endif
#else
#define RYML_EXPORT
#endif
#endif /* C4_YML_EXPORT_HPP_ */
-512
View File
@@ -1,512 +0,0 @@
#ifndef _C4_YML_FILTER_PROCESSOR_HPP_
#define _C4_YML_FILTER_PROCESSOR_HPP_
#include "c4/yml/common.hpp"
#ifdef RYML_DBG
#include "c4/charconv.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#endif
namespace c4 {
namespace yml {
/** @defgroup doc_filter_processors Scalar filter processors
*
* These are internal classes used by @ref ParseEngine to parse the
* scalars; normally there is no reason for a user to be manually
* using these classes.
*
* @ingroup doc_parse */
/** @{ */
//-----------------------------------------------------------------------------
/** Filters an input string into a different output string */
struct FilterProcessorSrcDst
{
csubstr src;
substr dst;
size_t rpos; ///< read position
size_t wpos; ///< write position
C4_ALWAYS_INLINE FilterProcessorSrcDst(csubstr src_, substr dst_) noexcept
: src(src_)
, dst(dst_)
, rpos(0)
, wpos(0)
{
RYML_ASSERT(!dst.overlaps(src));
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(dst.str, wpos <= dst.len ? wpos : dst.len); }
C4_ALWAYS_INLINE FilterResult result() const noexcept
{
FilterResult ret;
ret.str.str = wpos <= dst.len ? dst.str : nullptr;
ret.str.len = wpos;
return ret;
}
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE bool skipped_chars() const noexcept { return wpos != rpos; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
C4_ALWAYS_INLINE void set_at(size_t pos, char c) noexcept // NOLINT(readability-make-member-function-const)
{
RYML_ASSERT(pos < wpos);
dst.str[pos] = c;
}
C4_ALWAYS_INLINE void set(char c) noexcept
{
if(wpos < dst.len)
dst.str[wpos] = c;
++wpos;
}
C4_ALWAYS_INLINE void set(char c, size_t num) noexcept
{
RYML_ASSERT(num > 0);
if(wpos + num <= dst.len)
memset(dst.str + wpos, c, num);
wpos += num;
}
C4_ALWAYS_INLINE void copy() noexcept
{
RYML_ASSERT(rpos < src.len);
if(wpos < dst.len)
dst.str[wpos] = src.str[rpos];
++wpos;
++rpos;
}
C4_ALWAYS_INLINE void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
if(wpos + num <= dst.len)
memcpy(dst.str + wpos, src.str + rpos, num);
wpos += num;
rpos += num;
}
C4_ALWAYS_INLINE void translate_esc(char c) noexcept
{
if(wpos < dst.len)
dst.str[wpos] = c;
++wpos;
rpos += 2;
}
C4_ALWAYS_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(rpos+nr <= src.len);
if(wpos+nw <= dst.len)
memcpy(dst.str + wpos, s, nw);
wpos += nw;
rpos += 1 + nr;
}
C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
translate_esc_bulk(s, nw, nr);
}
};
//-----------------------------------------------------------------------------
// filter in place
// debugging scaffold
/** @cond dev */
#if defined(RYML_DBG) && 0
#define _c4dbgip(...) _c4dbgpf(__VA_ARGS__)
#else
#define _c4dbgip(...)
#endif
/** @endcond */
/** Filters in place. While the result may be larger than the source,
* any extending happens only at the end of the string. Consequently,
* it's impossible for characters to be left unfiltered.
*
* @see FilterProcessorInplaceMidExtending */
struct FilterProcessorInplaceEndExtending
{
substr src; ///< the subject string
size_t wcap; ///< write capacity - the capacity of the subject string's buffer
size_t rpos; ///< read position
size_t wpos; ///< write position
C4_ALWAYS_INLINE FilterProcessorInplaceEndExtending(substr src_, size_t wcap_) noexcept
: src(src_)
, wcap(wcap_)
, rpos(0)
, wpos(0)
{
RYML_ASSERT(wcap >= src.len);
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE FilterResult result() const noexcept
{
_c4dbgip("inplace: wpos={} wcap={} small={}", wpos, wcap, wpos > rpos);
FilterResult ret;
ret.str.str = (wpos <= wcap) ? src.str : nullptr;
ret.str.len = wpos;
return ret;
}
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
void set_at(size_t pos, char c) noexcept
{
RYML_ASSERT(pos < wpos);
const size_t save = wpos;
wpos = pos;
set(c);
wpos = save;
}
void set(char c) noexcept
{
if(wpos < wcap) // respect write-capacity
src.str[wpos] = c;
++wpos;
}
void set(char c, size_t num) noexcept
{
RYML_ASSERT(num);
if(wpos + num <= wcap) // respect write-capacity
memset(src.str + wpos, c, num);
wpos += num;
}
void copy() noexcept
{
RYML_ASSERT(wpos <= rpos);
RYML_ASSERT(rpos < src.len);
if(wpos < wcap) // respect write-capacity
src.str[wpos] = src.str[rpos];
++rpos;
++wpos;
}
void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
RYML_ASSERT(wpos <= rpos);
if(wpos + num <= wcap) // respect write-capacity
{
if(wpos + num <= rpos) // there is no overlap
memcpy(src.str + wpos, src.str + rpos, num);
else // there is overlap
memmove(src.str + wpos, src.str + rpos, num);
}
rpos += num;
wpos += num;
}
void translate_esc(char c) noexcept
{
RYML_ASSERT(rpos + 2 <= src.len);
RYML_ASSERT(wpos <= rpos);
if(wpos < wcap) // respect write-capacity
src.str[wpos] = c;
rpos += 2; // add 1u to account for the escape character
++wpos;
}
void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(nw <= nr + 1u);
RYML_ASSERT(rpos+nr <= src.len);
RYML_ASSERT(wpos <= rpos);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
RYML_ASSERT(wpos_next <= rpos_next);
if(wpos_next <= wcap)
memcpy(src.str + wpos, s, nw);
rpos = rpos_next;
wpos = wpos_next;
}
C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
translate_esc_bulk(s, nw, nr);
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Filters in place. The result may be larger than the source, and
* extending may happen anywhere. As a result some characters may be
* left unfiltered when there is no slack in the buffer and the
* write-position would overlap the read-position. Consequently, it's
* possible for characters to be left unfiltered. In YAML, this
* happens only with double-quoted strings, and only with a small
* number of escape sequences such as `\L` which is substituted by three
* bytes. These escape sequences cause a call to translate_esc_extending()
* which is the only entry point to this unfiltered situation.
*
* @see FilterProcessorInplaceMidExtending */
struct FilterProcessorInplaceMidExtending
{
substr src; ///< the subject string
size_t wcap; ///< write capacity - the capacity of the subject string's buffer
size_t rpos; ///< read position
size_t wpos; ///< write position
size_t maxcap; ///< the max capacity needed for filtering the string. This may be larger than the final string size.
bool unfiltered_chars; ///< number of characters that were not added to wpos from lack of capacity
C4_ALWAYS_INLINE FilterProcessorInplaceMidExtending(substr src_, size_t wcap_) noexcept
: src(src_)
, wcap(wcap_)
, rpos(0)
, wpos(0)
, maxcap(src.len)
, unfiltered_chars(false)
{
RYML_ASSERT(wcap >= src.len);
}
C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { RYML_ASSERT(maxpos <= src.len); return rpos < maxpos; }
C4_ALWAYS_INLINE FilterResultExtending result() const noexcept
{
_c4dbgip("inplace: wpos={} wcap={} unfiltered={} maxcap={}", this->wpos, this->wcap, this->unfiltered_chars, this->maxcap);
FilterResultExtending ret;
ret.str.str = (wpos <= wcap && !unfiltered_chars) ? src.str : nullptr;
ret.str.len = wpos;
ret.reqlen = maxcap;
return ret;
}
C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
C4_ALWAYS_INLINE char curr() const noexcept { RYML_ASSERT(rpos < src.len); return src[rpos]; }
C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
void set_at(size_t pos, char c) noexcept
{
RYML_ASSERT(pos < wpos);
const size_t save = wpos;
wpos = pos;
set(c);
wpos = save;
}
void set(char c) noexcept
{
if(wpos < wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
src.str[wpos] = c;
}
else
{
_c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void set(char c, size_t num) noexcept
{
RYML_ASSERT(num);
if(wpos + num <= wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
memset(src.str + wpos, c, num);
}
else
{
_c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+num > maxcap ? wpos+num : maxcap));
unfiltered_chars = true;
}
wpos += num;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void copy() noexcept
{
RYML_ASSERT(rpos < src.len);
if(wpos < wcap) // respect write-capacity
{
if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
src.str[wpos] = src.str[rpos];
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
++rpos;
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void copy(size_t num) noexcept
{
RYML_ASSERT(num);
RYML_ASSERT(rpos+num <= src.len);
if(wpos + num <= wcap) // respect write-capacity
{
if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
{
if(wpos + num <= rpos) // there is no overlap
memcpy(src.str + wpos, src.str + rpos, num);
else // there is overlap
memmove(src.str + wpos, src.str + rpos, num);
}
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
unfiltered_chars = true;
}
rpos += num;
wpos += num;
maxcap = wpos > maxcap ? wpos : maxcap;
}
void translate_esc(char c) noexcept
{
RYML_ASSERT(rpos + 2 <= src.len);
if(wpos < wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars)
src.str[wpos] = c;
}
else
{
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
unfiltered_chars = true;
}
rpos += 2;
++wpos;
maxcap = wpos > maxcap ? wpos : maxcap;
}
C4_NO_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(nr+1u >= nw);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
if(wpos_next <= wcap) // respect write-capacity
{
if((wpos <= rpos) && !unfiltered_chars) // write only if wpos is behind rpos
memcpy(src.str + wpos, s, nw);
}
else
{
_c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
unfiltered_chars = true;
}
rpos = rpos_next;
wpos = wpos_next;
maxcap = wpos > maxcap ? wpos : maxcap;
}
C4_NO_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
{
RYML_ASSERT(nw > 0);
RYML_ASSERT(nr > 0);
RYML_ASSERT(rpos+nr <= src.len);
const size_t wpos_next = wpos + nw;
const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
if(wpos_next <= rpos_next) // read and write do not overlap. just do a vanilla copy.
{
if((wpos_next <= wcap) && !unfiltered_chars)
memcpy(src.str + wpos, s, nw);
rpos = rpos_next;
wpos = wpos_next;
maxcap = wpos > maxcap ? wpos : maxcap;
}
else // there is overlap. move the (to-be-read) string to the right.
{
const size_t excess = wpos_next - rpos_next;
RYML_ASSERT(wpos_next > rpos_next);
if(src.len + excess <= wcap) // ensure we do not go past the end
{
RYML_ASSERT(rpos+nr+excess <= src.len);
if(wpos_next <= wcap)
{
if(!unfiltered_chars)
{
memmove(src.str + wpos_next, src.str + rpos_next, src.len - rpos_next);
memcpy(src.str + wpos, s, nw);
}
rpos = wpos_next; // wpos, not rpos
}
else
{
rpos = rpos_next;
//const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true);
unfiltered_chars = true;
}
wpos = wpos_next;
// extend the string up to capacity
src.len += excess;
maxcap = wpos > maxcap ? wpos : maxcap;
}
else
{
//const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
RYML_ASSERT(rpos_next <= src.len);
const size_t required_size = wpos_next + (src.len - rpos_next);
_c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, required_size > maxcap ? required_size : maxcap);
RYML_ASSERT(required_size > wcap);
unfiltered_chars = true;
maxcap = required_size > maxcap ? required_size : maxcap;
wpos = wpos_next;
rpos = rpos_next;
}
}
}
};
#undef _c4dbgip
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_FILTER_PROCESSOR_HPP_ */
-24
View File
@@ -1,24 +0,0 @@
#ifndef _C4_YML_FWD_HPP_
#define _C4_YML_FWD_HPP_
/** @file fwd.hpp forward declarations */
namespace c4 {
namespace yml {
struct NodeScalar;
struct NodeInit;
struct NodeData;
struct NodeType;
class NodeRef;
class ConstNodeRef;
class Tree;
struct ReferenceResolver;
template<class EventHandler> class ParseEngine;
struct EventHandlerTree;
using Parser = ParseEngine<EventHandlerTree>;
} // namespace c4
} // namespace yml
#endif /* _C4_YML_FWD_HPP_ */
File diff suppressed because it is too large Load Diff
-282
View File
@@ -1,282 +0,0 @@
#ifndef C4_YML_NODE_TYPE_HPP_
#define C4_YML_NODE_TYPE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
C4_SUPPRESS_WARNING_MSVC_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
#if __GNUC__ >= 6
C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
#endif
namespace c4 {
namespace yml {
/** @addtogroup doc_node_type
*
* @{
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** the integral type necessary to cover all the bits for NodeType_e */
using type_bits = uint32_t;
/** a bit mask for marking node types and styles */
typedef enum : type_bits {
#define __(v) (type_bits(1) << v) // a convenience define, undefined below // NOLINT
NOTYPE = 0, ///< no node type or style is set
KEY = __(0), ///< is member of a map
VAL = __(1), ///< a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or SEQ
MAP = __(2), ///< a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
SEQ = __(3), ///< a seq: a parent of VAL/SEQ/MAP nodes
DOC = __(4), ///< a document
STREAM = __(5)|SEQ, ///< a stream: a seq of docs
KEYREF = __(6), ///< a *reference: the key references an &anchor
VALREF = __(7), ///< a *reference: the val references an &anchor
KEYANCH = __(8), ///< the key has an &anchor
VALANCH = __(9), ///< the val has an &anchor
KEYTAG = __(10), ///< the key has a tag
VALTAG = __(11), ///< the val has a tag
KEYNIL = __(12), ///< the key is null (eg `{ : b}` results in a null key)
VALNIL = __(13), ///< the val is null (eg `{a : }` results in a null val)
_TYMASK = __(14)-1, ///< all the bits up to here
//
// unfiltered flags:
//
KEY_UNFILT = __(14), ///< the key scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
VAL_UNFILT = __(15), ///< the val scalar was left unfiltered; the parser was set not to filter. @see ParserOptions
//
// style flags:
//
FLOW_SL = __(16), ///< mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,key2: val2}')
FLOW_ML = __(17), ///< (NOT IMPLEMENTED, work in progress) mark container with multi-line flow style (seqs as '[\n val1,\n val2\n], maps as '{\n key: val,\n key2: val2\n}')
BLOCK = __(18), ///< mark container with block style (seqs as '- val\n', maps as 'key: val')
KEY_LITERAL = __(19), ///< mark key scalar as multiline, block literal |
VAL_LITERAL = __(20), ///< mark val scalar as multiline, block literal |
KEY_FOLDED = __(21), ///< mark key scalar as multiline, block folded >
VAL_FOLDED = __(22), ///< mark val scalar as multiline, block folded >
KEY_SQUO = __(23), ///< mark key scalar as single quoted '
VAL_SQUO = __(24), ///< mark val scalar as single quoted '
KEY_DQUO = __(25), ///< mark key scalar as double quoted "
VAL_DQUO = __(26), ///< mark val scalar as double quoted "
KEY_PLAIN = __(27), ///< mark key scalar as plain scalar (unquoted, even when multiline)
VAL_PLAIN = __(28), ///< mark val scalar as plain scalar (unquoted, even when multiline)
//
// type combination masks:
//
KEYVAL = KEY|VAL,
KEYSEQ = KEY|SEQ,
KEYMAP = KEY|MAP,
DOCMAP = DOC|MAP,
DOCSEQ = DOC|SEQ,
DOCVAL = DOC|VAL,
//
// style combination masks:
//
SCALAR_LITERAL = KEY_LITERAL|VAL_LITERAL,
SCALAR_FOLDED = KEY_FOLDED|VAL_FOLDED,
SCALAR_SQUO = KEY_SQUO|VAL_SQUO,
SCALAR_DQUO = KEY_DQUO|VAL_DQUO,
SCALAR_PLAIN = KEY_PLAIN|VAL_PLAIN,
KEYQUO = KEY_SQUO|KEY_DQUO|KEY_FOLDED|KEY_LITERAL, ///< key style is one of ', ", > or |
VALQUO = VAL_SQUO|VAL_DQUO|VAL_FOLDED|VAL_LITERAL, ///< val style is one of ', ", > or |
KEY_STYLE = KEY_LITERAL|KEY_FOLDED|KEY_SQUO|KEY_DQUO|KEY_PLAIN, ///< mask of all the scalar styles for key (not container styles!)
VAL_STYLE = VAL_LITERAL|VAL_FOLDED|VAL_SQUO|VAL_DQUO|VAL_PLAIN, ///< mask of all the scalar styles for val (not container styles!)
SCALAR_STYLE = KEY_STYLE|VAL_STYLE,
CONTAINER_STYLE_FLOW = FLOW_SL|FLOW_ML,
CONTAINER_STYLE_BLOCK = BLOCK,
CONTAINER_STYLE = FLOW_SL|FLOW_ML|BLOCK,
STYLE = SCALAR_STYLE | CONTAINER_STYLE,
//
// mixed masks
_KEYMASK = KEY | KEYQUO | KEYANCH | KEYREF | KEYTAG,
_VALMASK = VAL | VALQUO | VALANCH | VALREF | VALTAG,
#undef __
} NodeType_e;
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator| (NodeType_e lhs, NodeType_e rhs) noexcept { return (NodeType_e)(((type_bits)lhs) | ((type_bits)rhs)); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator& (NodeType_e lhs, NodeType_e rhs) noexcept { return (NodeType_e)(((type_bits)lhs) & ((type_bits)rhs)); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator>> (NodeType_e bits, uint32_t n) noexcept { return (NodeType_e)(((type_bits)bits) >> n); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator<< (NodeType_e bits, uint32_t n) noexcept { return (NodeType_e)(((type_bits)bits) << n); }
constexpr C4_ALWAYS_INLINE C4_CONST NodeType_e operator~ (NodeType_e bits) noexcept { return (NodeType_e)(~(type_bits)bits); }
C4_ALWAYS_INLINE NodeType_e& operator&= (NodeType_e &subject, NodeType_e bits) noexcept { subject = (NodeType_e)((type_bits)subject & (type_bits)bits); return subject; }
C4_ALWAYS_INLINE NodeType_e& operator|= (NodeType_e &subject, NodeType_e bits) noexcept { subject = (NodeType_e)((type_bits)subject | (type_bits)bits); return subject; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** wraps a NodeType_e element with some syntactic sugar and predicates */
struct RYML_EXPORT NodeType
{
public:
NodeType_e type;
public:
C4_ALWAYS_INLINE NodeType() noexcept : type(NOTYPE) {}
C4_ALWAYS_INLINE NodeType(NodeType_e t) noexcept : type(t) {}
C4_ALWAYS_INLINE NodeType(type_bits t) noexcept : type((NodeType_e)t) {}
C4_ALWAYS_INLINE bool has_any(NodeType_e t) const noexcept { return (type & t) != 0u; }
C4_ALWAYS_INLINE bool has_all(NodeType_e t) const noexcept { return (type & t) == t; }
C4_ALWAYS_INLINE bool has_none(NodeType_e t) const noexcept { return (type & t) == 0; }
C4_ALWAYS_INLINE void set(NodeType_e t) noexcept { type = t; }
C4_ALWAYS_INLINE void add(NodeType_e t) noexcept { type = (type|t); }
C4_ALWAYS_INLINE void rem(NodeType_e t) noexcept { type = (type & ~t); }
C4_ALWAYS_INLINE void addrem(NodeType_e bits_to_add, NodeType_e bits_to_remove) noexcept { type |= bits_to_add; type &= ~bits_to_remove; }
C4_ALWAYS_INLINE void clear() noexcept { type = NOTYPE; }
public:
C4_ALWAYS_INLINE operator NodeType_e & C4_RESTRICT () noexcept { return type; }
C4_ALWAYS_INLINE operator NodeType_e const& C4_RESTRICT () const noexcept { return type; }
public:
/** @name node type queries
* @{ */
/** return a preset string based on the node type */
C4_ALWAYS_INLINE const char *type_str() const noexcept { return type_str(type); }
/** return a preset string based on the node type */
static const char* type_str(NodeType_e t) noexcept;
/** fill a string with the node type flags. If the string is small, returns {null, len} */
C4_ALWAYS_INLINE csubstr type_str(substr buf) const noexcept { return type_str(buf, type); }
/** fill a string with the node type flags. If the string is small, returns {null, len} */
static csubstr type_str(substr buf, NodeType_e t) noexcept;
public:
/** @name node type queries
* @{ */
C4_ALWAYS_INLINE bool is_notype() const noexcept { return type == NOTYPE; }
C4_ALWAYS_INLINE bool is_stream() const noexcept { return ((type & STREAM) == STREAM) != 0; }
C4_ALWAYS_INLINE bool is_doc() const noexcept { return (type & DOC) != 0; }
C4_ALWAYS_INLINE bool is_container() const noexcept { return (type & (MAP|SEQ|STREAM)) != 0; }
C4_ALWAYS_INLINE bool is_map() const noexcept { return (type & MAP) != 0; }
C4_ALWAYS_INLINE bool is_seq() const noexcept { return (type & SEQ) != 0; }
C4_ALWAYS_INLINE bool has_key() const noexcept { return (type & KEY) != 0; }
C4_ALWAYS_INLINE bool has_val() const noexcept { return (type & VAL) != 0; }
C4_ALWAYS_INLINE bool is_val() const noexcept { return (type & KEYVAL) == VAL; }
C4_ALWAYS_INLINE bool is_keyval() const noexcept { return (type & KEYVAL) == KEYVAL; }
C4_ALWAYS_INLINE bool key_is_null() const noexcept { return (type & KEYNIL) != 0; }
C4_ALWAYS_INLINE bool val_is_null() const noexcept { return (type & VALNIL) != 0; }
C4_ALWAYS_INLINE bool has_key_tag() const noexcept { return (type & KEYTAG) != 0; }
C4_ALWAYS_INLINE bool has_val_tag() const noexcept { return (type & VALTAG) != 0; }
C4_ALWAYS_INLINE bool has_key_anchor() const noexcept { return (type & KEYANCH) != 0; }
C4_ALWAYS_INLINE bool has_val_anchor() const noexcept { return (type & VALANCH) != 0; }
C4_ALWAYS_INLINE bool has_anchor() const noexcept { return (type & (KEYANCH|VALANCH)) != 0; }
C4_ALWAYS_INLINE bool is_key_ref() const noexcept { return (type & KEYREF) != 0; }
C4_ALWAYS_INLINE bool is_val_ref() const noexcept { return (type & VALREF) != 0; }
C4_ALWAYS_INLINE bool is_ref() const noexcept { return (type & (KEYREF|VALREF)) != 0; }
C4_ALWAYS_INLINE bool is_key_unfiltered() const noexcept { return (type & (KEY_UNFILT)) != 0; }
C4_ALWAYS_INLINE bool is_val_unfiltered() const noexcept { return (type & (VAL_UNFILT)) != 0; }
RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor() const noexcept { return has_key_anchor(); }
RYML_DEPRECATED("use has_val_anchor()") bool is_val_anchor() const noexcept { return has_val_anchor(); }
RYML_DEPRECATED("use has_anchor()") bool is_anchor() const noexcept { return has_anchor(); }
RYML_DEPRECATED("use has_anchor() || is_ref()") bool is_anchor_or_ref() const noexcept { return has_anchor() || is_ref(); }
/** @} */
public:
/** @name style functions
* @{ */
C4_ALWAYS_INLINE bool is_container_styled() const noexcept { return (type & (CONTAINER_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_block() const noexcept { return (type & (BLOCK)) != 0; }
C4_ALWAYS_INLINE bool is_flow_sl() const noexcept { return (type & (FLOW_SL)) != 0; }
C4_ALWAYS_INLINE bool is_flow_ml() const noexcept { return (type & (FLOW_ML)) != 0; }
C4_ALWAYS_INLINE bool is_flow() const noexcept { return (type & (FLOW_ML|FLOW_SL)) != 0; }
C4_ALWAYS_INLINE bool is_key_styled() const noexcept { return (type & (KEY_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_val_styled() const noexcept { return (type & (VAL_STYLE)) != 0; }
C4_ALWAYS_INLINE bool is_key_literal() const noexcept { return (type & (KEY_LITERAL)) != 0; }
C4_ALWAYS_INLINE bool is_val_literal() const noexcept { return (type & (VAL_LITERAL)) != 0; }
C4_ALWAYS_INLINE bool is_key_folded() const noexcept { return (type & (KEY_FOLDED)) != 0; }
C4_ALWAYS_INLINE bool is_val_folded() const noexcept { return (type & (VAL_FOLDED)) != 0; }
C4_ALWAYS_INLINE bool is_key_squo() const noexcept { return (type & (KEY_SQUO)) != 0; }
C4_ALWAYS_INLINE bool is_val_squo() const noexcept { return (type & (VAL_SQUO)) != 0; }
C4_ALWAYS_INLINE bool is_key_dquo() const noexcept { return (type & (KEY_DQUO)) != 0; }
C4_ALWAYS_INLINE bool is_val_dquo() const noexcept { return (type & (VAL_DQUO)) != 0; }
C4_ALWAYS_INLINE bool is_key_plain() const noexcept { return (type & (KEY_PLAIN)) != 0; }
C4_ALWAYS_INLINE bool is_val_plain() const noexcept { return (type & (VAL_PLAIN)) != 0; }
C4_ALWAYS_INLINE bool is_key_quoted() const noexcept { return (type & KEYQUO) != 0; }
C4_ALWAYS_INLINE bool is_val_quoted() const noexcept { return (type & VALQUO) != 0; }
C4_ALWAYS_INLINE bool is_quoted() const noexcept { return (type & (KEYQUO|VALQUO)) != 0; }
C4_ALWAYS_INLINE NodeType key_style() const noexcept { return (type & (KEY_STYLE)); }
C4_ALWAYS_INLINE NodeType val_style() const noexcept { return (type & (VAL_STYLE)); }
C4_ALWAYS_INLINE void set_container_style(NodeType_e style) noexcept { type = ((style & CONTAINER_STYLE) | (type & ~CONTAINER_STYLE)); }
C4_ALWAYS_INLINE void set_key_style(NodeType_e style) noexcept { type = ((style & KEY_STYLE) | (type & ~KEY_STYLE)); }
C4_ALWAYS_INLINE void set_val_style(NodeType_e style) noexcept { type = ((style & VAL_STYLE) | (type & ~VAL_STYLE)); }
C4_ALWAYS_INLINE void clear_style() noexcept { type &= ~STYLE; }
/** @} */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** @name scalar style helpers
* @{ */
/** choose a YAML emitting style based on the scalar's contents */
RYML_EXPORT NodeType_e scalar_style_choose(csubstr scalar) noexcept;
/** choose a json style based on the scalar's contents */
RYML_EXPORT NodeType_e scalar_style_json_choose(csubstr scalar) noexcept;
/** query whether a scalar can be encoded using single quotes.
* It may not be possible, notably when there is leading
* whitespace after a newline. */
RYML_EXPORT bool scalar_style_query_squo(csubstr s) noexcept;
/** query whether a scalar can be encoded using plain style (no
* quotes, not a literal/folded block scalar). */
RYML_EXPORT bool scalar_style_query_plain(csubstr s) noexcept;
/** YAML-sense query of nullity. returns true if the scalar points
* to `nullptr` or is otherwise equal to one of the strings
* `"~"`,`"null"`,`"Null"`,`"NULL"` */
RYML_EXPORT inline C4_NO_INLINE bool scalar_is_null(csubstr s) noexcept
{
return s.str == nullptr ||
s == "~" ||
s == "null" ||
s == "Null" ||
s == "NULL";
}
/** @} */
/** @} */
} // namespace yml
} // namespace c4
C4_SUPPRESS_WARNING_MSVC_POP
C4_SUPPRESS_WARNING_GCC_CLANG_POP
#endif /* C4_YML_NODE_TYPE_HPP_ */
-324
View File
@@ -1,324 +0,0 @@
#ifndef _C4_YML_PARSE_HPP_
#define _C4_YML_PARSE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
namespace c4 {
namespace yml {
class Tree;
class NodeRef;
template<class EventHandler> class ParseEngine;
struct EventHandlerTree;
RYML_EXPORT id_type estimate_tree_capacity(csubstr src); // NOLINT
/** @addtogroup doc_parse
* @{ */
/** This is the main ryml parser, where the parser events are handled
* to create a ryml tree.
*
* @warning This class cannot parse YAML where there are container
* keys. This is not a limitation of the @ref ParseEngine, but of the
* @ref EventHandlerTree, which is present because the @ref Tree does
* not accept containers as keys. However, the @ref ParseEngine *can*
* parse container keys; consult its documentation for more details.
*
* @see ParserOptions
* @see ParseEngine
* @see EventHandlerTree
* */
using Parser = RYML_EXPORT ParseEngine<EventHandlerTree>;
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_place__with_existing_parser Parse in place with existing parser
*
* @brief parse a mutable YAML source buffer (re)using an existing
* parser. Scalars requiring filtering are mutated in place (except in
* the rare cases where the filtered scalar is longer than the
* original scalar, or where filtering was disabled before the
* call). These overloads accept an existing parser object, and
* provide the opportunity to use special parser options.
*
* @see ParserOptions
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id); /**< (1) parse YAML into an existing tree node.
*
* The filename will be used in any error messages
* arising during the parse. The callbacks in the
* tree are kept, and used to allocate
* the tree members, if any allocation is required. */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, Tree *t, id_type node_id); /**< (2) like (1) but no filename will be reported */
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t ); /**< (3) parse YAML into the root node of an existing tree.
*
* The filename will be used in any error messages
* arising during the parse. The callbacks in the
* tree are kept, and used to allocate
* the tree members, if any allocation is required. */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, Tree *t ); /**< (4) like (3) but no filename will be reported */
RYML_EXPORT void parse_in_place(Parser *parser, csubstr filename, substr yaml, NodeRef node ); /**< (5) like (1) but the node is given as a NodeRef */
RYML_EXPORT void parse_in_place(Parser *parser, substr yaml, NodeRef node ); /**< (6) like (5) but no filename will be reported */
RYML_EXPORT Tree parse_in_place(Parser *parser, csubstr filename, substr yaml ); /**< (7) create a new tree, and parse YAML into its root node.
*
* The filename will be used in any error messages
* arising during the parse. The tree is created with
* the callbacks currently in the parser.
*/
RYML_EXPORT Tree parse_in_place(Parser *parser, substr yaml ); /**< (8) like (7) but no filename will be reported */
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_place(Parser *parser, csubstr filename, substr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_place(Parser *parser, substr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_place(Parser *parser, csubstr filename, substr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_place(Parser *parser, substr json ); ///< (8) like (7) but no filename will be reported
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_place___with_temporary_parser Parse in place with temporary parser
*
* @brief parse a mutable YAML source buffer. Scalars requiring
* filtering are mutated in place (except in the rare cases where the
* filtered scalar is longer than the original scalar).
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to enable the user to easily parse
* YAML without the need to explicitly instantiate a parser and event
* handler. Note that some properties (notably node locations in the
* original source code) are only available through the parser
* class. If you need access to any of these properties, use
* the appropriate overload from @ref doc_parse_in_place__with_existing_parser
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_place( substr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_place( substr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_place(csubstr filename, substr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_place( substr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_place(csubstr filename, substr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_place( substr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_place( substr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_place( substr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_place(csubstr filename, substr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_place( substr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_place(csubstr filename, substr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_place( substr json ); ///< (8) like (7) but no filename will be reported
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_arena__with_existing_parser Parse in arena with existing parser
*
* @brief parse a read-only (immutable) YAML source buffer. This is
* achieved by first copying the contents of the buffer to the tree's
* arena, and then calling @ref parse_in_arena() . All the resulting
* scalars will be filtered in the arena. These overloads accept an
* existing parser object, and provide the opportunity to use special
* parser options.
*
* @see ParserOptions
*
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily parse YAML without the need
* to instantiate a separate parser. Note that some properties
* (notably node locations in the original source code) are only
* available through the parser class. If you need access to any of
* these properties, use the appropriate overload from @ref
* doc_parse_in_arena__with_existing_parser
*
* @warning overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
* will cause a linker error. This is to prevent an accidental copy of
* the source buffer to the tree's arena, because substr (which is
* mutable) is implicitly convertible to csubstr (which is
* immutable). If you really intend to parse a mutable buffer in the
* tree's arena, convert it first to immutable by assigning the substr
* to a csubstr prior to calling parse_in_arena(). This is not needed
* for parse_in_place() because csubstr is not implicitly convertible
* to substr. To be clear:
* ```c++
* substr mutable_buffer = ...;
* parser.parse_in_arena(mutable_buffer); // linker error
*
* csubstr immutable_buffer = ...;
* parser.parse_in_arena(immutable_buffer); // ok
* ```
*
* @{
*/
#define RYML_DONT_PARSE_SUBSTR_IN_ARENA "" \
"Do not pass a (mutable) substr to parse_in_arena(); " \
"if you have a substr, it should be parsed in place. " \
"Consider using parse_in_place() instead, or convert " \
"the buffer to csubstr prior to calling. This function " \
" is deliberately left undefined, so that calling it " \
"will cause a linker error."
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_arena(Parser *parser, csubstr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_arena(Parser *parser, csubstr filename, csubstr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_arena(Parser *parser, csubstr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_arena(Parser *parser, csubstr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_arena(Parser *parser, csubstr filename, csubstr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_arena(Parser *parser, csubstr json ); ///< (8) like (7) but no filename will be reported
/* READ THE DEPRECATION NOTE!
*
* All of the functions below are intentionally left undefined, to
* prevent them being used.
*
*/
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(Parser *parser, csubstr filename, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(Parser *parser, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(Parser *parser, csubstr filename, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(Parser *parser, csubstr filename, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(Parser *parser, substr json );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(Parser *parser, csubstr filename, substr json );
/** @endcond */
/** @} */
//-----------------------------------------------------------------------------
/** @defgroup doc_parse_in_arena__with_temporary_parser Parse in arena with temporary parser
*
* @brief parse a read-only (immutable) YAML source buffer. This is
* achieved by first copying the contents of the buffer to the tree's
* arena, and then calling @ref parse_in_arena() .
*
* @note These freestanding functions use a temporary parser object,
* and are convenience functions to easily one-off parse YAML without
* the need to instantiate a separate parser. Note that some
* properties (notably node locations in the original source code) are
* only available through the parser class. If you need access to any
* of these properties, use the appropriate overload from @ref
* doc_parse_in_arena__with_existing_parser
*
* @warning overloads receiving a substr YAML buffer are intentionally
* left undefined, such that calling parse_in_arena() with a substr
* will cause a linker error. This is to prevent an accidental copy of
* the source buffer to the tree's arena, because substr (which is
* mutable) is implicitly convertible to csubstr (which is
* immutable). If you really intend to parse a mutable buffer in the
* tree's arena, convert it first to immutable by assigning the substr
* to a csubstr prior to calling parse_in_arena(). This is not needed
* for parse_in_place() because csubstr is not implicitly convertible
* to substr. To be clear:
* ```c++
* substr mutable_buffer = ...;
* parser.parse_in_arena(mutable_buffer); // linker error
*
* csubstr immutable_buffer = ...;
* parser.parse_in_arena(immutable_buffer); // ok
* ```
*
* @{
*/
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, id_type node_id); ///< (1) parse YAML into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_in_arena( csubstr yaml, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ); ///< (3) parse YAML into an existing tree, into its root node.
RYML_EXPORT void parse_in_arena( csubstr yaml, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_in_arena( csubstr yaml, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_in_arena(csubstr filename, csubstr yaml ); ///< (7) create a new tree, and parse YAML into its root node.
RYML_EXPORT Tree parse_in_arena( csubstr yaml ); ///< (8) like (7) but no filename will be reported
// this is vertically aligned to highlight the parameter differences.
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, Tree *t, id_type node_id); ///< (1) parse JSON into an existing tree node. The filename will be used in any error messages arising during the parse.
RYML_EXPORT void parse_json_in_arena( csubstr json, Tree *t, id_type node_id); ///< (2) like (1) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, Tree *t ); ///< (3) parse JSON into an existing tree, into its root node.
RYML_EXPORT void parse_json_in_arena( csubstr json, Tree *t ); ///< (4) like (3) but no filename will be reported
RYML_EXPORT void parse_json_in_arena(csubstr filename, csubstr json, NodeRef node ); ///< (5) like (1) but the node is given as a NodeRef
RYML_EXPORT void parse_json_in_arena( csubstr json, NodeRef node ); ///< (6) like (5) but no filename will be reported
RYML_EXPORT Tree parse_json_in_arena(csubstr filename, csubstr json ); ///< (7) create a new tree, and parse JSON into its root node.
RYML_EXPORT Tree parse_json_in_arena( csubstr json ); ///< (8) like (7) but no filename will be reported
/* READ THE DEPRECATION NOTE!
*
* All of the functions below are intentionally left undefined, to
* prevent them being used.
*/
/** @cond dev */
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena( substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr yaml );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, Tree *t, id_type node_id);
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, Tree *t );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena( substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_json_in_arena(csubstr filename, substr json, NodeRef node );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena( substr json );
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_json_in_arena(csubstr filename, substr json );
/** @endcond */
/** @} */
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_PARSE_HPP_ */
File diff suppressed because it is too large Load Diff
-799
View File
@@ -1,799 +0,0 @@
#ifndef _C4_YML_PARSE_ENGINE_HPP_
#define _C4_YML_PARSE_ENGINE_HPP_
#ifndef _C4_YML_PARSER_STATE_HPP_
#include "c4/yml/parser_state.hpp"
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** @addtogroup doc_parse
* @{ */
/** @defgroup doc_event_handlers Event Handlers
*
* @brief rapidyaml implements its parsing logic with a two-level
* model, where a @ref ParseEngine object reads through the YAML
* source, and dispatches events to an EventHandler bound to the @ref
* ParseEngine. Because @ref ParseEngine is templated on the event
* handler, the binding uses static polymorphism, without any virtual
* functions. The actual handler object can be changed at run time,
* (but of course needs to be the type of the template parameter).
* This is thus a very efficient architecture, and further enables the
* user to provide his own custom handler if he wishes to bypass the
* rapidyaml @ref Tree.
*
* There are two handlers implemented in this project:
*
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref extra::EventHandlerInts parses YAML into an integer array
representation of the tree and scalars.
*
* - @ref extra::EventHandlerTestSuite is the handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project.
*
*
* ### Event model
*
* The event model used by the parse engine and event handlers follows
* very closely the event model in the [YAML test
* suite](https://github.com/yaml/yaml-test-suite).
*
* Consider for example this YAML,
* ```yaml
* {foo: bar,foo2: bar2}
* ```
* which would produce these events in the test-suite parlance:
* ```
* +STR
* +DOC
* +MAP {}
* =VAL :foo
* =VAL :bar
* =VAL :foo2
* =VAL :bar2
* -MAP
* -DOC
* -STR
* ```
*
* For reference, the @ref ParseEngine object will produce this
* sequence of calls to its bound EventHandler:
* ```cpp
* handler.begin_stream();
* handler.begin_doc();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("foo");
* handler.set_val_scalar_plain("bar");
* handler.add_sibling();
* handler.set_key_scalar_plain("foo2");
* handler.set_val_scalar_plain("bar2");
* handler.end_map();
* handler.end_doc();
* handler.end_stream();
* ```
*
* For many other examples of all areas of YAML and how ryml's parse
* model corresponds to the YAML standard model, refer to the [unit
* tests for the parse
* engine](https://github.com/biojppm/rapidyaml/tree/master/test/test_parse_engine.cpp).
*
*
* ### Special events
*
* Most of the parsing events adopted by rapidyaml in its event model
* are fairly obvious, but there are two less-obvious events requiring
* some explanation.
*
* These events exist to make it easier to parse some special YAML
* cases. They are called by the parser when a just-handled
* value/container is actually the first key of a new map:
*
* - `actually_val_is_first_key_of_new_map_flow()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTestSuite")
* - `actually_val_is_first_key_of_new_map_block()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTestSuite")
*
* For example, consider an implicit map inside a seq: `[a: b, c:
* d]` which is parsed as `[{a: b}, {c: d}]`. The standard event
* sequence for this YAML would be the following:
* ```cpp
* handler.begin_seq_val_flow();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("a");
* handler.set_val_scalar_plain("b");
* handler.end_map();
* handler.add_sibling();
* handler.begin_map_val_flow();
* handler.set_key_scalar_plain("c");
* handler.set_val_scalar_plain("d");
* handler.end_map();
* handler.end_seq();
* ```
* The problem with this event sequence is that it forces the
* parser to delay setting the val scalar (in this case "a" and
* "c") until it knows whether the scalar is a key or a val. This
* would require the parser to store the scalar until this
* time. For instance, in the example above, the parser should
* delay setting "a" and "c", because they are in fact keys and
* not vals. Until then, the parser would have to store "a" and
* "c" in its internal state. The downside is that this complexity
* cost would apply even if there is no implicit map -- every val
* in a seq would have to be delayed until one of the
* disambiguating subsequent tokens `,-]:` is found.
* By calling this function, the parser can avoid this complexity,
* by preemptively setting the scalar as a val. Then a call to
* this function will create the map and rearrange the scalar as
* key. Now the cost applies only once: when a seqimap starts. So
* the following (easier and cheaper) event sequence below has the
* same effect as the event sequence above:
* ```cpp
* handler.begin_seq_val_flow();
* handler.set_val_scalar_plain("notmap");
* handler.set_val_scalar_plain("a"); // preemptively set "a" as val!
* handler.actually_as_new_map_key(); // create a map, move the "a" val as the key of the first child of the new map
* handler.set_val_scalar_plain("b"); // now "a" is a key and "b" the val
* handler.end_map();
* handler.set_val_scalar_plain("c"); // "c" also as val!
* handler.actually_as_block_flow(); // likewise
* handler.set_val_scalar_plain("d"); // now "c" is a key and "b" the val
* handler.end_map();
* handler.end_seq();
* ```
* This also applies to container keys (although ryml's tree
* cannot accomodate these): the parser can preemptively set a
* container as a val, and call this event to turn that container
* into a key. For example, consider this yaml:
* ```yaml
* [aa, bb]: [cc, dd]
* # ^ ^ ^
* # | | |
* # (2) (1) (3) <- event sequence
* ```
* The standard event sequence for this YAML would be the
* following:
* ```cpp
* handler.begin_map_val_block(); // (1)
* handler.begin_seq_key_flow(); // (2)
* handler.set_val_scalar_plain("aa");
* handler.add_sibling();
* handler.set_val_scalar_plain("bb");
* handler.end_seq();
* handler.begin_seq_val_flow(); // (3)
* handler.set_val_scalar_plain("cc");
* handler.add_sibling();
* handler.set_val_scalar_plain("dd");
* handler.end_seq();
* handler.end_map();
* ```
* The problem with the sequence above is that, reading from
* left-to-right, the parser can only detect the proper calls at
* (1) and (2) once it reaches (1) in the YAML source. So, the
* parser would have to buffer the entire event sequence starting
* from the beginning until it reaches (1). Using this function,
* the parser can do instead:
* ```cpp
* handler.begin_seq_val_flow(); // (2) -- preemptively as val!
* handler.set_val_scalar_plain("aa");
* handler.add_sibling();
* handler.set_val_scalar_plain("bb");
* handler.end_seq();
* handler.actually_as_new_map_key(); // (1) -- adjust when finding that the prev val was actually a key.
* handler.begin_seq_val_flow(); // (3) -- go on as before
* handler.set_val_scalar_plain("cc");
* handler.add_sibling();
* handler.set_val_scalar_plain("dd");
* handler.end_seq();
* handler.end_map();
* ```
*/
class Tree;
class NodeRef;
class ConstNodeRef;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Options to give to the parser to control its behavior. */
struct RYML_EXPORT ParserOptions
{
private:
typedef enum : uint32_t {
SCALAR_FILTERING = (1u << 0u),
LOCATIONS = (1u << 1u),
DEFAULTS = SCALAR_FILTERING,
} Flags_e;
uint32_t flags = DEFAULTS;
public:
ParserOptions() = default;
public:
/** @name source location tracking */
/** @{ */
/** enable/disable source location tracking */
ParserOptions& locations(bool enabled) noexcept
{
if(enabled)
flags |= LOCATIONS;
else
flags &= ~LOCATIONS;
return *this;
}
/** query source location tracking status */
C4_ALWAYS_INLINE bool locations() const noexcept { return (flags & LOCATIONS); }
/** @} */
public:
/** @name scalar filtering status (experimental; disable at your discretion) */
/** @{ */
/** enable/disable scalar filtering while parsing */
ParserOptions& scalar_filtering(bool enabled) noexcept
{
if(enabled)
flags |= SCALAR_FILTERING;
else
flags &= ~SCALAR_FILTERING;
return *this;
}
/** query scalar filtering status */
C4_ALWAYS_INLINE bool scalar_filtering() const noexcept { return (flags & SCALAR_FILTERING); }
/** @} */
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** This is the main driver of parsing logic: it scans the YAML or
* JSON source for tokens, and emits the appropriate sequence of
* parsing events to its event handler. The parse engine itself has no
* special limitations, and *can* accomodate containers as keys; it is the
* event handler may introduce additional constraints.
*
* There are two implemented handlers (see @ref doc_event_handlers,
* which has important notes about the event model):
*
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref extra::EventHandlerTestSuite is a handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project. This is not part of the library and is
* not installed.
*
* - @ref extra::EventHandlerInts is the handler responsible for
* emitting integer-coded events. It is intended for implementing
* fully-conformant parsing in other programming languages
* (integration is currently under work for
* [YamlScript](https://github.com/yaml/yamlscript) and
* [go-yaml](https://github.com/yaml/go-yaml/)). It is not part of
* the library and is not installed.
*
*/
template<class EventHandler>
class ParseEngine
{
public:
using handler_type = EventHandler;
public:
/** @name construction and assignment */
/** @{ */
ParseEngine(EventHandler *evt_handler, ParserOptions opts={});
~ParseEngine();
ParseEngine(ParseEngine &&) noexcept;
ParseEngine(ParseEngine const&);
ParseEngine& operator=(ParseEngine &&) noexcept;
ParseEngine& operator=(ParseEngine const&);
/** @} */
public:
/** @name modifiers */
/** @{ */
/** Reserve a certain capacity for the parsing stack.
* This should be larger than the expected depth of the parsed
* YAML tree.
*
* The parsing stack is the only (potential) heap memory used
* directly by the parser.
*
* If the requested capacity is below the default
* stack size of 16, the memory is used directly in the parser
* object; otherwise it will be allocated from the heap.
*
* @note this reserves memory only for the parser itself; all the
* allocations for the parsed tree will go through the tree's
* allocator (when different).
*
* @note for maximum efficiency, the tree and the arena can (and
* should) also be reserved. */
void reserve_stack(id_type capacity)
{
m_evt_handler->m_stack.reserve(capacity);
}
/** Reserve a certain capacity for the array used to track node
* locations in the source buffer. */
void reserve_locations(size_t num_source_lines)
{
_resize_locations(num_source_lines);
}
RYML_DEPRECATED("filter arena no longer needed")
void reserve_filter_arena(size_t) {}
/** @} */
public:
/** @name getters */
/** @{ */
/** Get the options used to build this parser object. */
ParserOptions const& options() const { return m_options; }
/** Get the current callbacks in the parser. */
Callbacks const& callbacks() const { RYML_ASSERT(m_evt_handler); return m_evt_handler->m_stack.m_callbacks; }
/** Get the name of the latest file parsed by this object. */
csubstr filename() const { return m_file; }
/** Get the latest YAML buffer parsed by this object. */
csubstr source() const { return m_buf; }
/** Get the encoding of the latest YAML buffer parsed by this object.
* If no encoding was specified, UTF8 is assumed as per the YAML standard. */
Encoding_e encoding() const { return m_encoding != NOBOM ? m_encoding : UTF8; }
id_type stack_capacity() const { RYML_ASSERT(m_evt_handler); return m_evt_handler->m_stack.capacity(); }
size_t locations_capacity() const { return m_newline_offsets_capacity; }
RYML_DEPRECATED("filter arena no longer needed")
size_t filter_arena_capacity() const { return 0u; }
/** @} */
public:
/** @name parse methods */
/** @{ */
/** parse YAML in place, emitting events to the current handler */
void parse_in_place_ev(csubstr filename, substr src);
/** parse JSON in place, emitting events to the current handler */
void parse_json_in_place_ev(csubstr filename, substr src);
/** @} */
public:
// deprecated parse methods
/** @cond dev */
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place( substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_place(csubstr filename, substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_place( substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, csubstr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( csubstr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena(csubstr filename, csubstr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena( csubstr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, Tree *t, size_t node_id);
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, Tree *t );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena(csubstr filename, substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_arena( substr yaml, NodeRef node );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena(csubstr filename, substr yaml );
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena( substr yaml );
/** @endcond */
public:
/** @name locations */
/** @{ */
/** Get the string starting at a particular location, to the end
* of the parsed source buffer. */
csubstr location_contents(Location const& loc) const;
/** Given a pointer to a buffer position, get the location.
* @param[in] val must be pointing to somewhere in the source
* buffer that was last parsed by this object. */
Location val_location(const char *val) const;
/** @} */
public:
/** @cond dev */
template<class U>
RYML_DEPRECATED("moved to Tree::location(Parser const&). deliberately undefined here.")
auto location(Tree const&, id_type node) const -> typename std::enable_if<U::is_wtree, Location>::type;
template<class U>
RYML_DEPRECATED("moved to ConstNodeRef::location(Parser const&), deliberately undefined here.")
auto location(ConstNodeRef const&) const -> typename std::enable_if<U::is_wtree, Location>::type;
/** @endcond */
public:
/** @name scalar filtering */
/** @{*/
/** filter a plain scalar */
FilterResult filter_scalar_plain(csubstr scalar, substr dst, size_t indentation);
/** filter a plain scalar in place */
FilterResult filter_scalar_plain_in_place(substr scalar, size_t cap, size_t indentation);
/** filter a single-quoted scalar */
FilterResult filter_scalar_squoted(csubstr scalar, substr dst);
/** filter a single-quoted scalar in place */
FilterResult filter_scalar_squoted_in_place(substr scalar, size_t cap);
/** filter a double-quoted scalar */
FilterResult filter_scalar_dquoted(csubstr scalar, substr dst);
/** filter a double-quoted scalar in place */
FilterResultExtending filter_scalar_dquoted_in_place(substr scalar, size_t cap);
/** filter a block-literal scalar */
FilterResult filter_scalar_block_literal(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp);
/** filter a block-literal scalar in place */
FilterResult filter_scalar_block_literal_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp);
/** filter a block-folded scalar */
FilterResult filter_scalar_block_folded(csubstr scalar, substr dst, size_t indentation, BlockChomp_e chomp);
/** filter a block-folded scalar in place */
FilterResult filter_scalar_block_folded_in_place(substr scalar, size_t cap, size_t indentation, BlockChomp_e chomp);
/** @} */
private:
struct ScannedScalar
{
substr scalar;
bool needs_filter;
};
struct ScannedBlock
{
substr scalar;
size_t indentation;
BlockChomp_e chomp;
};
bool _is_doc_begin(csubstr s);
bool _is_doc_end(csubstr s);
bool _scan_scalar_plain_blck(ScannedScalar *C4_RESTRICT sc, size_t indentation);
bool _scan_scalar_plain_seq_flow(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_seq_blck(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_map_flow(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_map_blck(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_map_json(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_seq_json(ScannedScalar *C4_RESTRICT sc);
bool _scan_scalar_plain_unk(ScannedScalar *C4_RESTRICT sc);
bool _is_valid_start_scalar_plain_flow(csubstr s);
ScannedScalar _scan_scalar_squot();
ScannedScalar _scan_scalar_dquot();
void _scan_block(ScannedBlock *C4_RESTRICT sb, size_t indref);
csubstr _scan_anchor();
csubstr _scan_ref_seq();
csubstr _scan_ref_map();
csubstr _scan_tag();
public: // exposed for testing
/** @cond dev */
csubstr _filter_scalar_plain(substr s, size_t indentation);
csubstr _filter_scalar_squot(substr s);
csubstr _filter_scalar_dquot(substr s);
csubstr _filter_scalar_literal(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _filter_scalar_folded(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _move_scalar_left_and_add_newline(substr s);
csubstr _maybe_filter_key_scalar_plain(ScannedScalar const& sc, size_t indendation);
csubstr _maybe_filter_val_scalar_plain(ScannedScalar const& sc, size_t indendation);
csubstr _maybe_filter_key_scalar_squot(ScannedScalar const& sc);
csubstr _maybe_filter_val_scalar_squot(ScannedScalar const& sc);
csubstr _maybe_filter_key_scalar_dquot(ScannedScalar const& sc);
csubstr _maybe_filter_val_scalar_dquot(ScannedScalar const& sc);
csubstr _maybe_filter_key_scalar_literal(ScannedBlock const& sb);
csubstr _maybe_filter_val_scalar_literal(ScannedBlock const& sb);
csubstr _maybe_filter_key_scalar_folded(ScannedBlock const& sb);
csubstr _maybe_filter_val_scalar_folded(ScannedBlock const& sb);
/** @endcond */
private:
void _handle_map_block();
void _handle_seq_block();
void _handle_map_flow();
void _handle_seq_flow();
void _handle_seq_imap();
void _handle_map_json();
void _handle_seq_json();
void _handle_unk();
void _handle_unk_json();
void _handle_usty();
void _handle_flow_skip_whitespace();
void _end_map_blck();
void _end_seq_blck();
void _end2_map();
void _end2_seq();
void _begin2_doc();
void _begin2_doc_expl();
void _end2_doc();
void _end2_doc_expl();
void _maybe_begin_doc();
void _maybe_end_doc();
void _start_doc_suddenly();
void _end_doc_suddenly();
void _end_doc_suddenly__pop();
void _end_stream();
void _set_indentation(size_t indentation);
void _save_indentation();
void _handle_indentation_pop_from_block_seq();
void _handle_indentation_pop_from_block_map();
void _handle_indentation_pop(ParserState const* dst);
void _maybe_skip_comment();
void _skip_comment();
void _maybe_skip_whitespace_tokens();
void _maybe_skipchars(char c);
#ifdef RYML_NO_COVERAGE__TO_BE_DELETED
void _maybe_skipchars_up_to(char c, size_t max_to_skip);
#endif
template<size_t N>
void _skipchars(const char (&chars)[N]);
bool _maybe_scan_following_colon() noexcept;
bool _maybe_scan_following_comma() noexcept;
public:
/** @cond dev */
template<class FilterProcessor> auto _filter_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_squoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_dquoted(FilterProcessor &C4_RESTRICT proc) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_block_literal(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result());
template<class FilterProcessor> auto _filter_block_folded(FilterProcessor &C4_RESTRICT proc, size_t indentation, BlockChomp_e chomp) -> decltype(proc.result());
/** @endcond */
public:
/** @cond dev */
template<class FilterProcessor> void _filter_nl_plain(FilterProcessor &C4_RESTRICT proc, size_t indentation);
template<class FilterProcessor> void _filter_nl_squoted(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_nl_dquoted(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> bool _filter_ws_handle_to_first_non_space(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_ws_copy_trailing(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_ws_skip_trailing(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_dquoted_backslash(FilterProcessor &C4_RESTRICT proc);
template<class FilterProcessor> void _filter_chomp(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp, size_t indentation);
template<class FilterProcessor> size_t _handle_all_whitespace(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp);
template<class FilterProcessor> size_t _extend_to_chomp(FilterProcessor &C4_RESTRICT proc, size_t contents_len);
template<class FilterProcessor> void _filter_block_indentation(FilterProcessor &C4_RESTRICT proc, size_t indentation);
template<class FilterProcessor> void _filter_block_folded_newlines(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len);
template<class FilterProcessor> size_t _filter_block_folded_newlines_compress(FilterProcessor &C4_RESTRICT proc, size_t num_newl, size_t wpos_at_first_newl);
template<class FilterProcessor> void _filter_block_folded_newlines_leading(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len);
template<class FilterProcessor> void _filter_block_folded_indented_block(FilterProcessor &C4_RESTRICT proc, size_t indentation, size_t len, size_t curr_indentation) noexcept;
/** @endcond */
private:
void _line_progressed(size_t ahead);
void _line_ended();
void _line_ended_undo();
bool _finished_file() const;
bool _finished_line() const;
void _scan_line();
substr _peek_next_line(size_t pos=npos) const;
bool _at_line_begin() const
{
return m_evt_handler->m_curr->line_contents.rem.begin() == m_evt_handler->m_curr->line_contents.full.begin();
}
void _relocate_arena(csubstr prev_arena, substr next_arena);
static void _s_relocate_arena(void*, csubstr prev_arena, substr next_arena);
private:
C4_ALWAYS_INLINE bool has_all(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) == f; }
C4_ALWAYS_INLINE bool has_any(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) != 0; }
C4_ALWAYS_INLINE bool has_none(ParserFlag_t f) const noexcept { return (m_evt_handler->m_curr->flags & f) == 0; }
static C4_ALWAYS_INLINE bool has_all(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) == f; }
static C4_ALWAYS_INLINE bool has_any(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) != 0; }
static C4_ALWAYS_INLINE bool has_none(ParserFlag_t f, ParserState const* C4_RESTRICT s) noexcept { return (s->flags & f) == 0; }
#ifndef RYML_DBG
C4_ALWAYS_INLINE static void add_flags(ParserFlag_t on, ParserState *C4_RESTRICT s) noexcept { s->flags |= on; }
C4_ALWAYS_INLINE static void addrem_flags(ParserFlag_t on, ParserFlag_t off, ParserState *C4_RESTRICT s) noexcept { s->flags &= ~off; s->flags |= on; }
C4_ALWAYS_INLINE static void rem_flags(ParserFlag_t off, ParserState *C4_RESTRICT s) noexcept { s->flags &= ~off; }
C4_ALWAYS_INLINE void add_flags(ParserFlag_t on) noexcept { m_evt_handler->m_curr->flags |= on; }
C4_ALWAYS_INLINE void addrem_flags(ParserFlag_t on, ParserFlag_t off) noexcept { m_evt_handler->m_curr->flags &= ~off; m_evt_handler->m_curr->flags |= on; }
C4_ALWAYS_INLINE void rem_flags(ParserFlag_t off) noexcept { m_evt_handler->m_curr->flags &= ~off; }
#else
static void add_flags(ParserFlag_t on, ParserState *C4_RESTRICT s);
static void addrem_flags(ParserFlag_t on, ParserFlag_t off, ParserState *C4_RESTRICT s);
static void rem_flags(ParserFlag_t off, ParserState *C4_RESTRICT s);
C4_ALWAYS_INLINE void add_flags(ParserFlag_t on) noexcept { add_flags(on, m_evt_handler->m_curr); }
C4_ALWAYS_INLINE void addrem_flags(ParserFlag_t on, ParserFlag_t off) noexcept { addrem_flags(on, off, m_evt_handler->m_curr); }
C4_ALWAYS_INLINE void rem_flags(ParserFlag_t off) noexcept { rem_flags(off, m_evt_handler->m_curr); }
#endif
private:
void _prepare_locations();
void _resize_locations(size_t sz);
bool _locations_dirty() const;
private:
void _reset();
void _free();
void _clr();
#ifdef RYML_DBG
template<class ...Args> void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const;
#endif
template<class ...Args> void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
template<class ...Args> void _errloc(csubstr fmt, Location const& loc, Args const& C4_RESTRICT ...args) const;
template<class DumpFn> void _fmt_msg(DumpFn &&dumpfn) const;
private:
/** store pending tag or anchor/ref annotations */
struct Annotation
{
struct Entry
{
csubstr str;
size_t indentation;
size_t line;
};
Entry annotations[2];
size_t num_entries;
};
void _handle_colon();
void _add_annotation(Annotation *C4_RESTRICT dst, csubstr str, size_t indentation, size_t line);
void _clear_annotations(Annotation *C4_RESTRICT dst);
bool _has_pending_annotations() const { return m_pending_tags.num_entries || m_pending_anchors.num_entries; }
#ifdef RYML_NO_COVERAGE__TO_BE_DELETED
bool _handle_indentation_from_annotations();
#endif
bool _annotations_require_key_container() const;
void _handle_annotations_before_blck_key_scalar();
void _handle_annotations_before_blck_val_scalar();
void _handle_annotations_before_start_mapblck(size_t current_line);
void _handle_annotations_before_start_mapblck_as_key();
void _handle_annotations_and_indentation_after_start_mapblck(size_t key_indentation, size_t key_line);
size_t _select_indentation_from_annotations(size_t val_indentation, size_t val_line);
void _handle_directive(csubstr rem);
bool _handle_bom();
void _handle_bom(Encoding_e enc);
void _check_tag(csubstr tag);
private:
ParserOptions m_options;
csubstr m_file;
substr m_buf;
public:
/** @cond dev */
EventHandler *C4_RESTRICT m_evt_handler; // NOLINT
/** @endcond */
private:
Annotation m_pending_anchors;
Annotation m_pending_tags;
bool m_was_inside_qmrk;
bool m_doc_empty = true;
size_t m_prev_colon = npos;
Encoding_e m_encoding = UTF8;
private:
size_t *m_newline_offsets;
size_t m_newline_offsets_size;
size_t m_newline_offsets_capacity;
csubstr m_newline_offsets_buf;
};
/** Quickly inspect the source to estimate the number of nodes the
* resulting tree is likely have. If a tree is empty before
* parsing, considerable time will be spent growing it, so calling
* this to reserve the tree size prior to parsing is likely to
* result in a time gain. We encourage using this method before
* parsing, but as always measure its impact in performance to
* obtain a good trade-off.
*
* @note since this method is meant for optimizing performance, it
* is approximate. The result may be actually smaller than the
* resulting number of nodes, notably if the YAML uses implicit
* maps as flow seq members as in `[these: are, individual:
* maps]`. */
RYML_EXPORT id_type estimate_tree_capacity(csubstr src); // NOLINT(readability-redundant-declaration)
/** @} */
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif /* _C4_YML_PARSE_ENGINE_HPP_ */
-212
View File
@@ -1,212 +0,0 @@
#ifndef _C4_YML_PARSER_STATE_HPP_
#define _C4_YML_PARSER_STATE_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
namespace yml {
/** data type for @ref ParserState_e */
using ParserFlag_t = int;
/** Enumeration of the state flags for the parser */
typedef enum : ParserFlag_t {
RTOP = 0x01 << 0, ///< reading at top level
RUNK = 0x01 << 1, ///< reading unknown state (when starting): must determine whether scalar, map or seq
RMAP = 0x01 << 2, ///< reading a map
RSEQ = 0x01 << 3, ///< reading a seq
FLOW = 0x01 << 4, ///< reading is inside explicit flow chars: [] or {}
BLCK = 0x01 << 5, ///< reading in block mode
QMRK = 0x01 << 6, ///< reading an explicit key (`? key`)
RKEY = 0x01 << 7, ///< reading a scalar as key
RVAL = 0x01 << 9, ///< reading a scalar as val
RKCL = 0x01 << 8, ///< reading the key colon (ie the : after the key in the map)
RNXT = 0x01 << 10, ///< read next val or keyval
SSCL = 0x01 << 11, ///< there's a stored scalar
QSCL = 0x01 << 12, ///< stored scalar was quoted
RSET = 0x01 << 13, ///< the (implicit) map being read is a !!set. @see https://yaml.org/type/set.html
RDOC = 0x01 << 14, ///< reading a document
NDOC = 0x01 << 15, ///< no document mode. a document has ended and another has not started yet.
USTY = 0x01 << 16, ///< reading in unknown style mode - must determine FLOW or BLCK
//! reading an implicit map nested in an explicit seq.
//! eg, {key: [key2: value2, key3: value3]}
//! is parsed as {key: [{key2: value2}, {key3: value3}]}
RSEQIMAP = 0x01 << 17,
} ParserState_e;
#ifdef RYML_DBG
/** @cond dev */
namespace detail {
csubstr _parser_flags_to_str(substr buf, ParserFlag_t flags);
} // namespace
/** @endcond */
#endif
/** Helper to control the line contents while parsing a buffer */
struct LineContents
{
substr rem; ///< the stripped line remainder; initially starts at the first non-space character
size_t indentation; ///< the number of spaces on the beginning of the line
substr full; ///< the full line, including newlines on the right
substr stripped; ///< the stripped line, excluding newlines on the right
LineContents() = default;
void reset_with_next_line(substr buf, size_t offset)
{
RYML_ASSERT(offset <= buf.len);
size_t e = offset;
// get the current line stripped of newline chars
while(e < buf.len && (buf.str[e] != '\n' && buf.str[e] != '\r'))
++e;
RYML_ASSERT(e >= offset);
const substr stripped_ = buf.range(offset, e);
#if defined(__GNUC__) && __GNUC__ == 11
C4_DONT_OPTIMIZE(stripped_);
#endif
// advance pos to include the first line ending
if(e < buf.len && buf.str[e] == '\r')
++e;
if(e < buf.len && buf.str[e] == '\n')
++e;
const substr full_ = buf.range(offset, e);
reset(full_, stripped_);
}
void reset(substr full_, substr stripped_)
{
rem = stripped_;
indentation = stripped_.first_not_of(' '); // find the first column where the character is not a space
full = full_;
stripped = stripped_;
}
C4_ALWAYS_INLINE size_t current_col() const RYML_NOEXCEPT
{
// WARNING: gcc x86 release builds were wrong (eg returning 0
// when the result should be 4 ) when this function was like
// this:
//
//return current_col(rem);
//
// (see below for the full definition of the called overload
// of current_col())
//
// ... so we explicitly inline the code in here:
RYML_ASSERT(rem.str >= full.str);
size_t col = static_cast<size_t>(rem.str - full.str);
return col;
//
// this was happening only on builds specifically with (gcc
// AND x86 AND release); no other builds were having the
// problem: not in debug, not in x64, not in other
// architectures, not in clang, not in visual studio. WTF!?
//
// Enabling debug prints with RYML_DBG made the problem go
// away, so these could not be used to debug the
// problem. Adding prints inside the called current_col() also
// made the problem go away! WTF!???
//
// a prize will be offered to anybody able to explain why this
// was happening.
}
C4_ALWAYS_INLINE size_t current_col(csubstr s) const RYML_NOEXCEPT
{
RYML_ASSERT(s.str >= full.str);
RYML_ASSERT(full.is_super(s));
size_t col = static_cast<size_t>(s.str - full.str);
return col;
}
};
static_assert(std::is_standard_layout<LineContents>::value, "LineContents not standard");
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
struct ParserState
{
LineContents line_contents;
Location pos;
ParserFlag_t flags;
size_t indref; ///< the reference indentation in the current block scope
id_type level;
id_type node_id; ///< don't hold a pointer to the node as it will be relocated during tree resizes
size_t scalar_col; // the column where the scalar (or its quotes) begin
bool more_indented;
bool has_children;
ParserState() = default;
void start_parse(const char *file, id_type node_id_)
{
level = 0;
pos.name = to_csubstr(file);
pos.offset = 0;
pos.line = 1;
pos.col = 1;
node_id = node_id_;
more_indented = false;
scalar_col = 0;
indref = 0;
has_children = false;
}
void reset_after_push()
{
node_id = NONE;
indref = npos;
more_indented = false;
++level;
has_children = false;
}
C4_ALWAYS_INLINE void reset_before_pop(ParserState const& to_pop)
{
pos = to_pop.pos;
line_contents = to_pop.line_contents;
}
public:
C4_ALWAYS_INLINE bool at_line_beginning() const noexcept
{
return line_contents.rem.str == line_contents.full.str;
}
C4_ALWAYS_INLINE bool indentation_eq() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation == indref;
}
C4_ALWAYS_INLINE bool indentation_ge() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation >= indref;
}
C4_ALWAYS_INLINE bool indentation_gt() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation > indref;
}
C4_ALWAYS_INLINE bool indentation_lt() const noexcept
{
RYML_ASSERT(indref != npos);
return line_contents.indentation != npos && line_contents.indentation < indref;
}
};
static_assert(std::is_standard_layout<ParserState>::value, "ParserState not standard");
} // namespace yml
} // namespace c4
// NOLINTEND(hicpp-signed-bitwise)
#endif /* _C4_YML_PARSER_STATE_HPP_ */
-97
View File
@@ -1,97 +0,0 @@
#ifndef _C4_YML_PREPROCESS_HPP_
#define _C4_YML_PREPROCESS_HPP_
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#include <c4/substr.hpp>
namespace c4 {
namespace yml {
/** @addtogroup doc_preprocessors
* @{
*/
/** @cond dev */
namespace detail {
using Preprocessor = size_t(csubstr, substr);
template<Preprocessor PP, class CharContainer>
substr preprocess_into_container(csubstr input, CharContainer *out)
{
// try to write once. the preprocessor will stop writing at the end of
// the container, but will process all the input to determine the
// required container size.
size_t sz = PP(input, to_substr(*out));
// if the container size is not enough, resize, and run again in the
// resized container
if(sz > out->size())
{
out->resize(sz);
sz = PP(input, to_substr(*out));
}
return to_substr(*out).first(sz);
}
} // namespace detail
/** @endcond */
//-----------------------------------------------------------------------------
/** @defgroup doc_preprocess_rxmap preprocess_rxmap
*
* @brief Convert flow-type relaxed maps (with implicit bools) into strict YAML
* flow map:
*
* @code{.yaml}
* {a, b, c, d: [e, f], g: {a, b}}
* # is converted into this:
* {a: 1, b: 1, c: 1, d: [e, f], g: {a, b}}
* @endcode
* @note this is NOT recursive - conversion happens only in the top-level map
* @param rxmap A relaxed map
* @param buf output buffer
* @param out output container
*
* @{
*/
/** Write into a given output buffer. This function is safe to call with
* empty or small buffers; it won't write beyond the end of the buffer.
*
* @return the number of characters required for output
*/
RYML_EXPORT size_t preprocess_rxmap(csubstr rxmap, substr buf);
/** Write into an existing container. It is resized to contained the output.
* @return a substr of the container
* @overload preprocess_rxmap */
template<class CharContainer>
substr preprocess_rxmap(csubstr rxmap, CharContainer *out)
{
return detail::preprocess_into_container<preprocess_rxmap>(rxmap, out);
}
/** Create a container with the result.
* @overload preprocess_rxmap */
template<class CharContainer>
CharContainer preprocess_rxmap(csubstr rxmap)
{
CharContainer out;
preprocess_rxmap(rxmap, &out);
return out;
}
/** @} */ // preprocess_rxmap
/** @} */ // group
} // namespace yml
} // namespace c4
#endif /* _C4_YML_PREPROCESS_HPP_ */
@@ -1,88 +0,0 @@
#ifndef _C4_YML_REFERENCE_RESOLVER_HPP_
#define _C4_YML_REFERENCE_RESOLVER_HPP_
#include "c4/yml/tree.hpp"
#include "c4/yml/detail/stack.hpp"
namespace c4 {
namespace yml {
/** @addtogroup doc_ref_utils
* @{
*/
/** Reusable object to resolve references/aliases in a @ref Tree. */
struct RYML_EXPORT ReferenceResolver
{
ReferenceResolver() = default;
/** Resolve references: for each reference, look for a matching
* anchor, and copy its contents to the ref node.
*
* @p tree the subject tree
*
* @p clear_anchors whether to clear existing anchors after
* resolving
*
* This method first does a full traversal of the tree to gather
* all anchors and references in a separate collection, then it
* goes through that collection to locate the names, which it does
* by obeying the YAML standard diktat that "an alias node refers
* to the most recent node in the serialization having the
* specified anchor"
*
* So, depending on the number of anchor/alias nodes, this is a
* potentially expensive operation, with a best-case linear
* complexity (from the initial traversal). This potential cost is
* one of the reasons for requiring an explicit call.
*
* The @ref Tree has an `Tree::resolve()` overload set forwarding
* here. Previously this operation was done there, using a
* discarded object; using this separate class offers opportunity
* for reuse of the object.
*
* @warning resolving references opens an attack vector when the
* data is malicious or severely malformed, as the tree can expand
* exponentially. See for example the [Billion Laughs
* Attack](https://en.wikipedia.org/wiki/Billion_laughs_attack).
*
*/
void resolve(Tree *tree, bool clear_anchors=true);
public:
/** @cond dev */
struct RefData
{
NodeType type;
id_type node;
id_type prev_anchor;
id_type target;
id_type parent_ref;
id_type parent_ref_sibling;
};
void reset_(Tree *t_);
void resolve_();
void gather_anchors_and_refs_();
void gather_anchors_and_refs__(id_type n);
id_type count_anchors_and_refs_(id_type n);
id_type lookup_(RefData const* C4_RESTRICT ra);
Tree *C4_RESTRICT m_tree;
/** We're using this stack purely as an array. */
detail::stack<RefData> m_refs;
/** @endcond */
};
/** @} */
} // namespace ryml
} // namespace c4
#endif // _C4_YML_REFERENCE_RESOLVER_HPP_
-46
View File
@@ -1,46 +0,0 @@
#ifndef _C4_YML_STD_MAP_HPP_
#define _C4_YML_STD_MAP_HPP_
/** @file map.hpp write/read std::map to/from a YAML tree. */
#include "c4/yml/node.hpp"
#include <map>
namespace c4 {
namespace yml {
// std::map requires child nodes in the data
// tree hierarchy (a MAP node in ryml parlance).
// So it should be serialized via write()/read().
template<class K, class V, class Less, class Alloc>
void write(c4::yml::NodeRef *n, std::map<K, V, Less, Alloc> const& m)
{
*n |= c4::yml::MAP;
for(auto const& C4_RESTRICT p : m)
{
auto ch = n->append_child();
ch << c4::yml::key(p.first);
ch << p.second;
}
}
/** read the node members, assigning into the existing map. If a key
* is already present in the map, then its value will be
* move-assigned. */
template<class K, class V, class Less, class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::map<K, V, Less, Alloc> * m)
{
for(auto const& C4_RESTRICT ch : n)
{
K k{};
ch >> c4::yml::key(k);
ch >> (*m)[k];
}
return true;
}
} // namespace yml
} // namespace c4
#endif // _C4_YML_STD_MAP_HPP_
-8
View File
@@ -1,8 +0,0 @@
#ifndef _C4_YML_STD_STD_HPP_
#define _C4_YML_STD_STD_HPP_
#include "c4/yml/std/string.hpp"
#include "c4/yml/std/vector.hpp"
#include "c4/yml/std/map.hpp"
#endif // _C4_YML_STD_STD_HPP_
-9
View File
@@ -1,9 +0,0 @@
#ifndef C4_YML_STD_STRING_HPP_
#define C4_YML_STD_STRING_HPP_
/** @file string.hpp substring conversions for/from std::string */
// everything we need is implemented here:
#include <c4/std/string.hpp>
#endif // C4_YML_STD_STRING_HPP_
-59
View File
@@ -1,59 +0,0 @@
#ifndef _C4_YML_STD_VECTOR_HPP_
#define _C4_YML_STD_VECTOR_HPP_
#include "c4/yml/node.hpp"
#include <c4/std/vector.hpp>
#include <vector>
namespace c4 {
namespace yml {
// vector is a sequence-like type, and it requires child nodes
// in the data tree hierarchy (a SEQ node in ryml parlance).
// So it should be serialized via write()/read().
template<class V, class Alloc>
void write(c4::yml::NodeRef *n, std::vector<V, Alloc> const& vec)
{
*n |= c4::yml::SEQ;
for(V const& v : vec)
n->append_child() << v;
}
/** read the node members, overwriting existing vector entries. */
template<class V, class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::vector<V, Alloc> *vec)
{
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
vec->resize(static_cast<size_t>(n.num_children()));
C4_SUPPRESS_WARNING_GCC_POP
size_t pos = 0;
for(ConstNodeRef const child : n)
child >> (*vec)[pos++];
return true;
}
/** read the node members, overwriting existing vector entries.
* specialization: std::vector<bool> uses std::vector<bool>::reference as
* the return value of its operator[]. */
template<class Alloc>
bool read(c4::yml::ConstNodeRef const& n, std::vector<bool, Alloc> *vec)
{
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
vec->resize(static_cast<size_t>(n.num_children()));
C4_SUPPRESS_WARNING_GCC_POP
size_t pos = 0;
bool tmp = {};
for(ConstNodeRef const child : n)
{
child >> tmp;
(*vec)[pos++] = tmp;
}
return true;
}
} // namespace yml
} // namespace c4
#endif // _C4_YML_STD_VECTOR_HPP_
-83
View File
@@ -1,83 +0,0 @@
#ifndef _C4_YML_TAG_HPP_
#define _C4_YML_TAG_HPP_
#include <c4/yml/common.hpp>
namespace c4 {
namespace yml {
class Tree;
/** @addtogroup doc_tag_utils
*
* @{
*/
#ifndef RYML_MAX_TAG_DIRECTIVES
/** the maximum number of tag directives in a Tree */
#define RYML_MAX_TAG_DIRECTIVES 4
#endif
/** the integral type necessary to cover all the bits marking node tags */
using tag_bits = uint16_t;
/** a bit mask for marking tags for types */
typedef enum : tag_bits {
TAG_NONE = 0,
// container types
TAG_MAP = 1, /**< !!map Unordered set of key: value pairs without duplicates. @see https://yaml.org/type/map.html */
TAG_OMAP = 2, /**< !!omap Ordered sequence of key: value pairs without duplicates. @see https://yaml.org/type/omap.html */
TAG_PAIRS = 3, /**< !!pairs Ordered sequence of key: value pairs allowing duplicates. @see https://yaml.org/type/pairs.html */
TAG_SET = 4, /**< !!set Unordered set of non-equal values. @see https://yaml.org/type/set.html */
TAG_SEQ = 5, /**< !!seq Sequence of arbitrary values. @see https://yaml.org/type/seq.html */
// scalar types
TAG_BINARY = 6, /**< !!binary A sequence of zero or more octets (8 bit values). @see https://yaml.org/type/binary.html */
TAG_BOOL = 7, /**< !!bool Mathematical Booleans. @see https://yaml.org/type/bool.html */
TAG_FLOAT = 8, /**< !!float Floating-point approximation to real numbers. https://yaml.org/type/float.html */
TAG_INT = 9, /**< !!float Mathematical integers. https://yaml.org/type/int.html */
TAG_MERGE = 10, /**< !!merge Specify one or more mapping to be merged with the current one. https://yaml.org/type/merge.html */
TAG_NULL = 11, /**< !!null Devoid of value. https://yaml.org/type/null.html */
TAG_STR = 12, /**< !!str A sequence of zero or more Unicode characters. https://yaml.org/type/str.html */
TAG_TIMESTAMP = 13, /**< !!timestamp A point in time https://yaml.org/type/timestamp.html */
TAG_VALUE = 14, /**< !!value Specify the default value of a mapping https://yaml.org/type/value.html */
TAG_YAML = 15, /**< !!yaml Specify the default value of a mapping https://yaml.org/type/yaml.html */
} YamlTag_e;
RYML_EXPORT YamlTag_e to_tag(csubstr tag);
RYML_EXPORT csubstr from_tag(YamlTag_e tag);
RYML_EXPORT csubstr from_tag_long(YamlTag_e tag);
RYML_EXPORT csubstr normalize_tag(csubstr tag);
RYML_EXPORT csubstr normalize_tag_long(csubstr tag);
RYML_EXPORT csubstr normalize_tag_long(csubstr tag, substr output);
RYML_EXPORT bool is_custom_tag(csubstr tag);
struct RYML_EXPORT TagDirective
{
/** Eg <pre>!e!</pre> in <pre>%TAG !e! tag:example.com,2000:app/</pre> */
csubstr handle;
/** Eg <pre>tag:example.com,2000:app/</pre> in <pre>%TAG !e! tag:example.com,2000:app/</pre> */
csubstr prefix;
/** The next node to which this tag directive applies */
id_type next_node_id;
bool create_from_str(csubstr directive_); ///< leaves next_node_id unfilled
size_t transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets=true) const;
};
struct RYML_EXPORT TagDirectiveRange
{
TagDirective const* C4_RESTRICT b;
TagDirective const* C4_RESTRICT e;
C4_ALWAYS_INLINE TagDirective const* begin() const noexcept { return b; }
C4_ALWAYS_INLINE TagDirective const* end() const noexcept { return e; }
};
/** @} */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_TAG_HPP_ */
File diff suppressed because it is too large Load Diff
-25
View File
@@ -1,25 +0,0 @@
#ifndef _C4_YML_VERSION_HPP_
#define _C4_YML_VERSION_HPP_
/** @file version.hpp */
#define RYML_VERSION "0.10.0"
#define RYML_VERSION_MAJOR 0
#define RYML_VERSION_MINOR 10
#define RYML_VERSION_PATCH 0
#include <c4/substr.hpp>
#include <c4/yml/export.hpp>
namespace c4 {
namespace yml {
RYML_EXPORT csubstr version();
RYML_EXPORT int version_major();
RYML_EXPORT int version_minor();
RYML_EXPORT int version_patch();
} // namespace yml
} // namespace c4
#endif /* _C4_YML_VERSION_HPP_ */
-195
View File
@@ -1,195 +0,0 @@
#ifndef _C4_YML_WRITER_HPP_
#define _C4_YML_WRITER_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#include <c4/substr.hpp>
#include <stdio.h> // fwrite(), fputc()
#include <string.h> // memcpy()
namespace c4 {
namespace yml {
/** @addtogroup doc_emit
* @{
*/
/** @defgroup doc_writers Writer objects to use with an Emitter
* @see Emitter
* @{
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to a file. Defaults to stdout. */
struct WriterFile
{
FILE * m_file;
size_t m_pos;
WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}
substr _get(bool /*error_on_excess*/) const
{
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
(void)fwrite(a, sizeof(char), N - 1, m_file);
m_pos += N - 1;
}
void _do_write(csubstr sp)
{
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wsign-conversion")
if(sp.empty())
return;
(void)fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file);
m_pos += sp.len;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
}
void _do_write(const char c)
{
(void)fputc(c, m_file);
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
for(size_t i = 0; i < num_times; ++i)
(void)fputc(c, m_file);
m_pos += num_times;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to an STL-like ostream. */
template<class OStream>
struct WriterOStream
{
OStream* m_stream;
size_t m_pos;
WriterOStream(OStream &s) : m_stream(&s), m_pos(0) {}
substr _get(bool /*error_on_excess*/) const
{
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
m_stream->write(a, N - 1);
m_pos += N - 1;
}
void _do_write(csubstr sp)
{
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wsign-conversion")
if(sp.empty())
return;
m_stream->write(sp.str, sp.len);
m_pos += sp.len;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
}
void _do_write(const char c)
{
m_stream->put(c);
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
for(size_t i = 0; i < num_times; ++i)
m_stream->put(c);
m_pos += num_times;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a writer to a substr */
struct WriterBuf
{
substr m_buf;
size_t m_pos;
WriterBuf(substr sp) : m_buf(sp), m_pos(0) {}
substr _get(bool error_on_excess) const
{
if(m_pos <= m_buf.len)
return m_buf.first(m_pos);
else if(error_on_excess)
c4::yml::error("not enough space in the given buffer");
substr sp;
sp.str = nullptr;
sp.len = m_pos;
return sp;
}
template<size_t N>
void _do_write(const char (&a)[N])
{
RYML_ASSERT( ! m_buf.overlaps(a));
if(m_pos + N-1 <= m_buf.len)
memcpy(&(m_buf[m_pos]), a, N-1);
m_pos += N-1;
}
void _do_write(csubstr sp)
{
if(sp.empty())
return;
RYML_ASSERT( ! sp.overlaps(m_buf));
if(m_pos + sp.len <= m_buf.len)
memcpy(&(m_buf[m_pos]), sp.str, sp.len);
m_pos += sp.len;
}
void _do_write(const char c)
{
if(m_pos + 1 <= m_buf.len)
m_buf[m_pos] = c;
++m_pos;
}
void _do_write(const char c, size_t num_times)
{
if(m_pos + num_times <= m_buf.len)
for(size_t i = 0; i < num_times; ++i)
m_buf[m_pos + i] = c;
m_pos += num_times;
}
};
/** @ } */
/** @ } */
} // namespace yml
} // namespace c4
#endif /* _C4_YML_WRITER_HPP_ */
-16
View File
@@ -1,16 +0,0 @@
#ifndef _C4_YML_YML_HPP_
#define _C4_YML_YML_HPP_
#include "c4/yml/version.hpp"
#include "c4/yml/tree.hpp"
#include "c4/yml/node.hpp"
#include "c4/yml/emit.hpp"
#include "c4/yml/event_handler_tree.hpp"
#include "c4/yml/parse_engine.hpp"
#include "c4/yml/filter_processor.hpp"
#include "c4/yml/parse.hpp"
#include "c4/yml/preprocess.hpp"
#include "c4/yml/reference_resolver.hpp"
#include "c4/yml/tag.hpp"
#endif // _C4_YML_YML_HPP_
-391
View File
@@ -1,391 +0,0 @@
# To make this file known to Qt Creator using:
# Tools > Options > Debugger > Locals & Expressions > Extra Debugging Helpers
# Any contents here will be picked up by GDB, LLDB, and CDB based
# debugging in Qt Creator automatically.
# Example to display a simple type
# template<typename U, typename V> struct MapNode
# {
# U key;
# V data;
# }
#
# def qdump__MapNode(d, value):
# d.putValue("This is the value column contents")
# d.putExpandable()
# if d.isExpanded():
# with Children(d):
# # Compact simple case.
# d.putSubItem("key", value["key"])
# # Same effect, with more customization possibilities.
# with SubItem(d, "data")
# d.putItem("data", value["data"])
# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
# for more complex examples.
# to try parsing:
# env PYTHONPATH=/usr/share/qtcreator/debugger/ python src/ryml-gdbtypes.py
import dumper
#from dumper import Dumper, Value, Children, SubItem
#from dumper import SubItem, Children
from dumper import *
import sys
import os
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# QtCreator makes it really hard to figure out problems in this code.
# So here are some debugging utilities.
# FIXME. this decorator is not working; find out why.
def dbglog(func):
"""a decorator that logs entry and exit of functions"""
if not _DBG:
return func
def func_wrapper(*args, **kwargs):
_dbg_enter(func.__name__)
ret = func(*args, **kwargs)
_dbg_exit(func.__name__)
return ret
return func_wrapper
_DBG = False
_dbg_log = None
_dbg_stack = 0
def _dbg(*args, **kwargs):
global _dbg_log, _dbg_stack
if not _DBG:
return
if _dbg_log is None:
filename = os.path.join(os.path.dirname(__file__), "dbg.txt")
_dbg_log = open(filename, "w")
kwargs['file'] = _dbg_log
kwargs['flush'] = True
print(" " * _dbg_stack, *args, **kwargs)
def _dbg_enter(name):
global _dbg_stack
_dbg(name, "- enter")
_dbg_stack += 1
def _dbg_exit(name):
global _dbg_stack
_dbg_stack -= 1
_dbg(name, "- exit!")
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
NPOS = 18446744073709551615
MAX_SUBSTR_LEN_DISPLAY = 80
MAX_SUBSTR_LEN_EXPAND = 1000
def get_str_value(d, value, limit=0):
# adapted from dumper.py::Dumper::putCharArrayValue()
m_str = value["str"].pointer()
m_len = value["len"].integer()
if m_len == NPOS:
_dbg("getstr... 1", m_len)
m_str = "!!!!!<npos>!!!!!"
m_len = len(m_str)
return m_str, m_len
if limit == 0:
limit = d.displayStringLimit
elided, shown = d.computeLimit(m_len, limit)
mem = bytes(d.readRawMemory(m_str, shown))
mem = mem.decode('utf8')
return mem, m_len
def __display_csubstr(d, value, limit=0):
m_str, m_len = get_str_value(d, value)
safe_len = min(m_len, MAX_SUBSTR_LEN_DISPLAY)
disp = m_str[0:safe_len]
# ensure the string escapes characters like \n\r\t etc
disp = disp.encode('unicode_escape').decode('utf8')
# WATCHOUT. quotes in the string will make qtcreator hang!!!
disp = disp.replace('"', '\\"')
disp = disp.replace('\'', '\\')
if m_len <= MAX_SUBSTR_LEN_DISPLAY:
d.putValue(f"[{m_len}] '{disp}'")
else:
d.putValue(f"[{m_len}] '{disp}'...")
return m_str, m_len
def qdump__c4__csubstr(d, value):
m_str, m_len = __display_csubstr(d, value)
d.putExpandable()
if d.isExpanded():
with Children(d):
safe_len = min(m_len, MAX_SUBSTR_LEN_EXPAND)
for i in range(safe_len):
ct = d.createType('char')
d.putSubItem(safe_len, d.createValue(value["str"].pointer() + i, ct))
d.putSubItem("len", value["len"])
d.putPtrItem("str", value["str"].pointer())
def qdump__c4__substr(d, value):
qdump__c4__csubstr(d, value)
def qdump__c4__basic_substring(d, value):
qdump__c4__csubstr(d, value)
def qdump__c4__yml__NodeScalar(d, value):
alen = value["anchor"]["len"].integer()
tlen = value["tag" ]["len"].integer()
m_str, m_len = get_str_value(d, value["scalar"])
if alen == 0 and tlen == 0:
d.putValue(f'\'{m_str}\'')
elif alen == 0 and tlen > 0:
d.putValue(f'\'{m_str}\' [Ta]')
elif alen > 0 and tlen == 0:
d.putValue(f'\'{m_str}\' [tA]')
elif alen > 0 and tlen > 0:
d.putValue(f'\'{m_str}\' [TA]')
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("[scalar]", value["scalar"])
if tlen > 0:
d.putSubItem("[tag]", value["tag"])
if alen > 0:
d.putSubItem("[anchor or ref]", value["anchor"])
def _format_enum_value(int_value, enum_map):
str_value = enum_map.get(int_value, None)
display = f'{int_value}' if str_value is None else f'{str_value} ({int_value})'
return display
def _format_bitmask_value(int_value, enum_map):
str_value = enum_map.get(int_value, None)
if str_value:
return f'{str_value} ({int_value})'
else:
out = ""
orig = int_value
# do in reverse to get compound flags first
for k, v in reversed(enum_map.items()):
if (k != 0):
if (int_value & k) == k:
if len(out) > 0:
out += '|'
out += v
int_value &= ~k
else:
if len(out) == 0 and int_value == 0:
return v
if out == "":
return f'{int_value}'
return f"{out} ({orig})"
def _c4bit(*ints):
ret = 0
for i in ints:
ret |= 1 << i
return ret
node_types = {
0: "NOTYPE",
_c4bit(0): "VAL" ,
_c4bit(1): "KEY" ,
_c4bit(2): "MAP" ,
_c4bit(3): "SEQ" ,
_c4bit(4): "DOC" ,
_c4bit(5,3): "STREAM",
_c4bit(6): "KEYREF" ,
_c4bit(7): "VALREF" ,
_c4bit(8): "KEYANCH" ,
_c4bit(9): "VALANCH" ,
_c4bit(10): "KEYTAG" ,
_c4bit(11): "VALTAG" ,
_c4bit(12): "VALQUO" ,
_c4bit(13): "KEYQUO" ,
_c4bit(1,0): "KEYVAL",
_c4bit(1,3): "KEYSEQ",
_c4bit(1,2): "KEYMAP",
_c4bit(4,2): "DOCMAP",
_c4bit(4,3): "DOCSEQ",
_c4bit(4,0): "DOCVAL",
#
_c4bit(14): "STYLE_FLOW_SL",
_c4bit(15): "STYLE_FLOW_ML",
_c4bit(16): "STYLE_BLOCK",
#
_c4bit(17): "KEY_LITERAL",
_c4bit(18): "VAL_LITERAL",
_c4bit(19): "KEY_FOLDED",
_c4bit(20): "VAL_FOLDED",
_c4bit(21): "KEY_SQUO",
_c4bit(22): "VAL_SQUO",
_c4bit(23): "KEY_DQUO",
_c4bit(24): "VAL_DQUO",
_c4bit(25): "KEY_PLAIN",
_c4bit(26): "VAL_PLAIN",
}
node_types_rev = {v: k for k, v in node_types.items()}
def _node_type_has_all(node_type_value, type_name):
exp = node_types_rev[type_name]
return (node_type_value & exp) == exp
def _node_type_has_any(node_type_value, type_name):
exp = node_types_rev[type_name]
return (node_type_value & exp) != 0
def qdump__c4__yml__NodeType_e(d, value):
v = _format_bitmask_value(value.integer(), node_types)
d.putValue(v)
def qdump__c4__yml__NodeType(d, value):
qdump__c4__yml__NodeType_e(d, value["type"])
def qdump__c4__yml__NodeData(d, value):
d.putValue("wtf")
ty = _format_bitmask_value(value.integer(), node_types)
t = value["m_type"]["type"].integer()
k = value["m_key"]["scalar"]
v = value["m_val"]["scalar"]
sk, lk = get_str_value(d, k)
sv, lv = get_str_value(d, v)
if _node_type_has_all(t, "KEYVAL"):
d.putValue(f"'{sk}': '{sv}' {ty}")
elif _node_type_has_any(t, "KEY"):
d.putValue(f"'{sk}': {ty}")
elif _node_type_has_any(t, "VAL"):
d.putValue(f"'{sv}' {ty}")
else:
d.putValue(f"{ty}")
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("m_type", value["m_type"])
# key
if _node_type_has_any(t, "KEY"):
d.putSubItem("m_key", value["m_key"])
if _node_type_has_any(t, "KEYREF"):
with SubItem(d, "m_key.ref"):
s_, _ = get_str_value(d, value["m_key"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "KEYANCH"):
with SubItem(d, "m_key.anchor"):
s_, _ = get_str_value(d, value["m_key"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "KEYTAG"):
with SubItem(d, "m_key.tag"):
s_, _ = get_str_value(d, value["m_key"]["tag"])
d.putValue(f"'{s_}'")
# val
if _node_type_has_any(t, "VAL"):
d.putSubItem("m_val", value["m_val"])
if _node_type_has_any(t, "VALREF"):
with SubItem(d, "m_val.ref"):
s_, _ = get_str_value(d, value["m_val"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "VALANCH"):
with SubItem(d, "m_val.anchor"):
s_, _ = get_str_value(d, value["m_val"]["anchor"])
d.putValue(f"'{s_}'")
if _node_type_has_any(t, "VALTAG"):
with SubItem(d, "m_val.tag"):
s_, _ = get_str_value(d, value["m_val"]["tag"])
d.putValue(f"'{s_}'")
# hierarchy
_dump_node_index(d, "m_parent", value)
_dump_node_index(d, "m_first_child", value)
_dump_node_index(d, "m_last_child", value)
_dump_node_index(d, "m_next_sibling", value)
_dump_node_index(d, "m_prev_sibling", value)
def _dump_node_index(d, name, value):
if int(value[name].integer()) == NPOS:
pass
#with SubItem(d, name):
# d.putValue("-")
else:
d.putSubItem(name, value[name])
# c4::yml::Tree
def qdump__c4__yml__Tree(d, value):
m_size = value["m_size"].integer()
m_cap = value["m_cap"].integer()
d.putExpandable()
if d.isExpanded():
#d.putArrayData(value["m_buf"], m_size, value["m_buf"].dereference())
with Children(d):
with SubItem(d, f"[nodes]"):
d.putItemCount(m_size)
d.putArrayData(value["m_buf"].pointer(), m_size, value["m_buf"].type.dereference())
d.putPtrItem("m_buf", value["m_buf"].pointer())
d.putIntItem("m_size", value["m_size"])
d.putIntItem("m_cap (capacity)", value["m_cap"])
d.putIntItem("[slack]", m_cap - m_size)
d.putIntItem("m_free_head", value["m_free_head"])
d.putIntItem("m_free_tail", value["m_free_tail"])
d.putSubItem("m_arena", value["m_arena"])
def qdump__c4__yml__detail__stack(d, value):
T = value.type[0]
N = value.type[0]
m_size = value["m_size"].integer()
m_capacity = value["m_capacity"].integer()
d.putItemCount(m_size)
if d.isExpanded():
with Children(d):
with SubItem(d, f"[nodes]"):
d.putItemCount(m_size)
d.putArrayData(value["m_stack"].pointer(), m_size, T)
d.putIntItem("m_size", value["m_size"])
d.putIntItem("m_capacity", value["m_capacity"])
#d.putIntItem("[small capacity]", N)
d.putIntItem("[is large]", value["m_buf"].address() == value["m_stack"].pointer())
d.putPtrItem("m_stack", value["m_stack"].pointer())
d.putPtrItem("m_buf", value["m_buf"].address())
def qdump__c4__yml__detail__ReferenceResolver__refdata(d, value):
node = value["node"].integer()
ty = _format_bitmask_value(value["type"].integer(), node_types)
d.putValue(f'{node} {ty}')
d.putExpandable()
if d.isExpanded():
with Children(d):
d.putSubItem("type", value["type"])
d.putSubItem("node", value["node"])
_dump_node_index(d, "prev_anchor", value)
_dump_node_index(d, "target", value)
_dump_node_index(d, "parent_ref", value)
_dump_node_index(d, "parent_ref_sibling", value)
-11
View File
@@ -1,11 +0,0 @@
#ifndef _RYML_HPP_
#define _RYML_HPP_
#include "c4/yml/yml.hpp"
namespace ryml {
using namespace c4::yml;
using namespace c4;
}
#endif /* _RYML_HPP_ */
-304
View File
@@ -1,304 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Very good intro:
@see https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2017
@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
See also:
@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="c4::yml::NodeScalar">
<DisplayString Condition="(tag.len == 0) &amp;&amp; (anchor.len == 0)">{scalar.str,[scalar.len]}</DisplayString>
<DisplayString Condition="(tag.len > 0) &amp;&amp; (anchor.len == 0)">{scalar.str,[scalar.len]} [T]</DisplayString>
<DisplayString Condition="(tag.len == 0) &amp;&amp; (anchor.len > 0)">{scalar.str,[scalar.len]} [A]</DisplayString>
<DisplayString Condition="(tag.len > 0) &amp;&amp; (anchor.len > 0)">{scalar.str,[scalar.len]} [T][A]</DisplayString>
<Expand>
<Item Name="scalar">scalar</Item>
<Item Name="tag">tag</Item>
<Item Name="anchor">anchor</Item>
</Expand>
</Type>
<Type Name="c4::yml::NodeType">
<DisplayString Condition="((type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((type &amp; c4::yml::VAL) == c4::yml::VAL)">[KEYVAL]</DisplayString>
<DisplayString Condition="((type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ]</DisplayString>
<DisplayString Condition="((type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((type &amp; c4::yml::MAP) == c4::yml::MAP)">[KEYMAP]</DisplayString>
<DisplayString Condition="((type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((type &amp; c4::yml::VAL) == c4::yml::VAL)">[DOCVAL]</DisplayString>
<DisplayString Condition="((type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
<DisplayString Condition="((type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((type &amp; c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::VAL ) == c4::yml::VAL" >[VAL]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::KEY ) == c4::yml::KEY" >[KEY]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
<DisplayString Condition="(type &amp; c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
<Expand>
<Synthetic Name="[type bits]">
<Expand>
<Item Name="[0]" Condition="(type &amp; c4::yml::KEY) != 0">c4::yml::KEY</Item>
<Item Name="[1]" Condition="(type &amp; c4::yml::VAL) != 0">c4::yml::VAL</Item>
<Item Name="[2]" Condition="(type &amp; c4::yml::MAP) != 0">c4::yml::MAP</Item>
<Item Name="[3]" Condition="(type &amp; c4::yml::SEQ) != 0">c4::yml::SEQ</Item>
<Item Name="[4]" Condition="(type &amp; c4::yml::DOC) != 0">c4::yml::DOC</Item>
<Item Name="[5]" Condition="(type &amp; c4::yml::STREAM) != 0">c4::yml::STREAM</Item>
<Item Name="[6]" Condition="(type &amp; c4::yml::KEYREF) != 0">c4::yml::KEYREF</Item>
<Item Name="[7]" Condition="(type &amp; c4::yml::VALREF) != 0">c4::yml::VALREF</Item>
<Item Name="[8]" Condition="(type &amp; c4::yml::KEYANCH) != 0">c4::yml::KEYANCH</Item>
<Item Name="[9]" Condition="(type &amp; c4::yml::VALANCH) != 0">c4::yml::VALANCH</Item>
<Item Name="[10]" Condition="(type &amp; c4::yml::KEYTAG) != 0">c4::yml::KEYTAG</Item>
<Item Name="[11]" Condition="(type &amp; c4::yml::VALTAG) != 0">c4::yml::VALTAG</Item>
</Expand>
</Synthetic>
<Synthetic Name="[style bits]">
<Expand>
<Item Name="[0]" Condition="(type &amp; c4::yml::_WIP_KEY_UNFILT) != 0">c4::yml::_WIP_KEY_UNFILT</Item>
<Item Name="[1]" Condition="(type &amp; c4::yml::_WIP_VAL_UNFILT) != 0">c4::yml::_WIP_VAL_UNFILT</Item>
<Item Name="[2]" Condition="(type &amp; c4::yml::_WIP_STYLE_FLOW_SL) != 0">c4::yml::_WIP_STYLE_FLOW</Item>
<Item Name="[3]" Condition="(type &amp; c4::yml::_WIP_STYLE_FLOW_ML) != 0">c4::yml::_WIP_STYLE_FLOW</Item>
<Item Name="[4]" Condition="(type &amp; c4::yml::_WIP_STYLE_BLOCK) != 0">c4::yml::_WIP_STYLE_BLOCK</Item>
<Item Name="[5]" Condition="(type &amp; c4::yml::_WIP_KEY_LITERAL) != 0">c4::yml::_WIP_KEY_LITERAL</Item>
<Item Name="[6]" Condition="(type &amp; c4::yml::_WIP_VAL_LITERAL) != 0">c4::yml::_WIP_VAL_LITERAL</Item>
<Item Name="[7]" Condition="(type &amp; c4::yml::_WIP_KEY_FOLDED) != 0">c4::yml::_WIP_KEY_FOLDED</Item>
<Item Name="[8]" Condition="(type &amp; c4::yml::_WIP_VAL_FOLDED) != 0">c4::yml::_WIP_VAL_FOLDED</Item>
<Item Name="[9]" Condition="(type &amp; c4::yml::_WIP_KEY_SQUO) != 0">c4::yml::_WIP_KEY_SQUO</Item>
<Item Name="[10]" Condition="(type &amp; c4::yml::_WIP_VAL_SQUO) != 0">c4::yml::_WIP_VAL_SQUO</Item>
<Item Name="[11]" Condition="(type &amp; c4::yml::_WIP_KEY_DQUO) != 0">c4::yml::_WIP_KEY_DQUO</Item>
<Item Name="[12]" Condition="(type &amp; c4::yml::_WIP_VAL_DQUO) != 0">c4::yml::_WIP_VAL_DQUO</Item>
<Item Name="[13]" Condition="(type &amp; c4::yml::_WIP_KEY_PLAIN) != 0">c4::yml::_WIP_KEY_PLAIN</Item>
<Item Name="[14]" Condition="(type &amp; c4::yml::_WIP_VAL_PLAIN) != 0">c4::yml::_WIP_VAL_PLAIN</Item>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::NodeData">
<DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::VAL) == c4::yml::VAL)">[KEYVAL] {m_key.scalar.str,[m_key.scalar.len]}: {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
<DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
<DisplayString Condition="((m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY) &amp;&amp; ((m_type.type &amp; c4::yml::MAP) == c4::yml::MAP)">[KEYMAP] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
<DisplayString Condition="((m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((m_type.type &amp; c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
<DisplayString Condition="((m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC) &amp;&amp; ((m_type.type &amp; c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::VAL ) == c4::yml::VAL" >[VAL] {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::KEY ) == c4::yml::KEY" >[KEY] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
<DisplayString Condition="(m_type.type &amp; c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
<Expand>
<Item Name="type">m_type</Item>
<Item Name="key" Condition="(m_type.type &amp; c4::yml::KEY) != 0">m_key</Item>
<Item Name="val" Condition="(m_type.type &amp; c4::yml::VAL) != 0">m_val</Item>
<Item Name="key quoted" Condition="((m_type.type &amp; c4::yml::KEY) != 0) &amp;&amp; ((m_type.type &amp; c4::yml::KEYQUO) != 0)">c4::yml::KEYQUO</Item>
<Item Name="val quoted" Condition="((m_type.type &amp; c4::yml::VAL) != 0) &amp;&amp; ((m_type.type &amp; c4::yml::VALQUO) != 0)">c4::yml::VALQUO</Item>
<Item Name="key ref" Condition="(m_type.type &amp; c4::yml::KEYREF) != 0">m_key.anchor</Item>
<Item Name="val ref" Condition="(m_type.type &amp; c4::yml::VALREF) != 0">m_val.anchor</Item>
<Item Name="key anchor" Condition="(m_type.type &amp; c4::yml::KEYANCH) != 0">m_key.anchor</Item>
<Item Name="val anchor" Condition="(m_type.type &amp; c4::yml::VALANCH) != 0">m_val.anchor</Item>
<Item Name="parent" Condition="m_parent == c4::yml::NONE">NONE</Item>
<Item Name="parent" Condition="m_parent != c4::yml::NONE">m_parent</Item>
<Item Name="first child" Condition="m_first_child != c4::yml::NONE">m_first_child</Item>
<Item Name="last child" Condition="m_last_child != c4::yml::NONE">m_last_child</Item>
<Item Name="prev sibling" Condition="m_prev_sibling != c4::yml::NONE">m_prev_sibling</Item>
<Item Name="next sibling" Condition="m_next_sibling != c4::yml::NONE">m_next_sibling</Item>
</Expand>
</Type>
<Type Name="c4::yml::Tree">
<DisplayString>sz={m_size}, cap={m_cap}</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_cap</Item>
<Synthetic Name="[buffer]">
<Expand>
<ArrayItems>
<Size>m_cap</Size>
<ValuePointer>m_buf</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<Item Name="free head">m_free_head</Item>
<Item Name="arena">m_arena</Item>
</Expand>
</Type>
<Type Name="c4::yml::Tree::_lookup_path_token">
<DisplayString>{value} ({type})</DisplayString>
<Expand>
<Item Name="value">value</Item>
<Item Name="type">type</Item>
</Expand>
</Type>
<Type Name="c4::yml::Tree::lookup_result">
<DisplayString>{path} -- target={target} closest={closest}</DisplayString>
<Expand>
<Item Name="target">target</Item>
<Item Name="closest">closest</Item>
<Item Name="path_pos">path_pos</Item>
<Item Name="path">path</Item>
<Synthetic Name="[resolved]">
<DisplayString>{path.str,[path_pos]}</DisplayString>
</Synthetic>
<Synthetic Name="[unresolved]">
<DisplayString>{path.str+path_pos,[path.len-path_pos]}</DisplayString>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::NodeRef">
<DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
<DisplayString Condition="(m_seed.len != c4::yml::NONE) &amp;&amp; (m_seed.str == nullptr)">[INDEX SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
<DisplayString Condition="(m_seed.len != c4::yml::NONE) &amp;&amp; (m_seed.str != nullptr)">[NAMED SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
<DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
<Expand>
<Item Name="id">m_id</Item>
<Item Name="element">*(m_tree->m_buf + m_id)</Item>
<Item Name="tree">m_tree</Item>
<Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) &amp;&amp; (((m_tree->m_buf + m_id)->m_type.type &amp; (c4::yml::MAP|c4::yml::SEQ)) != 0)">
<Expand>
<CustomListItems>
<Variable Name="tree" InitialValue="m_tree"/>
<Variable Name="buf" InitialValue="m_tree->m_buf"/>
<Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
<Loop>
<Item>buf + curr</Item>
<Exec>curr = (buf + curr)->m_next_sibling</Exec>
<Break Condition="curr == c4::yml::NONE"/>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::ConstNodeRef">
<DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
<DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
<Expand>
<Item Name="id">m_id</Item>
<Item Name="element">*(m_tree->m_buf + m_id)</Item>
<Item Name="tree">m_tree</Item>
<Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) &amp;&amp; (((m_tree->m_buf + m_id)->m_type.type &amp; (c4::yml::MAP|c4::yml::SEQ)) != 0)">
<Expand>
<CustomListItems>
<Variable Name="tree" InitialValue="m_tree"/>
<Variable Name="buf" InitialValue="m_tree->m_buf"/>
<Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
<Loop>
<Item>buf + curr</Item>
<Exec>curr = (buf + curr)->m_next_sibling</Exec>
<Break Condition="curr == c4::yml::NONE"/>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::detail::ReferenceResolver">
<DisplayString>#refs={refs.m_size} #nodes={t->m_size}</DisplayString>
<Expand>
<Synthetic Name="[ref_nodes]">
<Expand>
<CustomListItems>
<Variable Name="curr" InitialValue="0"/>
<Loop>
<Item>t->m_buf + (refs.m_stack + curr)->node</Item>
<Exec>curr = curr+1</Exec>
<Break Condition="curr >= refs.m_size"/>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
<Synthetic Name="[refs]">
<Expand>
<ArrayItems>
<Size>refs.m_size</Size>
<ValuePointer>refs.m_stack</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<Item Name="[tree]">t</Item>
</Expand>
</Type>
<Type Name="c4::yml::detail::stack&lt;*,*&gt;">
<DisplayString>sz={m_size} cap={m_capacity}</DisplayString>
<Expand>
<Item Name="[size]">m_size</Item>
<Item Name="[capacity]">m_capacity</Item>
<Item Name="[is small]">m_buf == m_stack</Item>
<Synthetic Name="[items]">
<Expand>
<ArrayItems>
<Size>m_size</Size>
<ValuePointer>m_stack</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::detail::FilterProcessorSrcDst">
<DisplayString>src={src.str,[rpos]} dst={dst.str,[wpos]}</DisplayString>
<Expand>
<Item Name="[src]">src</Item>
<Item Name="[dst]">dst</Item>
<Item Name="[rpos]">rpos</Item>
<Item Name="[wpos]">wpos</Item>
<Synthetic Name="[read]">
<StringView>src.str,[rpos]</StringView>
<Expand>
<ArrayItems>
<Size>rpos</Size>
<ValuePointer>src.str</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="c4::yml::detail::FilterProcessorInplace">
<DisplayString>src={src.str,[rpos]} dst={src.str,[wpos]}</DisplayString>
<Expand>
<Item Name="[rpos]">rpos</Item>
<Item Name="[wpos]">wpos</Item>
<Item Name="[wcap]">wcap</Item>
<Synthetic Name="[buf]">
<StringView>src.str,[wcap]</StringView>
<Expand>
<ArrayItems>
<Size>wcap</Size>
<ValuePointer>src.str</ValuePointer>
</ArrayItems>
</Expand>
</Synthetic>
<Item Name="[src]">src</Item>
<Synthetic Name="[to be read]">
<StringView>src.str+rpos,[src.len-rpos]</StringView>
<Expand>
<ArrayItems><Size>src.len-rpos</Size><ValuePointer>src.str+rpos</ValuePointer></ArrayItems>
</Expand>
</Synthetic>
<Synthetic Name="[read]">
<StringView>src.str,[rpos]</StringView>
<Expand>
<ArrayItems><Size>rpos</Size><ValuePointer>src.str</ValuePointer></ArrayItems>
</Expand>
</Synthetic>
<Synthetic Name="[written]">
<StringView>src.str,[wpos]</StringView>
<Expand>
<ArrayItems><Size>wpos</Size><ValuePointer>src.str</ValuePointer></ArrayItems>
</Expand>
</Synthetic>
</Expand>
</Type>
</AutoVisualizer>
-6
View File
@@ -1,6 +0,0 @@
#ifndef _RYML_STD_HPP_
#define _RYML_STD_HPP_
#include "./c4/yml/std/std.hpp"
#endif /* _RYML_STD_HPP_ */
-139
View File
@@ -1,139 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{DE9653B6-17DD-356A-9EE0-28A731772587}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>rapidyaml</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset Condition="!$(Configuration.Contains(Clang))">$(DefaultPlatformToolset)</PlatformToolset>
<PlatformToolset Condition="$(Configuration.Contains(Clang))">ClangCL</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);C4_NO_DEBUG_BREAK</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)src;$(ProjectDir)include;$(ProjectDir)..\fast_float\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="$(Configuration.Contains(Debug))">
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="!$(Configuration.Contains(Debug))">
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="include\c4\base64.hpp" />
<ClInclude Include="include\c4\blob.hpp" />
<ClInclude Include="include\c4\charconv.hpp" />
<ClInclude Include="include\c4\compiler.hpp" />
<ClInclude Include="include\c4\config.hpp" />
<ClInclude Include="include\c4\cpu.hpp" />
<ClInclude Include="include\c4\dump.hpp" />
<ClInclude Include="include\c4\error.hpp" />
<ClInclude Include="include\c4\export.hpp" />
<ClInclude Include="include\c4\format.hpp" />
<ClInclude Include="include\c4\language.hpp" />
<ClInclude Include="include\c4\memory_util.hpp" />
<ClInclude Include="include\c4\platform.hpp" />
<ClInclude Include="include\c4\preprocessor.hpp" />
<ClInclude Include="include\c4\std\std.hpp" />
<ClInclude Include="include\c4\std\std_fwd.hpp" />
<ClInclude Include="include\c4\std\string.hpp" />
<ClInclude Include="include\c4\std\string_fwd.hpp" />
<ClInclude Include="include\c4\std\string_view.hpp" />
<ClInclude Include="include\c4\std\tuple.hpp" />
<ClInclude Include="include\c4\std\vector.hpp" />
<ClInclude Include="include\c4\std\vector_fwd.hpp" />
<ClInclude Include="include\c4\substr.hpp" />
<ClInclude Include="include\c4\substr_fwd.hpp" />
<ClInclude Include="include\c4\szconv.hpp" />
<ClInclude Include="include\c4\types.hpp" />
<ClInclude Include="include\c4\utf.hpp" />
<ClInclude Include="include\c4\windows.hpp" />
<ClInclude Include="include\c4\windows_pop.hpp" />
<ClInclude Include="include\c4\windows_push.hpp" />
<ClInclude Include="include\c4\yml\common.hpp" />
<ClInclude Include="include\c4\yml\detail\checks.hpp" />
<ClInclude Include="include\c4\yml\detail\dbgprint.hpp" />
<ClInclude Include="include\c4\yml\detail\print.hpp" />
<ClInclude Include="include\c4\yml\detail\stack.hpp" />
<ClInclude Include="include\c4\yml\emit.def.hpp" />
<ClInclude Include="include\c4\yml\emit.hpp" />
<ClInclude Include="include\c4\yml\export.hpp" />
<ClInclude Include="include\c4\yml\node.hpp" />
<ClInclude Include="include\c4\yml\parse.hpp" />
<ClInclude Include="include\c4\yml\preprocess.hpp" />
<ClInclude Include="include\c4\yml\std\map.hpp" />
<ClInclude Include="include\c4\yml\std\std.hpp" />
<ClInclude Include="include\c4\yml\std\string.hpp" />
<ClInclude Include="include\c4\yml\std\vector.hpp" />
<ClInclude Include="include\c4\yml\tag.hpp" />
<ClInclude Include="include\c4\yml\version.hpp" />
<ClInclude Include="include\c4\yml\tree.hpp" />
<ClInclude Include="include\c4\yml\writer.hpp" />
<ClInclude Include="include\c4\yml\event_handler_stack.hpp" />
<ClInclude Include="include\c4\yml\event_handler_tree.hpp" />
<ClInclude Include="include\c4\yml\filter_processor.hpp" />
<ClInclude Include="include\c4\yml\fwd.hpp" />
<ClInclude Include="include\c4\yml\node_type.hpp" />
<ClInclude Include="include\c4\yml\parse_engine.def.hpp" />
<ClInclude Include="include\c4\yml\parse_engine.hpp" />
<ClInclude Include="include\c4\yml\parser_state.hpp" />
<ClInclude Include="include\c4\yml\reference_resolver.hpp" />
<ClInclude Include="include\c4\yml\yml.hpp" />
<ClInclude Include="include\ryml.hpp" />
<ClInclude Include="include\ryml_std.hpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="include\c4\c4core.natvis" />
<Natvis Include="include\ryml.natvis" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\c4\base64.cpp" />
<ClCompile Include="src\c4\error.cpp" />
<ClCompile Include="src\c4\format.cpp" />
<ClCompile Include="src\c4\language.cpp" />
<ClCompile Include="src\c4\memory_util.cpp" />
<ClCompile Include="src\c4\utf.cpp" />
<ClCompile Include="src\c4\yml\common.cpp" />
<ClCompile Include="src\c4\yml\node.cpp" />
<ClCompile Include="src\c4\yml\parse.cpp" />
<ClCompile Include="src\c4\yml\preprocess.cpp" />
<ClCompile Include="src\c4\yml\tree.cpp" />
<ClCompile Include="src\c4\yml\node_type.cpp" />
<ClCompile Include="src\c4\yml\reference_resolver.cpp" />
<ClCompile Include="src\c4\yml\tag.cpp" />
<ClCompile Include="src\c4\yml\version.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-226
View File
@@ -1,226 +0,0 @@
#include "c4/base64.hpp"
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wchar-subscripts" // array subscript is of type 'char'
# pragma clang diagnostic ignored "-Wold-style-cast"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wuseless-cast"
# pragma GCC diagnostic ignored "-Wchar-subscripts"
# pragma GCC diagnostic ignored "-Wtype-limits"
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
// NOLINTBEGIN(bugprone-signed-char-misuse,cert-str34-c,hicpp-signed-bitwise)
namespace c4 {
namespace detail {
constexpr static const char base64_sextet_to_char_[64] = {
/* 0/ 65*/ 'A', /* 1/ 66*/ 'B', /* 2/ 67*/ 'C', /* 3/ 68*/ 'D',
/* 4/ 69*/ 'E', /* 5/ 70*/ 'F', /* 6/ 71*/ 'G', /* 7/ 72*/ 'H',
/* 8/ 73*/ 'I', /* 9/ 74*/ 'J', /*10/ 75*/ 'K', /*11/ 74*/ 'L',
/*12/ 77*/ 'M', /*13/ 78*/ 'N', /*14/ 79*/ 'O', /*15/ 78*/ 'P',
/*16/ 81*/ 'Q', /*17/ 82*/ 'R', /*18/ 83*/ 'S', /*19/ 82*/ 'T',
/*20/ 85*/ 'U', /*21/ 86*/ 'V', /*22/ 87*/ 'W', /*23/ 88*/ 'X',
/*24/ 89*/ 'Y', /*25/ 90*/ 'Z', /*26/ 97*/ 'a', /*27/ 98*/ 'b',
/*28/ 99*/ 'c', /*29/100*/ 'd', /*30/101*/ 'e', /*31/102*/ 'f',
/*32/103*/ 'g', /*33/104*/ 'h', /*34/105*/ 'i', /*35/106*/ 'j',
/*36/107*/ 'k', /*37/108*/ 'l', /*38/109*/ 'm', /*39/110*/ 'n',
/*40/111*/ 'o', /*41/112*/ 'p', /*42/113*/ 'q', /*43/114*/ 'r',
/*44/115*/ 's', /*45/116*/ 't', /*46/117*/ 'u', /*47/118*/ 'v',
/*48/119*/ 'w', /*49/120*/ 'x', /*50/121*/ 'y', /*51/122*/ 'z',
/*52/ 48*/ '0', /*53/ 49*/ '1', /*54/ 50*/ '2', /*55/ 51*/ '3',
/*56/ 52*/ '4', /*57/ 53*/ '5', /*58/ 54*/ '6', /*59/ 55*/ '7',
/*60/ 56*/ '8', /*61/ 57*/ '9', /*62/ 43*/ '+', /*63/ 47*/ '/',
};
// https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
constexpr static const char base64_char_to_sextet_[128] = {
#define __ char(-1) // undefined below
/* 0 NUL*/ __, /* 1 SOH*/ __, /* 2 STX*/ __, /* 3 ETX*/ __,
/* 4 EOT*/ __, /* 5 ENQ*/ __, /* 6 ACK*/ __, /* 7 BEL*/ __,
/* 8 BS */ __, /* 9 TAB*/ __, /* 10 LF */ __, /* 11 VT */ __,
/* 12 FF */ __, /* 13 CR */ __, /* 14 SO */ __, /* 15 SI */ __,
/* 16 DLE*/ __, /* 17 DC1*/ __, /* 18 DC2*/ __, /* 19 DC3*/ __,
/* 20 DC4*/ __, /* 21 NAK*/ __, /* 22 SYN*/ __, /* 23 ETB*/ __,
/* 24 CAN*/ __, /* 25 EM */ __, /* 26 SUB*/ __, /* 27 ESC*/ __,
/* 28 FS */ __, /* 29 GS */ __, /* 30 RS */ __, /* 31 US */ __,
/* 32 SPC*/ __, /* 33 ! */ __, /* 34 " */ __, /* 35 # */ __,
/* 36 $ */ __, /* 37 % */ __, /* 38 & */ __, /* 39 ' */ __,
/* 40 ( */ __, /* 41 ) */ __, /* 42 * */ __, /* 43 + */ 62,
/* 44 , */ __, /* 45 - */ __, /* 46 . */ __, /* 47 / */ 63,
/* 48 0 */ 52, /* 49 1 */ 53, /* 50 2 */ 54, /* 51 3 */ 55,
/* 52 4 */ 56, /* 53 5 */ 57, /* 54 6 */ 58, /* 55 7 */ 59,
/* 56 8 */ 60, /* 57 9 */ 61, /* 58 : */ __, /* 59 ; */ __,
/* 60 < */ __, /* 61 = */ __, /* 62 > */ __, /* 63 ? */ __,
/* 64 @ */ __, /* 65 A */ 0, /* 66 B */ 1, /* 67 C */ 2,
/* 68 D */ 3, /* 69 E */ 4, /* 70 F */ 5, /* 71 G */ 6,
/* 72 H */ 7, /* 73 I */ 8, /* 74 J */ 9, /* 75 K */ 10,
/* 76 L */ 11, /* 77 M */ 12, /* 78 N */ 13, /* 79 O */ 14,
/* 80 P */ 15, /* 81 Q */ 16, /* 82 R */ 17, /* 83 S */ 18,
/* 84 T */ 19, /* 85 U */ 20, /* 86 V */ 21, /* 87 W */ 22,
/* 88 X */ 23, /* 89 Y */ 24, /* 90 Z */ 25, /* 91 [ */ __,
/* 92 \ */ __, /* 93 ] */ __, /* 94 ^ */ __, /* 95 _ */ __,
/* 96 ` */ __, /* 97 a */ 26, /* 98 b */ 27, /* 99 c */ 28,
/*100 d */ 29, /*101 e */ 30, /*102 f */ 31, /*103 g */ 32,
/*104 h */ 33, /*105 i */ 34, /*106 j */ 35, /*107 k */ 36,
/*108 l */ 37, /*109 m */ 38, /*110 n */ 39, /*111 o */ 40,
/*112 p */ 41, /*113 q */ 42, /*114 r */ 43, /*115 s */ 44,
/*116 t */ 45, /*117 u */ 46, /*118 v */ 47, /*119 w */ 48,
/*120 x */ 49, /*121 y */ 50, /*122 z */ 51, /*123 { */ __,
/*124 | */ __, /*125 } */ __, /*126 ~ */ __, /*127 DEL*/ __,
#undef __
};
#ifndef NDEBUG
void base64_test_tables()
{
for(size_t i = 0; i < C4_COUNTOF(detail::base64_sextet_to_char_); ++i)
{
char s2c = base64_sextet_to_char_[i];
char c2s = base64_char_to_sextet_[(unsigned)s2c];
C4_CHECK((size_t)c2s == i);
}
for(size_t i = 0; i < C4_COUNTOF(detail::base64_char_to_sextet_); ++i)
{
char c2s = base64_char_to_sextet_[i];
if(c2s == char(-1))
continue;
char s2c = base64_sextet_to_char_[(unsigned)c2s];
C4_CHECK((size_t)s2c == i);
}
}
#endif
} // namespace detail
bool base64_valid(csubstr encoded)
{
if((encoded.len & size_t(3u)) != size_t(0)) // (encoded.len % 4u)
return false;
for(const char c : encoded)
{
if(c < 0/* || c >= 128*/)
return false;
if(c == '=')
continue;
if(detail::base64_char_to_sextet_[c] == char(-1))
return false;
}
return true;
}
size_t base64_encode(substr buf, cblob data)
{
#define c4append_(c) { if(pos < buf.len) { buf.str[pos] = (c); } ++pos; }
#define c4append_idx_(char_idx) \
{\
C4_XASSERT((char_idx) < sizeof(detail::base64_sextet_to_char_));\
c4append_(detail::base64_sextet_to_char_[(char_idx)]);\
}
size_t rem, pos = 0;
constexpr const uint32_t sextet_mask = uint32_t(1 << 6) - 1;
const unsigned char *C4_RESTRICT d = (const unsigned char *) data.buf; // cast to unsigned to avoid wrapping high-bits
for(rem = data.len; rem >= 3; rem -= 3, d += 3)
{
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8) | (uint32_t(d[2])));
c4append_idx_((val >> 18) & sextet_mask);
c4append_idx_((val >> 12) & sextet_mask);
c4append_idx_((val >> 6) & sextet_mask);
c4append_idx_((val ) & sextet_mask);
}
C4_ASSERT(rem < 3);
if(rem == 2)
{
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8));
c4append_idx_((val >> 18) & sextet_mask);
c4append_idx_((val >> 12) & sextet_mask);
c4append_idx_((val >> 6) & sextet_mask);
c4append_('=');
}
else if(rem == 1)
{
const uint32_t val = ((uint32_t(d[0]) << 16));
c4append_idx_((val >> 18) & sextet_mask);
c4append_idx_((val >> 12) & sextet_mask);
c4append_('=');
c4append_('=');
}
return pos;
#undef c4append_
#undef c4append_idx_
}
size_t base64_decode(csubstr encoded, blob data)
{
#define c4append_(c) { if(wpos < data.len) { data.buf[wpos] = static_cast<c4::byte>(c); } ++wpos; }
#define c4appendval_(c, shift)\
{\
C4_XASSERT((c) >= 0);\
C4_XASSERT(size_t(c) < sizeof(detail::base64_char_to_sextet_));\
val |= static_cast<uint32_t>(detail::base64_char_to_sextet_[(c)]) << ((shift) * 6);\
}
C4_ASSERT(base64_valid(encoded));
C4_CHECK((encoded.len & 3u) == 0);
size_t wpos = 0; // the write position
const char *C4_RESTRICT d = encoded.str;
constexpr const uint32_t full_byte = 0xff;
// process every quartet of input 6 bits --> triplet of output bytes
for(size_t rpos = 0; rpos < encoded.len; rpos += 4, d += 4)
{
if(d[2] == '=' || d[3] == '=') // skip the last quartet if it is padded
{
C4_ASSERT(d + 4 == encoded.str + encoded.len);
break;
}
uint32_t val = 0;
c4appendval_(d[3], 0);
c4appendval_(d[2], 1);
c4appendval_(d[1], 2);
c4appendval_(d[0], 3);
c4append_((val >> (2 * 8)) & full_byte);
c4append_((val >> (1 * 8)) & full_byte);
c4append_((val ) & full_byte);
}
// deal with the last quartet when it is padded
if(d == encoded.str + encoded.len)
return wpos;
if(d[2] == '=') // 2 padding chars
{
C4_ASSERT(d + 4 == encoded.str + encoded.len);
C4_ASSERT(d[3] == '=');
uint32_t val = 0;
c4appendval_(d[1], 2);
c4appendval_(d[0], 3);
c4append_((val >> (2 * 8)) & full_byte);
}
else if(d[3] == '=') // 1 padding char
{
C4_ASSERT(d + 4 == encoded.str + encoded.len);
uint32_t val = 0;
c4appendval_(d[2], 1);
c4appendval_(d[1], 2);
c4appendval_(d[0], 3);
c4append_((val >> (2 * 8)) & full_byte);
c4append_((val >> (1 * 8)) & full_byte);
}
return wpos;
#undef c4append_
#undef c4appendval_
}
} // namespace c4
// NOLINTEND(bugprone-signed-char-misuse,cert-str34-c,hicpp-signed-bitwise)
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
-234
View File
@@ -1,234 +0,0 @@
#include "c4/error.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define C4_LOGF_ERR(...) (void)fprintf(stderr, __VA_ARGS__); (void)fflush(stderr)
#define C4_LOGF_WARN(...) (void)fprintf(stderr, __VA_ARGS__); (void)fflush(stderr)
#define C4_LOGP(msg, ...) (void)printf(msg)
#if defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
# include "c4/windows.hpp"
#elif defined(C4_PS4)
# include <libdbg.h>
#elif defined(C4_UNIX) || defined(C4_LINUX)
# include <sys/stat.h>
# include <cstring>
# include <fcntl.h>
#elif defined(C4_MACOS) || defined(C4_IOS)
# include <assert.h>
# include <stdbool.h>
# include <sys/types.h>
# include <sys/sysctl.h>
#endif
// the amalgamation tool is dumb and was omitting this include under MACOS.
// So do it only once:
#if defined(C4_UNIX) || defined(C4_LINUX) || defined(C4_MACOS) || defined(C4_IOS)
# include <unistd.h>
#endif
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
# include <exception>
#endif
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wformat-nonliteral"
# pragma clang diagnostic ignored "-Wold-style-cast"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
// NOLINTBEGIN(*use-anonymous-namespace*,cert-dcl50-cpp)
//-----------------------------------------------------------------------------
namespace c4 {
static error_flags s_error_flags = ON_ERROR_DEFAULTS;
static error_callback_type s_error_callback = nullptr;
//-----------------------------------------------------------------------------
error_flags get_error_flags()
{
return s_error_flags;
}
void set_error_flags(error_flags flags)
{
s_error_flags = flags;
}
error_callback_type get_error_callback()
{
return s_error_callback;
}
/** Set the function which is called when an error occurs. */
void set_error_callback(error_callback_type cb)
{
s_error_callback = cb;
}
//-----------------------------------------------------------------------------
void handle_error(srcloc where, const char *fmt, ...)
{
char buf[1024];
size_t msglen = 0;
if(s_error_flags & (ON_ERROR_LOG|ON_ERROR_CALLBACK))
{
va_list args;
va_start(args, fmt);
int ilen = vsnprintf(buf, sizeof(buf), fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized)
va_end(args);
msglen = ilen >= 0 && ilen < (int)sizeof(buf) ? static_cast<size_t>(ilen) : sizeof(buf)-1;
}
if(s_error_flags & ON_ERROR_LOG)
{
C4_LOGF_ERR("\n");
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
C4_LOGF_ERR("%s:%d: ERROR here: %s\n", where.file, where.line, where.func);
#elif defined(C4_ERROR_SHOWS_FILELINE)
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
#elif ! defined(C4_ERROR_SHOWS_FUNC)
C4_LOGF_ERR("ERROR: %s\n", buf);
#endif
}
if(s_error_flags & ON_ERROR_CALLBACK)
{
if(s_error_callback)
{
s_error_callback(buf, msglen);
}
}
if(s_error_flags & ON_ERROR_THROW)
{
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
throw std::runtime_error(buf);
#endif
}
if(s_error_flags & ON_ERROR_ABORT)
{
abort();
}
abort(); // abort anyway, in case nothing was set
C4_UNREACHABLE_AFTER_ERR();
}
//-----------------------------------------------------------------------------
void handle_warning(srcloc where, const char *fmt, ...)
{
va_list args;
char buf[1024];
va_start(args, fmt);
int ret = vsnprintf(buf, sizeof(buf), fmt, args); // NOLINT(clang-analyzer-valist.Uninitialized)
if(ret+1 > (int)sizeof(buf))
buf[sizeof(buf) - 1] = '\0'; // truncate
else if(ret < 0)
buf[0] = '\0'; // output/format error
va_end(args);
C4_LOGF_WARN("\n");
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf);
C4_LOGF_WARN("%s:%d: WARNING: here: %s\n", where.file, where.line, where.func);
#elif defined(C4_ERROR_SHOWS_FILELINE)
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf);
#elif ! defined(C4_ERROR_SHOWS_FUNC)
C4_LOGF_WARN("WARNING: %s\n", buf);
#endif
}
//-----------------------------------------------------------------------------
bool is_debugger_attached()
{
#if defined(C4_UNIX) || defined(C4_LINUX)
static bool first_call = true;
static bool first_call_result = false;
if(first_call)
{
first_call = false;
C4_SUPPRESS_WARNING_GCC_PUSH
#if defined(__GNUC__) && __GNUC__ > 9
C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak")
#endif
//! @see http://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb
//! (this answer: http://stackoverflow.com/a/24969863/3968589 )
char buf[1024] = "";
int status_fd = open("/proc/self/status", O_RDONLY); // NOLINT
if (status_fd == -1)
return false;
ssize_t num_read = ::read(status_fd, buf, sizeof(buf));
if (num_read > 0)
{
static const char TracerPid[] = "TracerPid:";
char *tracer_pid;
if(num_read < 1024)
buf[num_read] = 0;
tracer_pid = strstr(buf, TracerPid);
if(tracer_pid)
first_call_result = !!::atoi(tracer_pid + sizeof(TracerPid) - 1); // NOLINT
}
close(status_fd);
C4_SUPPRESS_WARNING_GCC_POP
}
return first_call_result;
#elif defined(C4_PS4)
return (sceDbgIsDebuggerAttached() != 0);
#elif defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
return IsDebuggerPresent() != 0;
#elif defined(C4_MACOS) || defined(C4_IOS)
// https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
(void)junk;
// We're being debugged if the P_TRACED flag is set.
return ((info.kp_proc.p_flag & P_TRACED) != 0);
#else
return false;
#endif
} // is_debugger_attached()
} // namespace c4
// NOLINTEND(*use-anonymous-namespace*,cert-dcl50-cpp)
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
-64
View File
@@ -1,64 +0,0 @@
#include "c4/format.hpp"
#include <memory> // for std::align
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wformat-nonliteral"
# pragma clang diagnostic ignored "-Wold-style-cast"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
namespace c4 {
size_t to_chars(substr buf, fmt::const_raw_wrapper r)
{
void * vptr = buf.str;
size_t space = buf.len;
char * ptr = (char*) std::align(r.alignment, r.len, vptr, space);
if(ptr == nullptr)
{
// if it was not possible to align, return a conservative estimate
// of the required space
return r.alignment + r.len;
}
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
size_t sz = static_cast<size_t>(ptr - buf.str) + r.len;
if(sz <= buf.len)
{
memcpy(ptr, r.buf, r.len);
}
return sz;
}
bool from_chars(csubstr buf, fmt::raw_wrapper *r)
{
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wcast-qual")
void * vptr = (void*)buf.str;
C4_SUPPRESS_WARNING_GCC_POP
size_t space = buf.len;
char * ptr = (char*) std::align(r->alignment, r->len, vptr, space);
C4_CHECK(ptr != nullptr);
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
C4_SUPPRESS_WARNING_GCC_PUSH
#if defined(__GNUC__) && __GNUC__ > 9
C4_SUPPRESS_WARNING_GCC("-Wanalyzer-null-argument")
#endif
memcpy(r->buf, ptr, r->len);
C4_SUPPRESS_WARNING_GCC_POP
return true;
}
} // namespace c4
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
-16
View File
@@ -1,16 +0,0 @@
#include "c4/language.hpp"
namespace c4 {
namespace detail {
#ifndef __GNUC__
void use_char_pointer(char const volatile* v)
{
C4_UNUSED(v);
}
#else
void foo() {} // to avoid empty file warning from the linker
#endif
} // namespace detail
} // namespace c4
-32
View File
@@ -1,32 +0,0 @@
#include "c4/memory_util.hpp"
#include "c4/error.hpp"
namespace c4 {
/** Fills 'dest' with the first 'pattern_size' bytes at 'pattern', 'num_times'. */
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times)
{
if(C4_UNLIKELY(num_times == 0))
return;
C4_ASSERT( ! mem_overlaps(dest, pattern, num_times*pattern_size, pattern_size));
char *begin = static_cast<char*>(dest);
char *end = begin + num_times * pattern_size;
// copy the pattern once
::memcpy(begin, pattern, pattern_size);
// now copy from dest to itself, doubling up every time
size_t n = pattern_size;
while(begin + 2*n < end)
{
::memcpy(begin + n, begin, n);
n <<= 1u; // double n
}
// copy the missing part
if(begin + n < end)
{
::memcpy(begin + n, begin, static_cast<size_t>(end - (begin + n)));
}
}
} // namespace c4
-114
View File
@@ -1,114 +0,0 @@
#include "c4/utf.hpp"
#include "c4/charconv.hpp"
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, const uint32_t code)
{
C4_ASSERT(buf);
C4_ASSERT(buflen >= 4);
C4_UNUSED(buflen);
if (code <= UINT32_C(0x7f))
{
buf[0] = (uint8_t)code;
return 1u;
}
else if(code <= UINT32_C(0x7ff))
{
buf[0] = (uint8_t)(UINT32_C(0xc0) | (code >> 6u)); /* 110xxxxx */
buf[1] = (uint8_t)(UINT32_C(0x80) | (code & UINT32_C(0x3f))); /* 10xxxxxx */
return 2u;
}
else if(code <= UINT32_C(0xffff))
{
buf[0] = (uint8_t)(UINT32_C(0xe0) | ((code >> 12u))); /* 1110xxxx */
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 6u) & UINT32_C(0x3f))); /* 10xxxxxx */
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
return 3u;
}
else if(code <= UINT32_C(0x10ffff))
{
buf[0] = (uint8_t)(UINT32_C(0xf0) | ((code >> 18u))); /* 11110xxx */
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 12u) & UINT32_C(0x3f))); /* 10xxxxxx */
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code >> 6u) & UINT32_C(0x3f))); /* 10xxxxxx */
buf[3] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
return 4u;
}
return 0;
}
substr decode_code_point(substr out, csubstr code_point)
{
C4_ASSERT(out.len >= 4);
C4_ASSERT(!code_point.begins_with("U+"));
C4_ASSERT(!code_point.begins_with("\\x"));
C4_ASSERT(!code_point.begins_with("\\u"));
C4_ASSERT(!code_point.begins_with("\\U"));
C4_ASSERT(!code_point.begins_with('0'));
C4_ASSERT(code_point.len <= 8);
C4_ASSERT(code_point.len > 0);
uint32_t code_point_val;
C4_CHECK(read_hex(code_point, &code_point_val));
size_t ret = decode_code_point((uint8_t*)out.str, out.len, code_point_val);
C4_ASSERT(ret <= 4);
return out.first(ret);
}
size_t first_non_bom(csubstr s)
{
#define c4check2_(s, c0, c1) ((s).len >= 2) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)))
#define c4check3_(s, c0, c1, c2) ((s).len >= 3) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)) && ((s).str[2] == (c2)))
#define c4check4_(s, c0, c1, c2, c3) ((s).len >= 4) && (((s).str[0] == (c0)) && ((s).str[1] == (c1)) && ((s).str[2] == (c2)) && ((s).str[3] == (c3)))
// see https://en.wikipedia.org/wiki/Byte_order_mark#Byte-order_marks_by_encoding
if(s.len < 2u)
return false;
else if(c4check3_(s, '\xef', '\xbb', '\xbf')) // UTF-8
return 3u;
else if(c4check4_(s, '\x00', '\x00', '\xfe', '\xff')) // UTF-32BE
return 4u;
else if(c4check4_(s, '\xff', '\xfe', '\x00', '\x00')) // UTF-32LE
return 4u;
else if(c4check2_(s, '\xfe', '\xff')) // UTF-16BE
return 2u;
else if(c4check2_(s, '\xff', '\xfe')) // UTF-16BE
return 2u;
else if(c4check3_(s, '\x2b', '\x2f', '\x76')) // UTF-7
return 3u;
else if(c4check3_(s, '\xf7', '\x64', '\x4c')) // UTF-1
return 3u;
else if(c4check4_(s, '\xdd', '\x73', '\x66', '\x73')) // UTF-EBCDIC
return 4u;
else if(c4check3_(s, '\x0e', '\xfe', '\xff')) // SCSU
return 3u;
else if(c4check3_(s, '\xfb', '\xee', '\x28')) // BOCU-1
return 3u;
else if(c4check4_(s, '\x84', '\x31', '\x95', '\x33')) // GB18030
return 4u;
return 0u;
#undef c4check2_
#undef c4check3_
#undef c4check4_
}
substr get_bom(substr s)
{
return s.first(first_non_bom(s));
}
csubstr get_bom(csubstr s)
{
return s.first(first_non_bom(s));
}
substr skip_bom(substr s)
{
return s.sub(first_non_bom(s));
}
csubstr skip_bom(csubstr s)
{
return s.sub(first_non_bom(s));
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
-149
View File
@@ -1,149 +0,0 @@
#include "c4/yml/common.hpp"
#ifndef RYML_NO_DEFAULT_CALLBACKS
# include <stdlib.h>
# include <stdio.h>
# ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
# include <stdexcept>
# endif
#endif // RYML_NO_DEFAULT_CALLBACKS
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702/*unreachable code*/) // on the call to the unreachable macro
namespace {
Callbacks s_default_callbacks;
} // anon namespace
#ifndef RYML_NO_DEFAULT_CALLBACKS
void report_error_impl(const char* msg, size_t length, Location loc, FILE *f)
{
if(!f)
f = stderr;
if(loc)
{
if(!loc.name.empty())
{
// this is more portable than using fprintf("%.*s:") which
// is not available in some embedded platforms
fwrite(loc.name.str, 1, loc.name.len, f); // NOLINT
fputc(':', f); // NOLINT
}
fprintf(f, "%zu:", loc.line); // NOLINT
if(loc.col)
fprintf(f, "%zu:", loc.col); // NOLINT
if(loc.offset)
fprintf(f, " (%zuB):", loc.offset); // NOLINT
fputc(' ', f); // NOLINT
}
RYML_ASSERT(!csubstr(msg, length).ends_with('\0'));
fwrite(msg, 1, length, f); // NOLINT
fputc('\n', f); // NOLINT
fflush(f); // NOLINT
}
[[noreturn]] void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
{
RYML_ASSERT(!csubstr(msg, length).ends_with('\0'));
report_error_impl(msg, length, loc, nullptr);
#ifdef RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS
throw std::runtime_error(std::string(msg, length));
#else
::abort();
#endif
}
void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
{
void *mem = ::malloc(length);
if(mem == nullptr)
{
const char msg[] = "could not allocate memory";
error_impl(msg, sizeof(msg)-1, {}, nullptr);
}
return mem;
}
void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
{
::free(mem);
}
#endif // RYML_NO_DEFAULT_CALLBACKS
Callbacks::Callbacks() noexcept
:
m_user_data(nullptr),
#ifndef RYML_NO_DEFAULT_CALLBACKS
m_allocate(allocate_impl),
m_free(free_impl),
m_error(error_impl)
#else
m_allocate(nullptr),
m_free(nullptr),
m_error(nullptr)
#endif
{
}
Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error error_)
:
m_user_data(user_data),
#ifndef RYML_NO_DEFAULT_CALLBACKS
m_allocate(alloc_ ? alloc_ : allocate_impl),
m_free(free_ ? free_ : free_impl),
m_error((error_ ? error_ : error_impl))
#else
m_allocate(alloc_),
m_free(free_),
m_error(error_)
#endif
{
RYML_CHECK(m_allocate);
RYML_CHECK(m_free);
RYML_CHECK(m_error);
}
void set_callbacks(Callbacks const& c)
{
s_default_callbacks = c;
}
Callbacks const& get_callbacks()
{
return s_default_callbacks;
}
void reset_callbacks()
{
set_callbacks(Callbacks());
}
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
// https://en.cppreference.com/w/cpp/language/attributes/noreturn
[[noreturn]] void error(Callbacks const& cb, const char *msg, size_t msg_len, Location loc)
{
cb.m_error(msg, msg_len, loc, cb.m_user_data);
abort(); // call abort in case the error callback didn't interrupt execution
C4_UNREACHABLE();
}
// the [[noreturn]] attribute needs to be here as well (UB otherwise)
// see https://en.cppreference.com/w/cpp/language/attributes/noreturn
[[noreturn]] void error(const char *msg, size_t msg_len, Location loc)
{
error(s_default_callbacks, msg, msg_len, loc);
C4_UNREACHABLE();
}
C4_SUPPRESS_WARNING_MSVC_POP
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace yml
} // namespace c4
-30
View File
@@ -1,30 +0,0 @@
#include "c4/yml/node.hpp"
namespace c4 {
namespace yml {
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
size_t NodeRef::set_key_serialized(c4::fmt::const_base64_wrapper w)
{
_apply_seed();
csubstr encoded = this->to_arena(w);
this->set_key(encoded);
return encoded.len;
}
size_t NodeRef::set_val_serialized(c4::fmt::const_base64_wrapper w)
{
_apply_seed();
csubstr encoded = this->to_arena(w);
this->set_val(encoded);
return encoded.len;
}
} // namespace yml
} // namespace c4
-215
View File
@@ -1,215 +0,0 @@
#include "c4/yml/node_type.hpp"
namespace c4 {
namespace yml {
const char* NodeType::type_str(NodeType_e ty) noexcept
{
switch(ty & _TYMASK)
{
case KEYVAL:
return "KEYVAL";
case KEY:
return "KEY";
case VAL:
return "VAL";
case MAP:
return "MAP";
case SEQ:
return "SEQ";
case KEYMAP:
return "KEYMAP";
case KEYSEQ:
return "KEYSEQ";
case DOCSEQ:
return "DOCSEQ";
case DOCMAP:
return "DOCMAP";
case DOCVAL:
return "DOCVAL";
case DOC:
return "DOC";
case STREAM:
return "STREAM";
case NOTYPE:
return "NOTYPE";
default:
if((ty & KEYVAL) == KEYVAL)
return "KEYVAL***";
if((ty & KEYMAP) == KEYMAP)
return "KEYMAP***";
if((ty & KEYSEQ) == KEYSEQ)
return "KEYSEQ***";
if((ty & DOCSEQ) == DOCSEQ)
return "DOCSEQ***";
if((ty & DOCMAP) == DOCMAP)
return "DOCMAP***";
if((ty & DOCVAL) == DOCVAL)
return "DOCVAL***";
if(ty & KEY)
return "KEY***";
if(ty & VAL)
return "VAL***";
if(ty & MAP)
return "MAP***";
if(ty & SEQ)
return "SEQ***";
if(ty & DOC)
return "DOC***";
return "(unk)";
}
}
csubstr NodeType::type_str(substr buf, NodeType_e flags) noexcept
{
size_t pos = 0;
bool gotone = false;
#define _prflag(fl, txt) \
do { \
if((flags & (fl)) == (fl)) \
{ \
if(gotone) \
{ \
if(pos + 1 < buf.len) \
buf[pos] = '|'; \
++pos; \
} \
csubstr fltxt = txt; \
if(pos + fltxt.len <= buf.len) \
memcpy(buf.str + pos, fltxt.str, fltxt.len); \
pos += fltxt.len; \
gotone = true; \
flags = (flags & ~(fl)); /*remove the flag*/ \
} \
} while(0)
_prflag(STREAM, "STREAM");
_prflag(DOC, "DOC");
// key properties
_prflag(KEY, "KEY");
_prflag(KEYNIL, "KNIL");
_prflag(KEYTAG, "KTAG");
_prflag(KEYANCH, "KANCH");
_prflag(KEYREF, "KREF");
_prflag(KEY_LITERAL, "KLITERAL");
_prflag(KEY_FOLDED, "KFOLDED");
_prflag(KEY_SQUO, "KSQUO");
_prflag(KEY_DQUO, "KDQUO");
_prflag(KEY_PLAIN, "KPLAIN");
_prflag(KEY_UNFILT, "KUNFILT");
// val properties
_prflag(VAL, "VAL");
_prflag(VALNIL, "VNIL");
_prflag(VALTAG, "VTAG");
_prflag(VALANCH, "VANCH");
_prflag(VALREF, "VREF");
_prflag(VAL_UNFILT, "VUNFILT");
_prflag(VAL_LITERAL, "VLITERAL");
_prflag(VAL_FOLDED, "VFOLDED");
_prflag(VAL_SQUO, "VSQUO");
_prflag(VAL_DQUO, "VDQUO");
_prflag(VAL_PLAIN, "VPLAIN");
_prflag(VAL_UNFILT, "VUNFILT");
// container properties
_prflag(MAP, "MAP");
_prflag(SEQ, "SEQ");
_prflag(FLOW_SL, "FLOWSL");
_prflag(FLOW_ML, "FLOWML");
_prflag(BLOCK, "BLCK");
if(pos == 0)
_prflag(NOTYPE, "NOTYPE");
#undef _prflag
if(pos < buf.len)
{
buf[pos] = '\0';
return buf.first(pos);
}
else
{
csubstr failed;
failed.len = pos + 1;
failed.str = nullptr;
return failed;
}
}
//-----------------------------------------------------------------------------
// see https://www.yaml.info/learn/quote.html#noplain
bool scalar_style_query_squo(csubstr s) noexcept
{
return ! s.first_of_any("\n ", "\n\t");
}
// see https://www.yaml.info/learn/quote.html#noplain
bool scalar_style_query_plain(csubstr s) noexcept
{
if(s.begins_with("-."))
{
if(s == "-.inf" || s == "-.INF")
return true;
else if(s.sub(2).is_number())
return true;
}
else if(s.begins_with_any("0123456789.-+") && s.is_number())
{
return true;
}
return s != ':'
&& ( ! s.begins_with_any("-:?*&,'\"{}[]|>%#@`\r")) // @ and ` are reserved characters
&& ( ! s.ends_with_any(":#"))
// make this check in the last place, as it has linear
// complexity, while the previous ones are
// constant-time
&& (s.first_of("\n#:[]{},") == npos);
}
NodeType_e scalar_style_choose(csubstr s) noexcept
{
if(s.len)
{
if(s.begins_with_any(" \n\t")
||
s.ends_with_any(" \n\t"))
{
return SCALAR_DQUO;
}
else if( ! scalar_style_query_plain(s))
{
return scalar_style_query_squo(s) ? SCALAR_SQUO : SCALAR_DQUO;
}
// nothing remarkable - use plain
return SCALAR_PLAIN;
}
return s.str ? SCALAR_SQUO : SCALAR_PLAIN;
}
NodeType_e scalar_style_json_choose(csubstr s) noexcept
{
// do not quote special cases
bool plain = (
(s == "true" || s == "false" || s == "null")
||
(
// do not quote numbers
s.is_number()
&&
(
// quote integral numbers if they have a leading 0
// https://github.com/biojppm/rapidyaml/issues/291
(!(s.len > 1 && s.begins_with('0')))
// do not quote reals with leading 0
// https://github.com/biojppm/rapidyaml/issues/313
|| (s.find('.') != csubstr::npos)
)
)
);
return plain ? SCALAR_PLAIN : SCALAR_DQUO;
}
} // namespace yml
} // namespace c4
-146
View File
@@ -1,146 +0,0 @@
#include "c4/yml/parse.hpp"
#ifndef _C4_YML_NODE_HPP_
#include "c4/yml/node.hpp"
#endif
#ifndef _C4_YML_PARSE_ENGINE_HPP_
#include "c4/yml/parse_engine.hpp"
#endif
#ifndef _C4_YML_PARSE_ENGINE_DEF_HPP_
#include "c4/yml/parse_engine.def.hpp"
#endif
#ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
#include "c4/yml/event_handler_tree.hpp"
#endif
//-----------------------------------------------------------------------------
namespace c4 {
namespace yml {
// instantiate the parser class
template class ParseEngine<EventHandlerTree>;
namespace {
inline void _reset_tree_handler(Parser *parser, Tree *t, id_type node_id)
{
RYML_ASSERT(parser);
RYML_ASSERT(t);
if(!parser->m_evt_handler)
_RYML_CB_ERR(t->m_callbacks, "event handler is not set");
parser->m_evt_handler->reset(t, node_id);
RYML_ASSERT(parser->m_evt_handler->m_tree == t);
}
} // namespace
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t, id_type node_id)
{
_reset_tree_handler(parser, t, node_id);
parser->parse_in_place_ev(filename, yaml);
}
void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t, id_type node_id)
{
_reset_tree_handler(parser, t, node_id);
parser->parse_json_in_place_ev(filename, json);
}
// this is vertically aligned to highlight the parameter differences.
void parse_in_place(Parser *parser, substr yaml, Tree *t, id_type node_id) { parse_in_place(parser, {}, yaml, t, node_id); }
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *t ) { RYML_CHECK(t); parse_in_place(parser, filename, yaml, t, t->root_id()); }
void parse_in_place(Parser *parser, substr yaml, Tree *t ) { RYML_CHECK(t); parse_in_place(parser, {} , yaml, t, t->root_id()); }
void parse_in_place(Parser *parser, csubstr filename, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_in_place(parser, filename, yaml, node.tree(), node.id()); }
void parse_in_place(Parser *parser, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_in_place(parser, {} , yaml, node.tree(), node.id()); }
Tree parse_in_place(Parser *parser, csubstr filename, substr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_in_place(parser, filename, yaml, &tree, tree.root_id()); return tree; }
Tree parse_in_place(Parser *parser, substr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_in_place(parser, {} , yaml, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_in_place(csubstr filename, substr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, t, node_id); }
void parse_in_place( substr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, t, node_id); }
void parse_in_place(csubstr filename, substr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, t, t->root_id()); }
void parse_in_place( substr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, t, t->root_id()); }
void parse_in_place(csubstr filename, substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, filename, yaml, node.tree(), node.id()); }
void parse_in_place( substr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_in_place(&parser, {} , yaml, node.tree(), node.id()); }
Tree parse_in_place(csubstr filename, substr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_in_place(&parser, filename, yaml, &tree, tree.root_id()); return tree; }
Tree parse_in_place( substr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_in_place(&parser, {} , yaml, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_json_in_place(Parser *parser, substr json, Tree *t, id_type node_id) { parse_json_in_place(parser, {}, json, t, node_id); }
void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *t ) { RYML_CHECK(t); parse_json_in_place(parser, filename, json, t, t->root_id()); }
void parse_json_in_place(Parser *parser, substr json, Tree *t ) { RYML_CHECK(t); parse_json_in_place(parser, {} , json, t, t->root_id()); }
void parse_json_in_place(Parser *parser, csubstr filename, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_json_in_place(parser, filename, json, node.tree(), node.id()); }
void parse_json_in_place(Parser *parser, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); parse_json_in_place(parser, {} , json, node.tree(), node.id()); }
Tree parse_json_in_place(Parser *parser, csubstr filename, substr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_json_in_place(parser, filename, json, &tree, tree.root_id()); return tree; }
Tree parse_json_in_place(Parser *parser, substr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); parse_json_in_place(parser, {} , json, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_json_in_place(csubstr filename, substr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, t, node_id); }
void parse_json_in_place( substr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, t, node_id); }
void parse_json_in_place(csubstr filename, substr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, t, t->root_id()); }
void parse_json_in_place( substr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, t, t->root_id()); }
void parse_json_in_place(csubstr filename, substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, filename, json, node.tree(), node.id()); }
void parse_json_in_place( substr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); parse_json_in_place(&parser, {} , json, node.tree(), node.id()); }
Tree parse_json_in_place(csubstr filename, substr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_json_in_place(&parser, filename, json, &tree, tree.root_id()); return tree; }
Tree parse_json_in_place( substr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); parse_json_in_place(&parser, {} , json, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, filename, src, t, node_id); }
void parse_in_arena(Parser *parser, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, {} , src, t, node_id); }
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, filename, src, t, t->root_id()); }
void parse_in_arena(Parser *parser, csubstr yaml, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(yaml); parse_in_place(parser, {} , src, t, t->root_id()); }
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(parser, filename, src, node.tree(), node.id()); }
void parse_in_arena(Parser *parser, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(parser, {} , src, node.tree(), node.id()); }
Tree parse_in_arena(Parser *parser, csubstr filename, csubstr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(parser, filename, src, &tree, tree.root_id()); return tree; }
Tree parse_in_arena(Parser *parser, csubstr yaml ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(parser, {} , src, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, filename, src, t, node_id); }
void parse_in_arena( csubstr yaml, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, {} , src, t, node_id); }
void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, filename, src, t, t->root_id()); }
void parse_in_arena( csubstr yaml, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(yaml); parse_in_place(&parser, {} , src, t, t->root_id()); }
void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(&parser, filename, src, node.tree(), node.id()); }
void parse_in_arena( csubstr yaml, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(yaml); parse_in_place(&parser, {} , src, node.tree(), node.id()); }
Tree parse_in_arena(csubstr filename, csubstr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(&parser, filename, src, &tree, tree.root_id()); return tree; }
Tree parse_in_arena( csubstr yaml ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(yaml); parse_in_place(&parser, {} , src, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, filename, src, t, node_id); }
void parse_json_in_arena(Parser *parser, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, {} , src, t, node_id); }
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, filename, src, t, t->root_id()); }
void parse_json_in_arena(Parser *parser, csubstr json, Tree *t ) { RYML_CHECK(t); substr src = t->copy_to_arena(json); parse_json_in_place(parser, {} , src, t, t->root_id()); }
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(parser, filename, src, node.tree(), node.id()); }
void parse_json_in_arena(Parser *parser, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(parser, {} , src, node.tree(), node.id()); }
Tree parse_json_in_arena(Parser *parser, csubstr filename, csubstr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(parser, filename, src, &tree, tree.root_id()); return tree; }
Tree parse_json_in_arena(Parser *parser, csubstr json ) { RYML_CHECK(parser); RYML_CHECK(parser->m_evt_handler); Tree tree(parser->callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(parser, {} , src, &tree, tree.root_id()); return tree; }
// this is vertically aligned to highlight the parameter differences.
void parse_json_in_arena(csubstr filename, csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, filename, src, t, node_id); }
void parse_json_in_arena( csubstr json, Tree *t, id_type node_id) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, {} , src, t, node_id); }
void parse_json_in_arena(csubstr filename, csubstr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, filename, src, t, t->root_id()); }
void parse_json_in_arena( csubstr json, Tree *t ) { RYML_CHECK(t); Parser::handler_type event_handler(t->callbacks()); Parser parser(&event_handler); substr src = t->copy_to_arena(json); parse_json_in_place(&parser, {} , src, t, t->root_id()); }
void parse_json_in_arena(csubstr filename, csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(&parser, filename, src, node.tree(), node.id()); }
void parse_json_in_arena( csubstr json, NodeRef node ) { RYML_CHECK(!node.invalid()); Parser::handler_type event_handler(node.tree()->callbacks()); Parser parser(&event_handler); substr src = node.tree()->copy_to_arena(json); parse_json_in_place(&parser, {} , src, node.tree(), node.id()); }
Tree parse_json_in_arena(csubstr filename, csubstr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(&parser, filename, src, &tree, tree.root_id()); return tree; }
Tree parse_json_in_arena( csubstr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(&parser, {} , src, &tree, tree.root_id()); return tree; }
//-----------------------------------------------------------------------------
RYML_EXPORT id_type estimate_tree_capacity(csubstr src)
{
id_type num_nodes = 1; // root
for(size_t i = 0; i < src.len; ++i)
{
const char c = src.str[i];
num_nodes += (c == '\n') || (c == ',') || (c == '[') || (c == '{');
}
return num_nodes;
}
} // namespace yml
} // namespace c4
-112
View File
@@ -1,112 +0,0 @@
#include "c4/yml/preprocess.hpp"
#include "c4/yml/detail/dbgprint.hpp"
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
namespace c4 {
namespace yml {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace {
C4_ALWAYS_INLINE bool _is_idchar(char c)
{
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| (c == '_' || c == '-' || c == '~' || c == '$');
}
enum _ppstate : int { kReadPending = 0, kKeyPending = 1, kValPending = 2 };
C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
{
int n = (int)s + 1;
return (_ppstate)(n <= (int)kValPending ? n : 0);
}
} // empty namespace
//-----------------------------------------------------------------------------
size_t preprocess_rxmap(csubstr s, substr buf)
{
detail::_SubstrWriter writer(buf);
_ppstate state = kReadPending;
size_t last = 0;
if(s.begins_with('{'))
{
RYML_CHECK(s.ends_with('}'));
s = s.offs(1, 1);
}
writer.append('{');
for(size_t i = 0; i < s.len; ++i)
{
const char curr = s[i];
const char next = i+1 < s.len ? s[i+1] : '\0';
if(curr == '\'' || curr == '"')
{
csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
i += static_cast<size_t>(ss.end() - (s.str + i));
state = _next(state);
}
else if(state == kReadPending && _is_idchar(curr))
{
state = _next(state);
}
switch(state)
{
case kKeyPending:
{
if(curr == ':' && next == ' ')
{
state = _next(state);
}
else if(curr == ',' && next == ' ')
{
writer.append(s.range(last, i));
writer.append(": 1, ");
last = i + 2;
}
break;
}
case kValPending:
{
if(curr == '[' || curr == '{' || curr == '(')
{
csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
i += static_cast<size_t>(ss.end() - (s.str + i));
state = _next(state);
}
else if(curr == ',' && next == ' ')
{
state = _next(state);
}
break;
}
default:
// nothing to do
break;
}
}
writer.append(s.sub(last));
if(state == kKeyPending)
writer.append(": 1");
writer.append('}');
return writer.pos;
}
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace yml
} // namespace c4
-333
View File
@@ -1,333 +0,0 @@
#include "c4/yml/reference_resolver.hpp"
#include "c4/yml/common.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#ifdef RYML_DBG
#include "c4/yml/detail/print.hpp"
#else
#define _c4dbg_tree(...)
#define _c4dbg_node(...)
#endif
namespace c4 {
namespace yml {
/** @cond dev */
id_type ReferenceResolver::count_anchors_and_refs_(id_type n)
{
id_type c = 0;
c += m_tree->has_key_anchor(n);
c += m_tree->has_val_anchor(n);
c += m_tree->is_key_ref(n);
c += m_tree->is_val_ref(n);
c += m_tree->has_key(n) && m_tree->key(n) == "<<";
for(id_type ch = m_tree->first_child(n); ch != NONE; ch = m_tree->next_sibling(ch))
c += count_anchors_and_refs_(ch);
return c;
}
void ReferenceResolver::gather_anchors_and_refs__(id_type n)
{
// insert key refs BEFORE inserting val refs
if(m_tree->has_key(n))
{
if(!m_tree->is_key_quoted(n) && m_tree->key(n) == "<<")
{
_c4dbgpf("node[{}]: key is <<", n);
if(m_tree->has_val(n))
{
if(m_tree->is_val_ref(n))
{
_c4dbgpf("node[{}]: instance[{}]: val ref, inheriting! '{}'", n, m_refs.size(), m_tree->val_ref(n));
m_refs.push({VALREF, n, NONE, NONE, NONE, NONE});
//m_refs.push({KEYREF, n, NONE, NONE, NONE, NONE});
}
else
{
_c4dbgpf("node[{}]: not ref!", n);
}
}
else if(m_tree->is_seq(n))
{
// for merging multiple inheritance targets
// <<: [ *CENTER, *BIG ]
_c4dbgpf("node[{}]: is seq!", n);
for(id_type ich = m_tree->first_child(n); ich != NONE; ich = m_tree->next_sibling(ich))
{
_c4dbgpf("node[{}]: instance [{}]: val ref, inheriting multiple: {} '{}'", n, m_refs.size(), ich, m_tree->val_ref(ich));
if(m_tree->is_container(ich))
{
detail::_report_err(m_tree->m_callbacks, "ERROR: node {} child {}: refs for << cannot be containers.'", n, ich);
C4_UNREACHABLE_AFTER_ERR();
}
m_refs.push({VALREF, ich, NONE, NONE, n, m_tree->next_sibling(n)});
}
return; // don't descend into the seq
}
else
{
detail::_report_err(m_tree->m_callbacks, "ERROR: node {}: refs for << must be either val or seq", n);
C4_UNREACHABLE_AFTER_ERR();
}
}
else if(m_tree->is_key_ref(n))
{
_c4dbgpf("node[{}]: instance[{}]: key ref: '{}', key='{}'", n, m_refs.size(), m_tree->key_ref(n), m_tree->has_key(n) ? m_tree->key(n) : csubstr{"-"});
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->key(n) != "<<");
_RYML_CB_CHECK(m_tree->m_callbacks, (!m_tree->has_key(n)) || m_tree->key(n).ends_with(m_tree->key_ref(n)));
m_refs.push({KEYREF, n, NONE, NONE, NONE, NONE});
}
}
// val ref
if(m_tree->is_val_ref(n) && (!m_tree->has_key(n) || m_tree->key(n) != "<<"))
{
_c4dbgpf("node[{}]: instance[{}]: val ref: '{}'", n, m_refs.size(), m_tree->val_ref(n));
RYML_CHECK((!m_tree->has_val(n)) || m_tree->val(n).ends_with(m_tree->val_ref(n)));
m_refs.push({VALREF, n, NONE, NONE, NONE, NONE});
}
// anchors
if(m_tree->has_key_anchor(n))
{
_c4dbgpf("node[{}]: instance[{}]: key anchor: '{}'", n, m_refs.size(), m_tree->key_anchor(n));
RYML_CHECK(m_tree->has_key(n));
m_refs.push({KEYANCH, n, NONE, NONE, NONE, NONE});
}
if(m_tree->has_val_anchor(n))
{
_c4dbgpf("node[{}]: instance[{}]: val anchor: '{}'", n, m_refs.size(), m_tree->val_anchor(n));
RYML_CHECK(m_tree->has_val(n) || m_tree->is_container(n));
m_refs.push({VALANCH, n, NONE, NONE, NONE, NONE});
}
// recurse
for(id_type ch = m_tree->first_child(n); ch != NONE; ch = m_tree->next_sibling(ch))
gather_anchors_and_refs__(ch);
}
void ReferenceResolver::gather_anchors_and_refs_()
{
_c4dbgp("gathering anchors and refs...");
// minimize (re-)allocations by counting first
id_type num_anchors_and_refs = count_anchors_and_refs_(m_tree->root_id());
if(!num_anchors_and_refs)
return;
m_refs.reserve(num_anchors_and_refs);
m_refs.clear();
// now descend through the hierarchy
gather_anchors_and_refs__(m_tree->root_id());
_c4dbgpf("found {} anchors/refs", m_refs.size());
// finally connect the reference list
id_type prev_anchor = NONE;
id_type count = 0;
for(auto &rd : m_refs)
{
rd.prev_anchor = prev_anchor;
if(rd.type.has_anchor())
prev_anchor = count;
++count;
}
_c4dbgp("gathering anchors and refs: finished");
}
id_type ReferenceResolver::lookup_(RefData const* C4_RESTRICT ra)
{
#ifdef RYML_DBG
id_type instance = static_cast<id_type>(ra-m_refs.m_stack);
id_type node = ra->node;
#endif
RYML_ASSERT(ra->type.is_key_ref() || ra->type.is_val_ref());
RYML_ASSERT(ra->type.is_key_ref() != ra->type.is_val_ref());
csubstr refname;
_c4dbgpf("instance[{}:node{}]: lookup from node={}...", instance, node, ra->node);
if(ra->type.is_val_ref())
{
refname = m_tree->val_ref(ra->node);
_c4dbgpf("instance[{}:node{}]: valref: '{}'", instance, node, refname);
}
else
{
RYML_ASSERT(ra->type.is_key_ref());
refname = m_tree->key_ref(ra->node);
_c4dbgpf("instance[{}:node{}]: keyref: '{}'", instance, node, refname);
}
while(ra->prev_anchor != NONE)
{
ra = &m_refs[ra->prev_anchor];
_c4dbgpf("instance[{}:node{}]: lookup '{}' at [{}:node{}]: keyref='{}' valref='{}'", instance, node, refname, ra-m_refs.m_stack, ra->node,
(m_tree->has_key_anchor(ra->node) ? m_tree->key_anchor(ra->node) : csubstr("~")),
(m_tree->has_val_anchor(ra->node) ? m_tree->val_anchor(ra->node) : csubstr("~")));
if(m_tree->has_anchor(ra->node, refname))
{
_c4dbgpf("instance[{}:node{}]: got it at [{}:node{}]!", instance, node, ra-m_refs.m_stack, ra->node);
return ra->node;
}
}
detail::_report_err(m_tree->m_callbacks, "ERROR: anchor not found: '{}'", refname);
C4_UNREACHABLE_AFTER_ERR();
}
void ReferenceResolver::reset_(Tree *t_)
{
if(t_->callbacks() != m_refs.m_callbacks)
{
m_refs.m_callbacks = t_->callbacks();
}
m_tree = t_;
m_refs.clear();
}
void ReferenceResolver::resolve_()
{
/* from the specs: "an alias node refers to the most recent
* node in the serialization having the specified anchor". So
* we need to start looking upward from ref nodes.
*
* @see http://yaml.org/spec/1.2/spec.html#id2765878 */
_c4dbgp("matching anchors/refs...");
for(id_type i = 0, e = m_refs.size(); i < e; ++i)
{
RefData &C4_RESTRICT refdata = m_refs.top(i);
if( ! refdata.type.is_ref())
continue;
refdata.target = lookup_(&refdata);
}
_c4dbgp("matching anchors/refs: finished");
// insert the resolved references
_c4dbgp("modifying tree...");
id_type prev_parent_ref = NONE;
id_type prev_parent_ref_after = NONE;
for(id_type i = 0, e = m_refs.size(); i < e; ++i)
{
RefData const& C4_RESTRICT refdata = m_refs[i];
_c4dbgpf("instance[{}:node{}]: {}/{}...", i, refdata.node, i+1, e);
if( ! refdata.type.is_ref())
continue;
_c4dbgpf("instance[{}:node{}]: is reference!", i, refdata.node);
if(refdata.parent_ref != NONE)
{
_c4dbgpf("instance[{}:node{}] has parent: {}", i, refdata.node, refdata.parent_ref);
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref));
const id_type p = m_tree->parent(refdata.parent_ref);
const id_type after = (prev_parent_ref != refdata.parent_ref) ?
refdata.parent_ref//prev_sibling(rd.parent_ref_sibling)
:
prev_parent_ref_after;
prev_parent_ref = refdata.parent_ref;
prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
m_tree->remove(refdata.node);
}
else
{
_c4dbgpf("instance[{}:node{}] has no parent", i, refdata.node, refdata.parent_ref);
if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) == "<<")
{
_c4dbgpf("instance[{}:node{}] is inheriting", i, refdata.node);
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_keyval(refdata.node));
const id_type p = m_tree->parent(refdata.node);
const id_type after = m_tree->prev_sibling(refdata.node);
_c4dbgpf("instance[{}:node{}] p={} after={}", i, refdata.node, p, after);
m_tree->duplicate_children_no_rep(refdata.target, p, after);
m_tree->remove(refdata.node);
}
else if(refdata.type.is_key_ref())
{
_c4dbgpf("instance[{}:node{}] is key ref", i, refdata.node);
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node));
_RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target));
if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
{
_c4dbgpf("instance[{}:node{}] target.anchor==val.anchor=={}", i, refdata.node, m_tree->val_anchor(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
const type_bits existing_style_flags = VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
static_assert((VAL_STYLE >> 1u) == (KEY_STYLE), "bad flags");
m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
m_tree->_add_flags(refdata.node, KEY | (existing_style_flags >> 1u));
}
else
{
_c4dbgpf("instance[{}:node{}] don't inherit container flags", i, refdata.node);
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
// keys cannot be containers, so don't inherit container flags
const type_bits existing_style_flags = KEY_STYLE & m_tree->_p(refdata.target)->m_type.type;
m_tree->_add_flags(refdata.node, KEY | existing_style_flags);
}
}
else // val ref
{
_c4dbgpf("instance[{}:node{}] is val ref", i, refdata.node);
_RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
{
_c4dbgpf("instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->key_anchor(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
// keys cannot be containers, so don't inherit container flags
const type_bits existing_style_flags = (KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
static_assert((KEY_STYLE << 1u) == (VAL_STYLE), "bad flags");
m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
m_tree->_add_flags(refdata.node, VAL | (existing_style_flags << 1u));
}
else
{
_c4dbgpf("instance[{}:node{}] duplicate contents", i, refdata.node);
m_tree->duplicate_contents(refdata.target, refdata.node);
}
}
}
_c4dbg_tree("after insertion", *m_tree);
}
}
void ReferenceResolver::resolve(Tree *t_, bool clear_anchors)
{
_c4dbgp("resolving references...");
reset_(t_);
_c4dbg_tree("unresolved tree", *m_tree);
gather_anchors_and_refs_();
if(m_refs.empty())
return;
resolve_();
_c4dbg_tree("resolved tree", *m_tree);
// clear anchors and refs
if(clear_anchors)
{
_c4dbgp("clearing anchors/refs");
auto clear_ = [this]{
for(auto const& C4_RESTRICT ar : m_refs)
{
m_tree->rem_anchor_ref(ar.node);
if(ar.parent_ref != NONE)
if(m_tree->type(ar.parent_ref) != NOTYPE)
m_tree->remove(ar.parent_ref);
}
};
clear_();
// some of the elements injected during the resolution may
// have nested anchors; these anchors will have been newly
// injected during the resolution; collect again, and clear
// again, to ensure those are also cleared:
gather_anchors_and_refs_();
clear_();
_c4dbgp("clearing anchors/refs: finished");
}
_c4dbg_tree("final resolved tree", *m_tree);
m_tree = nullptr;
_c4dbgp("resolving references: finished");
}
/** @endcond */
} // namespace ryml
} // namespace c4
-316
View File
@@ -1,316 +0,0 @@
#include "c4/yml/tag.hpp"
#include "c4/yml/detail/dbgprint.hpp"
namespace c4 {
namespace yml {
bool is_custom_tag(csubstr tag)
{
if((tag.len > 2) && (tag.str[0] == '!'))
{
size_t pos = tag.find('!', 1);
return pos != npos && pos > 1 && tag.str[1] != '<';
}
return false;
}
csubstr normalize_tag(csubstr tag)
{
YamlTag_e t = to_tag(tag);
if(t != TAG_NONE)
return from_tag(t);
if(tag.begins_with("!<"))
tag = tag.sub(1);
if(tag.begins_with("<!"))
return tag;
return tag;
}
csubstr normalize_tag_long(csubstr tag)
{
YamlTag_e t = to_tag(tag);
if(t != TAG_NONE)
return from_tag_long(t);
if(tag.begins_with("!<"))
tag = tag.sub(1);
if(tag.begins_with("<!"))
return tag;
return tag;
}
csubstr normalize_tag_long(csubstr tag, substr output)
{
csubstr result = normalize_tag_long(tag);
if(result.begins_with("!!"))
{
tag = tag.sub(2);
const csubstr pfx = "<tag:yaml.org,2002:";
const size_t len = pfx.len + tag.len + 1;
if(len <= output.len)
{
memcpy(output.str , pfx.str, pfx.len);
memcpy(output.str + pfx.len, tag.str, tag.len);
output[pfx.len + tag.len] = '>';
result = output.first(len);
}
else
{
result.str = nullptr;
result.len = len;
}
}
return result;
}
YamlTag_e to_tag(csubstr tag)
{
if(tag.begins_with("!<"))
tag = tag.sub(1);
if(tag.begins_with("!!"))
tag = tag.sub(2);
else if(tag.begins_with('!'))
return TAG_NONE;
else if(tag.begins_with("tag:yaml.org,2002:"))
{
RYML_ASSERT(csubstr("tag:yaml.org,2002:").len == 18);
tag = tag.sub(18);
}
else if(tag.begins_with("<tag:yaml.org,2002:"))
{
RYML_ASSERT(csubstr("<tag:yaml.org,2002:").len == 19);
tag = tag.sub(19);
if(!tag.len)
return TAG_NONE;
tag = tag.offs(0, 1);
}
if(tag == "map")
return TAG_MAP;
else if(tag == "omap")
return TAG_OMAP;
else if(tag == "pairs")
return TAG_PAIRS;
else if(tag == "set")
return TAG_SET;
else if(tag == "seq")
return TAG_SEQ;
else if(tag == "binary")
return TAG_BINARY;
else if(tag == "bool")
return TAG_BOOL;
else if(tag == "float")
return TAG_FLOAT;
else if(tag == "int")
return TAG_INT;
else if(tag == "merge")
return TAG_MERGE;
else if(tag == "null")
return TAG_NULL;
else if(tag == "str")
return TAG_STR;
else if(tag == "timestamp")
return TAG_TIMESTAMP;
else if(tag == "value")
return TAG_VALUE;
else if(tag == "yaml")
return TAG_YAML;
return TAG_NONE;
}
csubstr from_tag_long(YamlTag_e tag)
{
switch(tag)
{
case TAG_MAP:
return {"<tag:yaml.org,2002:map>"};
case TAG_OMAP:
return {"<tag:yaml.org,2002:omap>"};
case TAG_PAIRS:
return {"<tag:yaml.org,2002:pairs>"};
case TAG_SET:
return {"<tag:yaml.org,2002:set>"};
case TAG_SEQ:
return {"<tag:yaml.org,2002:seq>"};
case TAG_BINARY:
return {"<tag:yaml.org,2002:binary>"};
case TAG_BOOL:
return {"<tag:yaml.org,2002:bool>"};
case TAG_FLOAT:
return {"<tag:yaml.org,2002:float>"};
case TAG_INT:
return {"<tag:yaml.org,2002:int>"};
case TAG_MERGE:
return {"<tag:yaml.org,2002:merge>"};
case TAG_NULL:
return {"<tag:yaml.org,2002:null>"};
case TAG_STR:
return {"<tag:yaml.org,2002:str>"};
case TAG_TIMESTAMP:
return {"<tag:yaml.org,2002:timestamp>"};
case TAG_VALUE:
return {"<tag:yaml.org,2002:value>"};
case TAG_YAML:
return {"<tag:yaml.org,2002:yaml>"};
case TAG_NONE:
default:
return {""};
}
}
csubstr from_tag(YamlTag_e tag)
{
switch(tag)
{
case TAG_MAP:
return {"!!map"};
case TAG_OMAP:
return {"!!omap"};
case TAG_PAIRS:
return {"!!pairs"};
case TAG_SET:
return {"!!set"};
case TAG_SEQ:
return {"!!seq"};
case TAG_BINARY:
return {"!!binary"};
case TAG_BOOL:
return {"!!bool"};
case TAG_FLOAT:
return {"!!float"};
case TAG_INT:
return {"!!int"};
case TAG_MERGE:
return {"!!merge"};
case TAG_NULL:
return {"!!null"};
case TAG_STR:
return {"!!str"};
case TAG_TIMESTAMP:
return {"!!timestamp"};
case TAG_VALUE:
return {"!!value"};
case TAG_YAML:
return {"!!yaml"};
case TAG_NONE:
default:
return {""};
}
}
bool TagDirective::create_from_str(csubstr directive_)
{
csubstr directive = directive_;
directive = directive.sub(4);
if(!directive.begins_with(' '))
return false;
directive = directive.triml(' ');
size_t pos = directive.find(' ');
if(pos == npos)
return false;
handle = directive.first(pos);
directive = directive.sub(handle.len).triml(' ');
pos = directive.find(' ');
if(pos != npos)
directive = directive.first(pos);
prefix = directive;
next_node_id = NONE;
_c4dbgpf("%TAG: handle={} prefix={}", handle, prefix);
return true;
}
size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets) const
{
_c4dbgpf("%TAG: handle={} prefix={} next_node={}. tag={}", handle, prefix, next_node_id, tag);
_RYML_CB_ASSERT(callbacks, tag.len >= handle.len);
csubstr rest = tag.sub(handle.len);
_c4dbgpf("%TAG: rest={}", rest);
if(rest.begins_with('<'))
{
_c4dbgpf("%TAG: begins with <. rest={}", rest);
if(C4_UNLIKELY(!rest.ends_with('>')))
_RYML_CB_ERR(callbacks, "malformed tag");
rest = rest.offs(1, 1);
if(rest.begins_with(prefix))
{
_c4dbgpf("%TAG: already transformed! actual={}", rest.sub(prefix.len));
return 0; // return 0 to signal that the tag is local and cannot be resolved
}
}
size_t len = prefix.len + rest.len;
if(with_brackets)
len += 2;
size_t numpc = rest.count('%');
if(numpc == 0)
{
if(len <= output.len)
{
if(with_brackets)
{
output.str[0] = '<';
memcpy(1u + output.str, prefix.str, prefix.len);
memcpy(1u + output.str + prefix.len, rest.str, rest.len);
output.str[1u + prefix.len + rest.len] = '>';
}
else
{
memcpy(output.str, prefix.str, prefix.len);
memcpy(output.str + prefix.len, rest.str, rest.len);
}
}
}
else
{
// need to decode URI % sequences
size_t pos = rest.find('%');
_RYML_CB_ASSERT(callbacks, pos != npos);
do {
size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
if(next == npos)
next = rest.len;
_RYML_CB_CHECK(callbacks, pos+1 < next);
_RYML_CB_CHECK(callbacks, pos+1 + 2 <= next);
size_t delta = next - (pos+1);
len -= delta;
pos = rest.find('%', pos+1);
} while(pos != npos);
if(len <= output.len)
{
size_t prev = 0, wpos = 0;
auto appendstr = [&](csubstr s) { memcpy(output.str + wpos, s.str, s.len); wpos += s.len; };
auto appendchar = [&](char c) { output.str[wpos++] = c; };
if(with_brackets)
appendchar('<');
appendstr(prefix);
pos = rest.find('%');
_RYML_CB_ASSERT(callbacks, pos != npos);
do {
size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);
if(next == npos)
next = rest.len;
_RYML_CB_CHECK(callbacks, pos+1 < next);
_RYML_CB_CHECK(callbacks, pos+1 + 2 <= next);
uint8_t val;
if(C4_UNLIKELY(!read_hex(rest.range(pos+1, next), &val) || val > 127))
_RYML_CB_ERR(callbacks, "invalid URI character");
appendstr(rest.range(prev, pos));
appendchar(static_cast<char>(val));
prev = next;
pos = rest.find('%', pos+1);
} while(pos != npos);
_RYML_CB_ASSERT(callbacks, pos == npos);
_RYML_CB_ASSERT(callbacks, prev > 0);
_RYML_CB_ASSERT(callbacks, rest.len >= prev);
appendstr(rest.sub(prev));
if(with_brackets)
appendchar('>');
_RYML_CB_ASSERT(callbacks, wpos == len);
}
}
return len;
}
} // namespace yml
} // namespace c4
File diff suppressed because it is too large Load Diff
-27
View File
@@ -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
-42
View File
@@ -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}
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -211,7 +211,7 @@ target_link_libraries(common PRIVATE
target_link_libraries(common PUBLIC
fmt::fmt
fast_float
rapidyaml::rapidyaml
ryml::ryml
)
fixup_file_properties(common)
+46 -1
View File
@@ -3,8 +3,11 @@
#include "YAML.h"
#include "Assertions.h"
#include "c4/yml/error.def.hpp" // for ryml::err_basic_format etc
#include <csetjmp>
#include <cstdlib>
struct RapidYAMLContext
{
@@ -18,6 +21,47 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
context.error = error;
ryml::Callbacks callbacks;
#if RYML_VERSION_MAJOR > 0 || RYML_VERSION_MINOR >= 11
callbacks.set_user_data(static_cast<void*>(&context));
callbacks.set_error_basic([](ryml::csubstr msg, const ryml::ErrorDataBasic& errdata, void* user_data) {
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_basic_format(std::move(callback), msg, errdata);
// We might have already returned, so don't try to recover.
pxFailRel(description.c_str());
std::abort();
});
callbacks.set_error_parse([](ryml::csubstr msg, const ryml::ErrorDataParse& errdata, void* user_data) {
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_parse_format(std::move(callback), msg, errdata);
Error::SetString(context->error, std::move(description));
std::longjmp(context->env, 1);
});
callbacks.set_error_visit([](ryml::csubstr msg, const ryml::ErrorDataVisit& errdata, void* user_data) {
std::string description;
auto callback = [&description](ryml::csubstr string) {
description.append(string.str, string.len);
};
ryml::err_visit_format(std::move(callback), msg, errdata);
// We've probably already returned, so don't try to recover.
pxFailRel(description.c_str());
std::abort();
});
#else
callbacks.m_user_data = static_cast<void*>(&context);
callbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location location, void* user_data) {
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
@@ -25,6 +69,7 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
Error::SetString(context->error, std::string(msg, msg_len));
std::longjmp(context->env, 1);
};
#endif
ryml::EventHandlerTree event_handler(callbacks);
ryml::Parser parser(&event_handler);
+1 -2
View File
@@ -5,9 +5,8 @@
#include "Error.h"
#include "ryml.hpp"
#include "ryml_std.hpp"
#include "ryml.hpp"
#include "ryml.hpp"
#include <optional>
-1
View File
@@ -36,7 +36,6 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ForcedIncludeFiles>PrecompiledHeader.h</ForcedIncludeFiles>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
+2 -1
View File
@@ -4,7 +4,7 @@
<ItemDefinitionGroup>
<Link>
<AdditionalLibraryDirectories>$(DepsLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;z.lib;zstd.lib;plutovg.lib;plutosvg.lib;ryml.lib</AdditionalDependencies>
<AdditionalDependencies Condition="$(Configuration.Contains(Debug))">%(AdditionalDependencies);kddockwidgets-qt6d.lib;</AdditionalDependencies>
<AdditionalDependencies Condition="!$(Configuration.Contains(Debug))">%(AdditionalDependencies);kddockwidgets-qt6.lib;</AdditionalDependencies>
</Link>
@@ -27,6 +27,7 @@
<DepsDLLs Condition="!$(Configuration.Contains(Debug))" Include="$(DepsBinDir)kddockwidgets-qt6.dll" />
<DepsDLLs Include="$(DepsBinDir)plutovg.dll" />
<DepsDLLs Include="$(DepsBinDir)plutosvg.dll" />
<DepsDLLs Include="$(DepsBinDir)ryml.dll" />
<DepsDLLs Condition="Exists('$(DepsBinDir)avcodec-62.dll')" Include="$(DepsBinDir)avcodec-62.dll" />
<DepsDLLs Condition="Exists('$(DepsBinDir)avformat-62.dll')" Include="$(DepsBinDir)avformat-62.dll" />
<DepsDLLs Condition="Exists('$(DepsBinDir)avutil-60.dll')" Include="$(DepsBinDir)avutil-60.dll" />
+1 -1
View File
@@ -1310,7 +1310,7 @@ function(setup_main_executable target)
# Copy dependency libraries.
set(DEPS_BINDIR "${CMAKE_SOURCE_DIR}/deps/bin")
set(DEPS_TO_COPY freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll libsharpyuv.dll libwebp.dll libwebpdemux.dll libwebpmux.dll lz4.dll SDL3.dll shaderc_shared.dll z.dll zstd.dll plutovg.dll plutosvg.dll)
set(DEPS_TO_COPY freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll libsharpyuv.dll libwebp.dll libwebpdemux.dll libwebpmux.dll lz4.dll SDL3.dll shaderc_shared.dll z.dll zstd.dll plutovg.dll plutosvg.dll ryml.dll)
set(DEPS_TO_COPY
$<IF:$<CONFIG:Debug>,kddockwidgets-qt6d.dll,kddockwidgets-qt6.dll>
${DEPS_TO_COPY}
-2
View File
@@ -17,8 +17,6 @@
#include "common/YAML.h"
#include <sstream>
#include "ryml_std.hpp"
#include "ryml.hpp"
#include "fmt/format.h"
#include "fmt/ranges.h"
#include <fstream>
-4
View File
@@ -43,7 +43,6 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\simpleini\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libzip\msvc;$(SolutionDir)3rdparty\libzip\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\cpuinfo\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fast_float\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rcheevos\include;$(SolutionDir)3rdparty\rainterface</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\soundtouch\soundtouch</AdditionalIncludeDirectories>
@@ -983,9 +982,6 @@
<ProjectReference Include="$(SolutionDir)3rdparty\cubeb\cubeb.vcxproj">
<Project>{bf74c473-dc04-44b3-92e8-4145f4e77342}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\rapidyaml\rapidyaml.vcxproj">
<Project>{de9653b6-17dd-356a-9ee0-28a731772587}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
</ProjectReference>