diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000..446ebd009 --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +test/googletest-1.13.0 diff --git a/.codedocs b/.codedocs index 02e438213..ae63822d2 100644 --- a/.codedocs +++ b/.codedocs @@ -8,7 +8,7 @@ EXAMPLE_PATH = # One or more directories and files to exclude from documentation generation. # Use relative paths with respect to the repository root directory. -EXCLUDE = test/gtest-1.8.0/ +EXCLUDE = test/googletest-1.13.0/ # One or more wildcard patterns to exclude files and directories from document # generation. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..dc2380610 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + groups: + github-actions: + patterns: + - "*" + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..5c7614bd1 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,141 @@ +name: Github PR +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: +permissions: read-all +defaults: + run: + shell: bash +jobs: + cmake-build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + cxx_standard: [11, 17, 20] + build: [static, shared] + googletest: [build, system] + generator: ["Default Generator", "MinGW Makefiles"] + exclude: + - os: ubuntu-latest + cxx_standard: 11 + googletest: system + - os: macos-latest + build: shared + - os: macos-latest + generator: "MinGW Makefiles" + - os: ubuntu-latest + generator: "MinGW Makefiles" + - os: macos-latest + googletest: system + - os: windows-latest + googletest: system + env: + YAML_BUILD_SHARED_LIBS: ${{ matrix.build == 'shared' && 'ON' || 'OFF' }} + YAML_USE_SYSTEM_GTEST: ${{ matrix.googletest == 'system' && 'ON' || 'OFF' }} + CMAKE_GENERATOR: >- + ${{format(matrix.generator != 'Default Generator' && '-G "{0}"' || '', matrix.generator)}} + CMAKE_INSTALL_PREFIX: "${{ github.workspace }}/install-prefix" + CMAKE_BUILD_TYPE: Debug + CMAKE_CXX_FLAGS_DEBUG: ${{ matrix.googletest == 'build' && '-g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC' || '-g' }} + runs-on: ${{ matrix.os }} + steps: + + - uses: awalsh128/cache-apt-pkgs-action@latest + if: matrix.os == 'ubuntu-latest' + with: + packages: googletest libgmock-dev libgtest-dev + version: 1.0 + + - uses: actions/checkout@v6.0.2 + + - name: Configure + run: | + cmake \ + ${{ env.CMAKE_GENERATOR }} \ + -S "${{ github.workspace }}" \ + -B build \ + -D CMAKE_CXX_STANDARD=${{ matrix.cxx_standard }} \ + -D CMAKE_INSTALL_PREFIX="${{ env.CMAKE_INSTALL_PREFIX }}" \ + -D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \ + -D CMAKE_CXX_FLAGS_DEBUG="${{ env.CMAKE_CXX_FLAGS_DEBUG }}" \ + -D YAML_BUILD_SHARED_LIBS=${{ env.YAML_BUILD_SHARED_LIBS }} \ + -D YAML_USE_SYSTEM_GTEST=${{ env.YAML_USE_SYSTEM_GTEST }} \ + -D YAML_CPP_BUILD_TESTS=ON + + - name: Build + run: | + cmake \ + --build build \ + --config ${{ env.CMAKE_BUILD_TYPE }} \ + --verbose \ + --parallel + + - name: Run Tests + shell: bash + run: | + ctest \ + --test-dir build \ + --build-config ${{ env.CMAKE_BUILD_TYPE }} \ + --output-on-failure \ + --verbose + + - name: Install + run: cmake --install build --config ${{ env.CMAKE_BUILD_TYPE }} + + - name: Configure CMake package test + run: | + cmake \ + ${{ env.CMAKE_GENERATOR }} \ + -S "${{ github.workspace }}/test/cmake" \ + -B consumer-build \ + -D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \ + -D CMAKE_PREFIX_PATH="${{ env.CMAKE_INSTALL_PREFIX }}" + + - name: Build CMake package test + run: | + cmake \ + --build consumer-build \ + --config ${{ env.CMAKE_BUILD_TYPE }} \ + --verbose + + bazel-build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6.0.2 + + - name: Build + run: | + cd "${{ github.workspace }}" + bazel build :all + + - name: Test + run: | + cd "${{ github.workspace }}" + bazel test test + + bzlmod-build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6.0.2 + + - name: Build + shell: bash + run: | + cd "${{ github.workspace }}" + bazel build --enable_bzlmod :all + + - name: Test + shell: bash + run: | + cd "${{ github.workspace }}" + bazel test --enable_bzlmod test diff --git a/.github/workflows/bzlmod-archive.yml b/.github/workflows/bzlmod-archive.yml new file mode 100644 index 000000000..1b07d82ce --- /dev/null +++ b/.github/workflows/bzlmod-archive.yml @@ -0,0 +1,19 @@ +name: Bazel Release + +on: + release: + types: [published] + +jobs: + # A release archive is required for bzlmod + # See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html + bazel-release-archive: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.1 + - run: git archive $GITHUB_REF -o "yaml-cpp-${GITHUB_REF:10}.tar.gz" + - run: gh release upload ${GITHUB_REF:10} "yaml-cpp-${GITHUB_REF:10}.tar.gz" + env: + GH_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 567609b12..2f9d10f06 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ build/ +/tags +/bazel-* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d0b6a04ef..000000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: c++ -os: - - linux - - osx -compiler: - - clang - - gcc -before_install: - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y \ - && sudo apt-get update -qq \ - && if [ "$CXX" == "g++" ]; then - sudo apt-get install -qq g++-4.7 && export CXX="g++-4.7" CC="gcc-4.7" - fi - fi -before_script: - - mkdir build - - cd build - - cmake .. -script: - - make - - test/run-tests - -matrix: - exclude: - - os: linux - compiler: clang diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..45ae375ee --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,23 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +yaml_cpp_defines = select({ + # On Windows, ensure static linking is used. + "@platforms//os:windows": ["YAML_CPP_STATIC_DEFINE", "YAML_CPP_NO_CONTRIB"], + "//conditions:default": [], +}) + +cc_library( + name = "yaml-cpp_internal", + visibility = ["//:__subpackages__"], + strip_include_prefix = "src", + hdrs = glob(["src/**/*.h"]), +) + +cc_library( + name = "yaml-cpp", + visibility = ["//visibility:public"], + includes = ["include"], + hdrs = glob(["include/**/*.h"]), + srcs = glob(["src/**/*.cpp", "src/**/*.h"]), + defines = yaml_cpp_defines, +) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fc29cbe1..0df533a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,365 +1,213 @@ -### -### CMake settings -### -## Due to Mac OSX we need to keep compatibility with CMake 2.6 -# see http://www.cmake.org/Wiki/CMake_Policies -cmake_minimum_required(VERSION 2.6) -# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0012 -if(POLICY CMP0012) - cmake_policy(SET CMP0012 OLD) -endif() -# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0015 -if(POLICY CMP0015) - cmake_policy(SET CMP0015 OLD) -endif() -# see https://cmake.org/cmake/help/latest/policy/CMP0042.html -if(POLICY CMP0042) - # Enable MACOSX_RPATH by default. - cmake_policy(SET CMP0042 NEW) -endif() - -include(CheckCXXCompilerFlag) - +# 3.5 is actually available almost everywhere. +# 3.30 as the upper policy limit avoids CMake deprecation warnings. +cmake_minimum_required(VERSION 3.5...3.30) -### -### Project settings -### -project(YAML_CPP) +# enable MSVC_RUNTIME_LIBRARY target property +# see https://cmake.org/cmake/help/latest/policy/CMP0091.html +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif() -set(YAML_CPP_VERSION_MAJOR "0") -set(YAML_CPP_VERSION_MINOR "5") -set(YAML_CPP_VERSION_PATCH "3") -set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") +project(YAML_CPP VERSION 0.8.0 LANGUAGES CXX) -enable_testing() +set(YAML_CPP_MAIN_PROJECT OFF) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + set(YAML_CPP_MAIN_PROJECT ON) +endif() +include(CMakePackageConfigHelpers) +include(CMakeDependentOption) +include(CheckCXXCompilerFlag) +include(GNUInstallDirs) +include(CTest) -### -### Project options -### -## Project stuff -option(YAML_CPP_BUILD_TESTS "Enable testing" ON) +option(YAML_CPP_BUILD_CONTRIB "Enable yaml-cpp contrib in library" ON) option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON) -option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) - -## Build options -# --> General -# see http://www.cmake.org/cmake/help/cmake2.6docs.html#variable:BUILD_SHARED_LIBS -# http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_library -option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) - -# --> Apple -option(APPLE_UNIVERSAL_BIN "Apple: Build universal binary" OFF) - -# --> Microsoft Visual C++ -# see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx -# http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx -option(MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON) -option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs (/ML until VS .NET 2003)" OFF) - -### -### Sources, headers, directories and libs -### - -# From http://www.cmake.org/pipermail/cmake/2010-March/035992.html: -# function to collect all the sources from sub-directories -# into a single list -function(add_sources) - get_property(is_defined GLOBAL PROPERTY SRCS_LIST DEFINED) - if(NOT is_defined) - define_property(GLOBAL PROPERTY SRCS_LIST - BRIEF_DOCS "List of source files" - FULL_DOCS "List of all source files in the entire project") - endif() - # make absolute paths - set(SRCS) - foreach(s IN LISTS ARGN) - if(NOT IS_ABSOLUTE "${s}") - get_filename_component(s "${s}" ABSOLUTE) - endif() - list(APPEND SRCS "${s}") - endforeach() - # append to global list - set_property(GLOBAL APPEND PROPERTY SRCS_LIST "${SRCS}") -endfunction(add_sources) - -set(header_directory "include/yaml-cpp/") - -file(GLOB sources "src/[a-zA-Z]*.cpp") -file(GLOB_RECURSE public_headers "include/yaml-cpp/[a-zA-Z]*.h") -file(GLOB private_headers "src/[a-zA-Z]*.h") - -if(YAML_CPP_BUILD_CONTRIB) - file(GLOB contrib_sources "src/contrib/[a-zA-Z]*.cpp") - file(GLOB contrib_public_headers "include/yaml-cpp/contrib/[a-zA-Z]*.h") - file(GLOB contrib_private_headers "src/contrib/[a-zA-Z]*.h") +option(YAML_BUILD_SHARED_LIBS "Build yaml-cpp shared library" ${BUILD_SHARED_LIBS}) +option(YAML_CPP_INSTALL "Enable generation of yaml-cpp install targets" ${YAML_CPP_MAIN_PROJECT}) +option(YAML_CPP_FORMAT_SOURCE "Format source" ${YAML_CPP_MAIN_PROJECT}) +option(YAML_CPP_DISABLE_UNINSTALL "Disable uninstallation of yaml-cpp" OFF) +option(YAML_USE_SYSTEM_GTEST "Use system googletest if found" OFF) +option(YAML_ENABLE_PIC "Use Position-Independent Code " ON) + +cmake_dependent_option(YAML_CPP_BUILD_TESTS + "Enable yaml-cpp tests" OFF + "BUILD_TESTING;YAML_CPP_MAIN_PROJECT" OFF) +cmake_dependent_option(YAML_MSVC_SHARED_RT + "MSVC: Build yaml-cpp with shared runtime libs (/MD)" ON + "CMAKE_SYSTEM_NAME MATCHES Windows" OFF) +set(YAML_CPP_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/yaml-cpp" + CACHE STRING "Path to install the CMake package to") + +if (YAML_CPP_FORMAT_SOURCE) + find_program(YAML_CPP_CLANG_FORMAT_EXE NAMES clang-format) +endif() + +if (YAML_BUILD_SHARED_LIBS) + set(yaml-cpp-type SHARED) + set(yaml-cpp-label-postfix "shared") else() - add_definitions(-DYAML_CPP_NO_CONTRIB) + set(yaml-cpp-type STATIC) + set(yaml-cpp-label-postfix "static") endif() -set(library_sources - ${sources} - ${public_headers} - ${private_headers} - ${contrib_sources} - ${contrib_public_headers} - ${contrib_private_headers} -) -add_sources(${library_sources}) - -if(VERBOSE) - message(STATUS "sources: ${sources}") - message(STATUS "public_headers: ${public_headers}") - message(STATUS "private_headers: ${private_headers}") - message(STATUS "contrib_sources: ${contrib_sources}") - message(STATUS "contrib_public_headers: ${contrib_public_headers}") - message(STATUS "contrib_private_headers: ${contrib_private_headers}") +set(build-shared $) +set(build-windows-dll $,${build-shared}>) +set(not-msvc $>) +set(msvc-shared_rt $) + +if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY + MultiThreaded$<$:Debug>$<${msvc-shared_rt}:DLL>) endif() -include_directories(${YAML_CPP_SOURCE_DIR}/src) -include_directories(${YAML_CPP_SOURCE_DIR}/include) +set(contrib-pattern "src/contrib/*.cpp") +set(src-pattern "src/*.cpp") +if (CMAKE_VERSION VERSION_GREATER 3.12) + list(INSERT contrib-pattern 0 CONFIGURE_DEPENDS) + list(INSERT src-pattern 0 CONFIGURE_DEPENDS) +endif() +file(GLOB yaml-cpp-contrib-sources ${contrib-pattern}) +file(GLOB yaml-cpp-sources ${src-pattern}) +set(msvc-rt $) -### -### General compilation settings -### -set(yaml_c_flags ${CMAKE_C_FLAGS}) -set(yaml_cxx_flags ${CMAKE_CXX_FLAGS}) +set(msvc-rt-mtd-static $) +set(msvc-rt-mt-static $) -if(BUILD_SHARED_LIBS) - set(LABEL_SUFFIX "shared") -else() - set(LABEL_SUFFIX "static") -endif() +set(msvc-rt-mtd-dll $) +set(msvc-rt-mt-dll $) -if(APPLE) - if(APPLE_UNIVERSAL_BIN) - set(CMAKE_OSX_ARCHITECTURES ppc;i386) - endif() -endif() +set(backport-msvc-runtime $) -if(IPHONE) - set(CMAKE_OSX_SYSROOT "iphoneos4.2") - set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") -endif() +add_library(yaml-cpp ${yaml-cpp-type} "") +add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp) -if(WIN32) - if(BUILD_SHARED_LIBS) - add_definitions(-D${PROJECT_NAME}_DLL) # use or build Windows DLL - endif() - if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "C:/") - endif() -endif() +set_property(TARGET yaml-cpp + PROPERTY + MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}) +set_property(TARGET yaml-cpp + PROPERTY + CXX_STANDARD_REQUIRED ON) -# GCC or Clang or Intel Compiler specialities -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR - CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR - CMAKE_CXX_COMPILER_ID MATCHES "Intel") - - ### General stuff - if(WIN32) - set(CMAKE_SHARED_LIBRARY_PREFIX "") # DLLs do not have a "lib" prefix - set(CMAKE_IMPORT_LIBRARY_PREFIX "") # same for DLL import libs - set(CMAKE_LINK_DEF_FILE_FLAG "") # CMake workaround (2.8.3) - endif() - - ### Project stuff - if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) - endif() - # - set(CMAKE_CXX_FLAGS_RELEASE "-O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") - set(CMAKE_CXX_FLAGS_DEBUG "-g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") - # - set(GCC_EXTRA_OPTIONS "") - # - if(BUILD_SHARED_LIBS) - set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} -fPIC") - endif() - # - set(FLAG_TESTED "-Wextra") - check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) - if(FLAG_WEXTRA) - set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") - endif() - # - set(yaml_cxx_flags "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long -std=c++11 ${yaml_cxx_flags}") - - ### Make specific - if(${CMAKE_BUILD_TOOL} MATCHES make OR ${CMAKE_BUILD_TOOL} MATCHES gmake) - add_custom_target(debuggable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for debug compilation" - VERBATIM) - add_custom_target(releasable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for release compilation" - VERBATIM) - endif() +if (NOT YAML_BUILD_SHARED_LIBS) + set_property(TARGET yaml-cpp PROPERTY POSITION_INDEPENDENT_CODE ${YAML_ENABLE_PIC}) endif() -# Microsoft VisualC++ specialities -if(MSVC) - ### General stuff - # a) Change MSVC runtime library settings (/MD[d], /MT[d], /ML[d] (single-threaded until VS 2003)) - # plus set lib suffix for later use and project label accordingly - # see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx - # http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx - set(LIB_RT_SUFFIX "md") # CMake defaults to /MD for MSVC - set(LIB_RT_OPTION "/MD") - # - if(NOT MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML) - if(MSVC_STHREADED_RT) # User wants to have old single-threaded static runtime libraries - set(LIB_RT_SUFFIX "ml") - set(LIB_RT_OPTION "/ML") - if(NOT ${MSVC_VERSION} LESS 1400) - message(FATAL_ERROR "Single-threaded static runtime libraries (/ML) only available until VS .NET 2003 (7.1).") - endif() - else() - set(LIB_RT_SUFFIX "mt") - set(LIB_RT_OPTION "/MT") - endif() - - # correct linker options - foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) - set(var_name "${flag_var}") - if(NOT "${config_name}" STREQUAL "") - set(var_name "${var_name}_${config_name}") - endif() - string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}") - set(${var_name} "${${var_name}}" CACHE STRING "" FORCE) - endforeach() - endforeach() - endif() - # - set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_SUFFIX}") - - # b) Change prefix for static libraries - set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs - - # c) Correct suffixes for static libraries - if(NOT BUILD_SHARED_LIBS) - ### General stuff - set(LIB_TARGET_SUFFIX "${LIB_SUFFIX}${LIB_RT_SUFFIX}") - endif() - - ### Project stuff - # /W3 = set warning level; see http://msdn.microsoft.com/en-us/library/thxezb7y.aspx - # /wd4127 = disable warning C4127 "conditional expression is constant"; see http://msdn.microsoft.com/en-us/library/6t66728h.aspx - # /wd4355 = disable warning C4355 "'this' : used in base member initializer list"; http://msdn.microsoft.com/en-us/library/3c594ae3.aspx - set(yaml_cxx_flags "/W3 /wd4127 /wd4355 ${yaml_cxx_flags}") +target_include_directories(yaml-cpp + PUBLIC + $ + $ + PRIVATE + $) + +if (NOT DEFINED CMAKE_CXX_STANDARD) + set_target_properties(yaml-cpp + PROPERTIES + CXX_STANDARD 11) endif() +if(YAML_CPP_MAIN_PROJECT) + target_compile_options(yaml-cpp + PRIVATE + $<${not-msvc}:-Wall -Wextra -Wshadow -Weffc++ -Wno-long-long> + $<${not-msvc}:-pedantic -pedantic-errors>) +endif() -### -### General install settings -### -set(INCLUDE_INSTALL_ROOT_DIR include) +target_compile_options(yaml-cpp + PRIVATE + $<$:-MTd> + $<$:-MT> + $<$:-MDd> + $<$:-MD> -set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_ROOT_DIR}/yaml-cpp) -set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") + # /wd4127 = disable warning C4127 "conditional expression is constant" + # http://msdn.microsoft.com/en-us/library/6t66728h.aspx + # /wd4355 = disable warning C4355 "'this' : used in base member initializer list + # http://msdn.microsoft.com/en-us/library/3c594ae3.aspx + $<$:/W3 /wd4127 /wd4355>) -set(_INSTALL_DESTINATIONS - RUNTIME DESTINATION bin - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} -) +target_compile_definitions(yaml-cpp + PUBLIC + $<$>:YAML_CPP_STATIC_DEFINE> + PRIVATE + $<${build-windows-dll}:${PROJECT_NAME}_DLL> + $<$>:YAML_CPP_NO_CONTRIB>) +target_sources(yaml-cpp + PRIVATE + $<$:${yaml-cpp-contrib-sources}> + ${yaml-cpp-sources}) -### -### Library -### -add_library(yaml-cpp ${library_sources}) -set_target_properties(yaml-cpp PROPERTIES - COMPILE_FLAGS "${yaml_c_flags} ${yaml_cxx_flags}" -) +if (NOT DEFINED CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "d") +endif() set_target_properties(yaml-cpp PROPERTIES - VERSION "${YAML_CPP_VERSION}" - SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" - PROJECT_LABEL "yaml-cpp ${LABEL_SUFFIX}" -) - -if(IPHONE) - set_target_properties(yaml-cpp PROPERTIES - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0" - ) + VERSION "${PROJECT_VERSION}" + SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" + PROJECT_LABEL "yaml-cpp ${yaml-cpp-label-postfix}" + DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") + +set(EXPORT_TARGETS yaml-cpp::yaml-cpp) +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/yaml-cpp-config.cmake.in" + "${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake" + INSTALL_DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}" + PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR) +unset(EXPORT_TARGETS) + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" + COMPATIBILITY AnyNewerVersion) + +configure_file(yaml-cpp.pc.in yaml-cpp.pc @ONLY) + +if (YAML_CPP_INSTALL) + install(TARGETS yaml-cpp + EXPORT yaml-cpp-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h") + install(EXPORT yaml-cpp-targets + NAMESPACE yaml-cpp:: + DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}") + install(FILES + "${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake" + "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" + DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}") + install(FILES "${PROJECT_BINARY_DIR}/yaml-cpp.pc" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) endif() -if(MSVC) - if(NOT BUILD_SHARED_LIBS) - # correct library names - set_target_properties(yaml-cpp PROPERTIES - DEBUG_POSTFIX "${LIB_TARGET_SUFFIX}d" - RELEASE_POSTFIX "${LIB_TARGET_SUFFIX}" - MINSIZEREL_POSTFIX "${LIB_TARGET_SUFFIX}" - RELWITHDEBINFO_POSTFIX "${LIB_TARGET_SUFFIX}" - ) - endif() +if(YAML_CPP_BUILD_TESTS) + add_subdirectory(test) endif() -install(TARGETS yaml-cpp EXPORT yaml-cpp-targets ${_INSTALL_DESTINATIONS}) -install( - DIRECTORY ${header_directory} - DESTINATION ${INCLUDE_INSTALL_DIR} - FILES_MATCHING PATTERN "*.h" -) - -export( - TARGETS yaml-cpp - FILE "${PROJECT_BINARY_DIR}/yaml-cpp-targets.cmake") -export(PACKAGE yaml-cpp) -set(EXPORT_TARGETS yaml-cpp CACHE INTERNAL "export targets") - -set(CONFIG_INCLUDE_DIRS "${YAML_CPP_SOURCE_DIR}/include") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config.cmake.in - "${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake" @ONLY) - -if(WIN32 AND NOT CYGWIN) - set(INSTALL_CMAKE_DIR CMake) -else() - set(INSTALL_CMAKE_DIR ${LIB_INSTALL_DIR}/cmake/yaml-cpp) +if(YAML_CPP_BUILD_TOOLS) + add_subdirectory(util) endif() -file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_ROOT_DIR}") -set(CONFIG_INCLUDE_DIRS "\${YAML_CPP_CMAKE_DIR}/${REL_INCLUDE_DIR}") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config.cmake.in - "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/yaml-cpp-config.cmake" @ONLY) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config-version.cmake.in - "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" @ONLY) - -install(FILES - "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/yaml-cpp-config.cmake" - "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) -install(EXPORT yaml-cpp-targets DESTINATION ${INSTALL_CMAKE_DIR}) - -if(UNIX) - set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) - configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) - install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +if (YAML_CPP_FORMAT_SOURCE AND YAML_CPP_CLANG_FORMAT_EXE) + add_custom_target(format + COMMAND clang-format --style=file -i $ + COMMAND_EXPAND_LISTS + COMMENT "Running clang-format" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + VERBATIM) endif() +# uninstall target +if(YAML_CPP_INSTALL AND NOT YAML_CPP_DISABLE_UNINSTALL AND NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) -### -### Extras -### -if(YAML_CPP_BUILD_TESTS) - add_subdirectory(test) + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() -if(YAML_CPP_BUILD_TOOLS) - add_subdirectory(util) -endif() - -### Formatting -get_property(all_sources GLOBAL PROPERTY SRCS_LIST) -add_custom_target(format - COMMAND clang-format --style=file -i ${all_sources} - COMMENT "Running clang-format" - VERBATIM) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd09a1aca..e4ca076dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,9 +17,9 @@ Commit messages should be in the imperative mood, as described in the [Git contr # Tests -Please verify the tests pass by running the target `tests/run_tests`. +Please verify the tests pass by configuring CMake with `-D YAML_CPP_BUILD_TESTS=ON` and running the target `test/yaml-cpp-tests`. -If you are adding functionality, add tests accordingly. +If you are adding functionality, add tests accordingly. Note that the "spec tests" are reserved for examples directly from the YAML spec, so if you have new examples, put them in other test files. # Pull request process diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..132cde13b --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,14 @@ +""" +yaml-cpp is a YAML parser and emitter in c++ matching the YAML specification. +""" + +module( + name = "yaml-cpp", + compatibility_level = 1, + version = "0.8.0", +) + +bazel_dep(name = "platforms", version = "1.0.0") +bazel_dep(name = "rules_cc", version = "0.2.14") + +bazel_dep(name = "googletest", version = "1.17.0.bcr.2", dev_dependency = True) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 000000000..d06bb14a0 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,282 @@ +{ + "lockFileVersion": 24, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16", + "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1", + "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", + "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/source.json": "d725d73707d01bb46ab3ca59ba408b8e9bd336642ca77a2269d4bfb8bbfd413d", + "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85", + "https://bcr.bazel.build/modules/apple_support/1.22.1/MODULE.bazel": "90bd1a660590f3ceffbdf524e37483094b29352d85317060b2327fff8f3f4458", + "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", + "https://bcr.bazel.build/modules/apple_support/1.23.1/source.json": "d888b44312eb0ad2c21a91d026753f330caa48a25c9b2102fae75eb2b0dcfdd2", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", + "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", + "https://bcr.bazel.build/modules/googletest/1.17.0.bcr.2/MODULE.bazel": "827f54f492a3ce549c940106d73de332c2b30cebd0c20c0bc5d786aba7f116cb", + "https://bcr.bazel.build/modules/googletest/1.17.0.bcr.2/source.json": "3664514073a819992320ffbce5825e4238459df344d8b01748af2208f8d2e1eb", + "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", + "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", + "https://bcr.bazel.build/modules/pybind11_bazel/2.13.6/MODULE.bazel": "2d746fda559464b253b2b2e6073cb51643a2ac79009ca02100ebbc44b4548656", + "https://bcr.bazel.build/modules/pybind11_bazel/2.13.6/source.json": "6aa0703de8efb20cc897bbdbeb928582ee7beaf278bcd001ac253e1605bddfae", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a", + "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa", + "https://bcr.bazel.build/modules/re2/2025-08-12.bcr.1/MODULE.bazel": "e09b434b122bfb786a69179f9b325e35cb1856c3f56a7a81dd61609260ed46e1", + "https://bcr.bazel.build/modules/re2/2025-08-12.bcr.1/source.json": "a8ae7c09533bf67f9f6e5122d884d5741600b09d78dca6fc0f2f8d2ee0c2d957", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.4/MODULE.bazel": "bb03a452a7527ac25a7518fb86a946ef63df860b9657d8323a0c50f8504fb0b9", + "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8", + "https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54", + "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615", + "https://bcr.bazel.build/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc", + "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", + "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", + "https://bcr.bazel.build/modules/rules_python/0.34.0/MODULE.bazel": "1d623d026e075b78c9fde483a889cda7996f5da4f36dffb24c246ab30f06513a", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/1.5.1/MODULE.bazel": "acfe65880942d44a69129d4c5c3122d57baaf3edf58ae5a6bd4edea114906bf5", + "https://bcr.bazel.build/modules/rules_python/1.5.1/source.json": "aa903e1bcbdfa1580f2b8e2d55100b7c18bc92d779ebb507fec896c75635f7bd", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", + "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "rL/34P1aFDq2GqVC2zCFgQ8nTuOC6ziogocpvG50Qz8=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python+//python/uv:uv.bzl%uv": { + "general": { + "bzlTransitiveDigest": "8vT1ddXtljNxYD0tJkksqzeKE6xqx4Ix+tXthAppjTI=", + "usagesDigest": "WYhzIw9khRBy34H1GxV5+fI1yi07O90NmCXosPUdHWQ=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "uv": { + "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo", + "attributes": { + "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'", + "toolchain_names": [ + "none" + ], + "toolchain_implementations": { + "none": "'@@rules_python+//python:none'" + }, + "toolchain_compatible_with": { + "none": [ + "@platforms//:incompatible" + ] + }, + "toolchain_target_settings": {} + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_python+", + "platforms", + "platforms" + ] + ] + } + } + }, + "facts": {} +} diff --git a/README.md b/README.md index dc1495c61..ec72636d1 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,86 @@ -# yaml-cpp [![Build Status](https://travis-ci.org/jbeder/yaml-cpp.svg?branch=master)](https://travis-ci.org/jbeder/yaml-cpp) [![Documentation](https://codedocs.xyz/jbeder/yaml-cpp.svg)](https://codedocs.xyz/jbeder/yaml-cpp/) +# yaml-cpp ![Build Status](https://github.com/jbeder/yaml-cpp/actions/workflows/build.yml/badge.svg) [![Documentation](https://codedocs.xyz/jbeder/yaml-cpp.svg)](https://codedocs.xyz/jbeder/yaml-cpp/) -yaml-cpp is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html). +`yaml-cpp` is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html). -To get a feel for how it can be used, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) or [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML). For the old API (version < 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)). +## Usage -# Problems? # +See [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) and [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML) for reference. For the old API (until 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)). -If you find a bug, post an [issue](https://github.com/jbeder/yaml-cpp/issues)! If you have questions about how to use yaml-cpp, please post it on http://stackoverflow.com and tag it [`yaml-cpp`](http://stackoverflow.com/questions/tagged/yaml-cpp). +## Any Problems? -# How to Build # +If you find a bug, post an [issue](https://github.com/jbeder/yaml-cpp/issues)! If you have questions about how to use yaml-cpp, please post it on http://stackoverflow.com and tag it [`yaml-cpp`](http://stackoverflow.com/questions/tagged/yaml-cpp). -yaml-cpp uses [CMake](http://www.cmake.org) to support cross-platform building. The basic steps to build are: +## How to Build -1. Download and install [CMake](http://www.cmake.org) (Resources -> Download). +`yaml-cpp` uses [CMake](http://www.cmake.org) to support cross-platform building. Install [CMake](http://www.cmake.org) _(Resources -> Download)_ before proceeding. The basic steps to build are: -**Note:** If you don't use the provided installer for your platform, make sure that you add CMake's bin folder to your path. +**Note:** If you don't use the provided installer for your platform, make sure that you add `CMake`'s bin folder to your path. -2. Navigate into the source directory, and type: +#### 1. Navigate into the source directory, create build folder and run `CMake`: -``` +```sh mkdir build cd build +cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=on|OFF] .. ``` -3. Run CMake. The basic syntax is: + * The `generator` option is the build system you'd like to use. Run `cmake` without arguments to see a full list of available generators. + * On Windows, you might use "Visual Studio 12 2013" (VS 2013 32-bits), or "Visual Studio 14 2015 Win64" (VS 2015 64-bits). + * On OS X, you might use "Xcode". + * On a UNIX-like system, omit the option (for a Makefile). -``` -cmake [-G generator] [-DBUILD_SHARED_LIBS=ON|OFF] .. -``` + * `yaml-cpp` builds a static library by default, you may want to build a shared library by specifying `-DYAML_BUILD_SHARED_LIBS=ON`. - * The `generator` is whatever type of build system you'd like to use. To see a full list of generators on your platform, just run `cmake` (with no arguments). For example: - * On Windows, you might use "Visual Studio 12 2013" to generate a Visual Studio 2013 solution or "Visual Studio 14 2015 Win64" to generate a 64-bit Visual Studio 2015 solution. - * On OS X, you might use "Xcode" to generate an Xcode project - * On a UNIX-y system, simply omit the option to generate a makefile + * [Debug mode of the GNU standard C++ + library](https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html) + can be used when both `yaml-cpp` and client code is compiled with the + `_GLIBCXX_DEBUG` flag (e.g. by calling CMake with `-D + CMAKE_CXX_FLAGS_DEBUG='-g -D_GLIBCXX_DEBUG'` option). - * yaml-cpp defaults to building a static library, but you may build a shared library by specifying `-DBUILD_SHARED_LIBS=ON`. + Note that for `yaml-cpp` unit tests to run successfully, the _GoogleTest_ + library also must be built with this flag, i.e. the system one cannot be + used (the _YAML_USE_SYSTEM_GTEST_ CMake option must be _OFF_, which is the + default). * For more options on customizing the build, see the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file. -4. Build it! +#### 2. Build it! + * The command you'll need to run depends on the generator you chose earlier. + +**Note:** To clean up, just remove the `build` directory. + +## How to Integrate it within your project using CMake + +You can use for example FetchContent : -5. To clean up, just remove the `build` directory. +```cmake +include(FetchContent) -# Recent Release # +FetchContent_Declare( + yaml-cpp + GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git + GIT_TAG # Can be a tag (yaml-cpp-x.x.x), a commit hash, or a branch name (master) +) +FetchContent_MakeAvailable(yaml-cpp) -[yaml-cpp 0.5.3](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.5.3) has been released! This is a bug fix release. It also will be the last release that uses Boost; futures releases will require C++11 instead. +target_link_libraries(YOUR_LIBRARY PUBLIC yaml-cpp::yaml-cpp) # The library or executable that require yaml-cpp library +``` + +## Recent Releases + +[yaml-cpp 0.8.0](https://github.com/jbeder/yaml-cpp/releases/tag/0.8.0) released! [yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old API. -**The old API will continue to be supported, and will still receive bugfixes!** The 0.3.x and 0.4.x versions will be old API releases, and 0.5.x and above will all be new API releases. +**The old API will stop receiving bugfixes in 2026.** The 0.3.x versions provide the old API, and 0.5.x and above all provide the new API. + +# API Documentation + +The autogenerated API reference is hosted on [CodeDocs](https://codedocs.xyz/jbeder/yaml-cpp/index.html) + +# Third Party Integrations + +The following projects are not officially supported: + +- [Qt wrapper](https://gist.github.com/brcha/d392b2fe5f1e427cc8a6) +- [UnrealEngine Wrapper](https://github.com/jwindgassen/UnrealYAML) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..06a17511b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/jbeder/yaml-cpp/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base. diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 000000000..c2d34d479 --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif() + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() +endforeach() diff --git a/docs/Breaking-Changes.md b/docs/Breaking-Changes.md new file mode 100644 index 000000000..959adea22 --- /dev/null +++ b/docs/Breaking-Changes.md @@ -0,0 +1,52 @@ +# The following is a list of breaking changes to yaml-cpp, by version # + +# New API # + +## HEAD ## + + * Throws an exception when trying to parse a negative number as an unsigned integer. + * Supports the `as`/`as`, which throws an exception when the value exceeds the range of `int8_t`/`uint8_t`. + +## 0.6.0 ## + + * Requires C++11. + +## 0.5.3 ## + +_none_ + +## 0.5.2 ## + +_none_ + +## 0.5.1 ## + + * `Node::clear` was replaced by `Node::reset`, which takes an optional node, similar to smart pointers. + +## 0.5.0 ## + +Initial version of the new API. + +# Old API # + +## 0.3.0 ## + +_none_ + +## 0.2.7 ## + + * `YAML::Binary` now takes `const unsigned char *` for the binary data (instead of `const char *`). + +## 0.2.6 ## + + * `Node::GetType()` is now `Node::Type()`, and returns an enum `NodeType::value`, where: +> > ` struct NodeType { enum value { Null, Scalar, Sequence, Map }; }; ` + * `Node::GetTag()` is now `Node::Tag()` + * `Node::Identity()` is removed, and `Node::IsAlias()` and `Node::IsReferenced()` have been merged into `Node::IsAliased()`. The reason: there's no reason to distinguish an alias node from its anchor - whichever happens to be emitted first will be the anchor, and the rest will be aliases. + * `Node::Read` is now `Node::to`. This wasn't a documented function, so it shouldn't break anything. + * `Node`'s comparison operators (for example, `operator == (const Node&, const T&)`) have all been removed. These weren't documented either (they were just used for the tests), so this shouldn't break anything either. + * The emitter no longer produces the document start by default - if you want it, you can supply it with the manipulator `YAML::BeginDoc`. + +## 0.2.5 ## + +This wiki was started with v0.2.5. \ No newline at end of file diff --git a/docs/How-To-Emit-YAML.md b/docs/How-To-Emit-YAML.md new file mode 100644 index 000000000..6e6f9f58e --- /dev/null +++ b/docs/How-To-Emit-YAML.md @@ -0,0 +1,226 @@ +## Contents ## + + + +# Basic Emitting # + +The model for emitting YAML is `std::ostream` manipulators. A `YAML::Emitter` objects acts as an output stream, and its output can be retrieved through the `c_str()` function (as in `std::string`). For a simple example: + +```cpp +#include "yaml-cpp/yaml.h" + +int main() +{ + YAML::Emitter out; + out << "Hello, World!"; + + std::cout << "Here's the output YAML:\n" << out.c_str(); // prints "Hello, World!" + return 0; +} +``` + +# Simple Lists and Maps # + +A `YAML::Emitter` object acts as a state machine, and we use manipulators to move it between states. Here's a simple sequence: + +```cpp +YAML::Emitter out; +out << YAML::BeginSeq; +out << "eggs"; +out << "bread"; +out << "milk"; +out << YAML::EndSeq; +``` + +produces + +```yaml +- eggs +- bread +- milk +``` + +A simple map: + +```cpp +YAML::Emitter out; +out << YAML::BeginMap; +out << YAML::Key << "name"; +out << YAML::Value << "Ryan Braun"; +out << YAML::Key << "position"; +out << YAML::Value << "LF"; +out << YAML::EndMap; +``` + +produces + +```yaml +name: Ryan Braun +position: LF +``` + +These elements can, of course, be nested: + +```cpp +YAML::Emitter out; +out << YAML::BeginMap; +out << YAML::Key << "name"; +out << YAML::Value << "Barack Obama"; +out << YAML::Key << "children"; +out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; +out << YAML::EndMap; +``` + +produces + +```yaml +name: Barack Obama +children: + - Sasha + - Malia +``` + +# Using Manipulators # + +To deviate from standard formatting, you can use manipulators to modify the output format. For example, + +```cpp +YAML::Emitter out; +out << YAML::Literal << "A\n B\n C"; +``` + +produces + +```yaml +| +A + B + C +``` +and + +```cpp +YAML::Emitter out; +out << YAML::Flow; +out << YAML::BeginSeq << 2 << 3 << 5 << 7 << 11 << YAML::EndSeq; +``` + +produces + +```yaml +[2, 3, 5, 7, 11] +``` + +Comments act like manipulators: + +```cpp +YAML::Emitter out; +out << YAML::BeginMap; +out << YAML::Key << "method"; +out << YAML::Value << "least squares"; +out << YAML::Comment("should we change this method?"); +out << YAML::EndMap; +``` + +produces + +```yaml +method: least squares # should we change this method? +``` + +And so do aliases/anchors: + +```cpp +YAML::Emitter out; +out << YAML::BeginSeq; +out << YAML::Anchor("fred"); +out << YAML::BeginMap; +out << YAML::Key << "name" << YAML::Value << "Fred"; +out << YAML::Key << "age" << YAML::Value << "42"; +out << YAML::EndMap; +out << YAML::Alias("fred"); +out << YAML::EndSeq; +``` + +produces + +```yaml +- &fred + name: Fred + age: 42 +- *fred +``` + +# STL Containers, and Other Overloads # +We overload `operator <<` for `std::vector`, `std::list`, and `std::map`, so you can write stuff like: + +{% raw %} +```cpp +std::vector squares = {1, 4, 9, 16}; + +std::map ages = {{"Daniel", 26}, {"Jesse", 24}}; + +YAML::Emitter out; +out << YAML::BeginSeq; +out << YAML::Flow << squares; +out << ages; +out << YAML::EndSeq; +``` +{% endraw %} + +produces + +```yaml +- [1, 4, 9, 16] +- + Daniel: 26 + Jesse: 24 +``` + +Of course, you can overload `operator <<` for your own types: + +```cpp +struct Vec3 { int x; int y; int z; }; +YAML::Emitter& operator << (YAML::Emitter& out, const Vec3& v) { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; + return out; +} +``` +and it'll play nicely with everything else. + +# Using Existing Nodes # + +We also overload `operator << ` for `YAML::Node`s in both APIs, so you can output existing Nodes. Of course, Nodes in the old API are read-only, so it's tricky to emit them if you want to modify them. So use the new API! + +# Output Encoding # + +The output is always UTF-8. By default, yaml-cpp will output as much as it can without escaping any characters. If you want to restrict the output to ASCII, use the manipulator `YAML::EscapeNonAscii`: + +```cpp +emitter.SetOutputCharset(YAML::EscapeNonAscii); +``` + +# Lifetime of Manipulators # + +Manipulators affect the **next** output item in the stream. If that item is a `BeginSeq` or `BeginMap`, the manipulator lasts until the corresponding `EndSeq` or `EndMap`. (However, within that sequence or map, you can override the manipulator locally, etc.; in effect, there's a "manipulator stack" behind the scenes.) + +If you want to permanently change a setting, there are global setters corresponding to each manipulator, e.g.: + +```cpp +YAML::Emitter out; +out.SetIndent(4); +out.SetMapStyle(YAML::Flow); +``` + +# When Something Goes Wrong # + +If something goes wrong when you're emitting a document, it must be something like forgetting a `YAML::EndSeq`, or a misplaced `YAML::Key`. In this case, emitting silently fails (no more output is emitted) and an error flag is set. For example: + +```cpp +YAML::Emitter out; +assert(out.good()); +out << YAML::Key; +assert(!out.good()); +std::cout << "Emitter error: " << out.GetLastError() << "\n"; +``` diff --git a/docs/How-To-Parse-A-Document-(Old-API).md b/docs/How-To-Parse-A-Document-(Old-API).md new file mode 100644 index 000000000..82fac718a --- /dev/null +++ b/docs/How-To-Parse-A-Document-(Old-API).md @@ -0,0 +1,265 @@ +_The following describes the old API. For the new API, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial)._ + +## Contents ## + + +# Basic Parsing # + +The parser accepts streams, not file names, so you need to first load the file. Since a YAML file can contain many documents, you can grab them one-by-one. A simple way to parse a YAML file might be: + +``` +#include +#include "yaml-cpp/yaml.h" + +int main() +{ + std::ifstream fin("test.yaml"); + YAML::Parser parser(fin); + + YAML::Node doc; + while(parser.GetNextDocument(doc)) { + // ... + } + + return 0; +} +``` + +# Reading From the Document # + +Suppose we have a document consisting only of a scalar. We can read that scalar like this: + +``` +YAML::Node doc; // let's say we've already parsed this document +std::string scalar; +doc >> scalar; +std::cout << "That scalar was: " << scalar << std::endl; +``` + +How about sequences? Let's say our document now consists only of a sequences of scalars. We can use an iterator: + +``` +YAML::Node doc; // already parsed +for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + std::string scalar; + *it >> scalar; + std::cout << "Found scalar: " << scalar << std::endl; +} +``` + +... or we can just loop through: + +``` +YAML::Node doc; // already parsed +for(unsigned i=0;i> scalar; + std::cout << "Found scalar: " << scalar << std::endl; +} +``` + +And finally maps. For now, let's say our document is a map with all keys/values being scalars. Again, we can iterate: + +``` +YAML::Node doc; // already parsed +for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + std::string key, value; + it.first() >> key; + it.second() >> value; + std::cout << "Key: " << key << ", value: " << value << std::endl; +} +``` + +Note that dereferencing a map iterator is undefined; instead, use the `first` and `second` methods to get the key and value nodes, respectively. + +Alternatively, we can pick off the values one-by-one, if we know the keys: + +``` +YAML::Node doc; // already parsed +std::string name; +doc["name"] >> name; +int age; +doc["age"] >> age; +std::cout << "Found entry with name '" << name << "' and age '" << age << "'\n"; +``` + +One thing to be keep in mind: reading a map by key (as immediately above) requires looping through all entries until we find the right key, which is an O(n) operation. So if you're reading the entire map this way, it'll be O(n^2). For small n, this isn't a big deal, but I wouldn't recommend reading maps with a very large number of entries (>100, say) this way. + +## Optional Keys ## + +If you try to access a key that doesn't exist, `yaml-cpp` throws an exception (see [When Something Goes Wrong](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)#When_Something_Goes_Wrong). If you have optional keys, it's often easier to use `FindValue` instead of `operator[]`: + +``` +YAML::Node doc; // already parsed +if(const YAML::Node *pName = doc.FindValue("name")) { + std::string name; + *pName >> name; + std::cout << "Key 'name' exists, with value '" << name << "'\n"; +} else { + std::cout << "Key 'name' doesn't exist\n"; +} +``` + +# Getting More Complicated # + +The above three methods can be combined to read from an arbitrary document. But we can make life a lot easier. Suppose we're reading 3-vectors (i.e., vectors with three components), so we've got a structure looking like this: + +``` +struct Vec3 { + float x, y, z; +}; +``` + +We can read this in one operation by overloading the extraction (>>) operator: + +``` +void operator >> (const YAML::Node& node, Vec3& v) +{ + node[0] >> v.x; + node[1] >> v.y; + node[2] >> v.z; +} + +// now it's a piece of cake to read it +YAML::Node doc; // already parsed +Vec3 v; +doc >> v; +std::cout << "Here's the vector: (" << v.x << ", " << v.y << ", " << v.z << ")\n"; +``` + +# A Complete Example # + +Here's a complete example of how to parse a complex YAML file: + +`monsters.yaml` + +``` +- name: Ogre + position: [0, 5, 0] + powers: + - name: Club + damage: 10 + - name: Fist + damage: 8 +- name: Dragon + position: [1, 0, 10] + powers: + - name: Fire Breath + damage: 25 + - name: Claws + damage: 15 +- name: Wizard + position: [5, -3, 0] + powers: + - name: Acid Rain + damage: 50 + - name: Staff + damage: 3 +``` + +`main.cpp` + +``` +#include "yaml-cpp/yaml.h" +#include +#include +#include +#include + +// our data types +struct Vec3 { + float x, y, z; +}; + +struct Power { + std::string name; + int damage; +}; + +struct Monster { + std::string name; + Vec3 position; + std::vector powers; +}; + +// now the extraction operators for these types +void operator >> (const YAML::Node& node, Vec3& v) { + node[0] >> v.x; + node[1] >> v.y; + node[2] >> v.z; +} + +void operator >> (const YAML::Node& node, Power& power) { + node["name"] >> power.name; + node["damage"] >> power.damage; +} + +void operator >> (const YAML::Node& node, Monster& monster) { + node["name"] >> monster.name; + node["position"] >> monster.position; + const YAML::Node& powers = node["powers"]; + for(unsigned i=0;i> power; + monster.powers.push_back(power); + } +} + +int main() +{ + std::ifstream fin("monsters.yaml"); + YAML::Parser parser(fin); + YAML::Node doc; + parser.GetNextDocument(doc); + for(unsigned i=0;i> monster; + std::cout << monster.name << "\n"; + } + + return 0; +} +``` + +# When Something Goes Wrong # + +... we throw an exception (all exceptions are derived from `YAML::Exception`). If there's a parsing exception (i.e., a malformed YAML document), we throw a `YAML::ParserException`: + +``` +try { + std::ifstream fin("test.yaml"); + YAML::Parser parser(fin); + YAML::Node doc; + parser.GetNextDocument(doc); + // do stuff +} catch(YAML::ParserException& e) { + std::cout << e.what() << "\n"; +} +``` + +If you make a programming error (say, trying to read a scalar from a sequence node, or grabbing a key that doesn't exist), we throw some kind of `YAML::RepresentationException`. To prevent this, you can check what kind of node something is: + +``` + YAML::Node node; + YAML::NodeType::value type = node.Type(); // should be: + // YAML::NodeType::Null + // YAML::NodeType::Scalar + // YAML::NodeType::Sequence + // YAML::NodeType::Map +``` + +# Note about copying `YAML::Node` # + +Currently `YAML::Node` is non-copyable, so you need to do something like + +``` + const YAML::Node& node = doc["whatever"]; +``` + +This is intended behavior. If you want to copy a node, use the `Clone` function: + +``` + std::auto_ptr pCopy = myOtherNode.Clone(); +``` + +The intent is that if you'd like to keep a `YAML::Node` around for longer than the document will stay in scope, you can clone it and store it as long as you like. \ No newline at end of file diff --git a/docs/Strings.md b/docs/Strings.md new file mode 100644 index 000000000..f2328a1b6 --- /dev/null +++ b/docs/Strings.md @@ -0,0 +1,18 @@ +# Encodings and `yaml-cpp` # + +`yaml-cpp` will parse any file as specified by the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html#id2570322). Internally, it stores all strings in UTF-8, and representation is done with UTF-8. This means that in + +``` +std::string str; +node >> str; +``` + +`str` will be UTF-8. Similarly, if you're accessing a map by string key, you need to pass the key in UTF-8. If your application uses a different encoding, you need to convert to and from UTF-8 to work with `yaml-cpp`. (It's possible we'll add some small conversion functions, but for now it's restricted.) + +--- + +For convenience, Richard Weeks has kindly provided a google gadget that converts Unicode to a string literal. It's a Google Gadget, so unfortunately it does not work on GitHub. Patches welcome to port it to a usable format here: + +``` + +``` \ No newline at end of file diff --git a/docs/Tutorial.md b/docs/Tutorial.md new file mode 100644 index 000000000..a7b0e21d0 --- /dev/null +++ b/docs/Tutorial.md @@ -0,0 +1,201 @@ +# Introduction # + +A typical example, loading a configuration file, might look like this: + +```cpp +YAML::Node config = YAML::LoadFile("config.yaml"); + +if (config["lastLogin"]) { + std::cout << "Last logged in: " << config["lastLogin"].as() << "\n"; +} + +const std::string username = config["username"].as(); +const std::string password = config["password"].as(); +login(username, password); +config["lastLogin"] = getCurrentDateTime(); + +std::ofstream fout("config.yaml"); +fout << config; +``` + +# Basic Parsing and Node Editing # + +All nodes in a YAML document (including the root) are represented by `YAML::Node`. You can check what kind it is: + +```cpp +YAML::Node node = YAML::Load("[1, 2, 3]"); +assert(node.Type() == YAML::NodeType::Sequence); +assert(node.IsSequence()); // a shortcut! +``` + +Collection nodes (sequences and maps) act somewhat like STL vectors and maps: + +```cpp +YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]"); +for (std::size_t i=0;i() << "\n"; +} +// or: +for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) { + std::cout << it->as() << "\n"; +} + +primes.push_back(13); +assert(primes.size() == 6); +``` + +and + +```cpp +YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}"); +for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) { + std::cout << "Playing at " << it->first.as() << " is " << it->second.as() << "\n"; +} + +lineup["RF"] = "Corey Hart"; +lineup["C"] = "Jonathan Lucroy"; +assert(lineup.size() == 5); +``` + +Querying for keys does **not** create them automatically (this makes handling optional map entries very easy) + +```cpp +YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}"); +if (node["name"]) { + std::cout << node["name"].as() << "\n"; +} +if (node["mascot"]) { + std::cout << node["mascot"].as() << "\n"; +} +assert(node.size() == 2); // the previous call didn't create a node +``` + +If you're not sure what kind of data you're getting, you can query the type of a node: + +```cpp +switch (node.Type()) { + case Null: // ... + case Scalar: // ... + case Sequence: // ... + case Map: // ... + case Undefined: // ... +} +``` + +or ask directly whether it's a particular type, e.g.: + +```cpp +if (node.IsSequence()) { + // ... +} +``` + +# Building Nodes # + +You can build `YAML::Node` from scratch: + +```cpp +YAML::Node node; // starts out as null +node["key"] = "value"; // it now is a map node +node["seq"].push_back("first element"); // node["seq"] automatically becomes a sequence +node["seq"].push_back("second element"); + +node["mirror"] = node["seq"][0]; // this creates an alias +node["seq"][0] = "1st element"; // this also changes node["mirror"] +node["mirror"] = "element #1"; // and this changes node["seq"][0] - they're really the "same" node + +node["self"] = node; // you can even create self-aliases +node[node["mirror"]] = node["seq"]; // and strange loops :) +``` + +The above node is now: + +```yaml +&1 +key: value +&2 seq: [&3 "element #1", second element] +mirror: *3 +self: *1 +*3 : *2 +``` + +# How Sequences Turn Into Maps # + +Sequences can be turned into maps by asking for non-integer keys. For example, + +```cpp +YAML::Node node = YAML::Load("[1, 2, 3]"); +node[1] = 5; // still a sequence, [1, 5, 3] +node.push_back(-3) // still a sequence, [1, 5, 3, -3] +node["key"] = "value"; // now it's a map! {0: 1, 1: 5, 2: 3, 3: -3, key: value} +``` + +Indexing a sequence node by an index that's not in its range will _usually_ turn it into a map, but if the index is one past the end of the sequence, then the sequence will grow by one to accommodate it. (That's the **only** exception to this rule.) For example, + +```cpp +YAML::Node node = YAML::Load("[1, 2, 3]"); +node[3] = 4; // still a sequence, [1, 2, 3, 4] +node[10] = 10; // now it's a map! {0: 1, 1: 2, 2: 3, 3: 4, 10: 10} +``` + +# Converting To/From Native Data Types # + +Yaml-cpp has built-in conversion to and from most built-in data types, as well as `std::vector`, `std::list`, and `std::map`. The following examples demonstrate when those conversions are used: + +```cpp +YAML::Node node = YAML::Load("{pi: 3.14159, [0, 1]: integers}"); + +// this needs the conversion from Node to double +double pi = node["pi"].as(); + +// this needs the conversion from double to Node +node["e"] = 2.71828; + +// this needs the conversion from Node to std::vector (*not* the other way around!) +std::vector v; +v.push_back(0); +v.push_back(1); +std::string str = node[v].as(); +``` + +To use yaml-cpp with your own data types, you need to specialize the YAML::convert<> template class. For example, suppose you had a simple `Vec3` class: + +```cpp +struct Vec3 { double x, y, z; /* etc - make sure you have overloaded operator== */ }; +``` + +You could write + +```cpp +namespace YAML { +template<> +struct convert { + static Node encode(const Vec3& rhs) { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + return node; + } + + static bool decode(const Node& node, Vec3& rhs) { + if(!node.IsSequence() || node.size() != 3) { + return false; + } + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + return true; + } +}; +} +``` + +Then you could use `Vec3` wherever you could use any other type: + +```cpp +YAML::Node node = YAML::Load("start: [1, 3, 0]"); +Vec3 v = node["start"].as(); +node["end"] = Vec3(2, -1, 0); +``` \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..c74188174 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..17f131518 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +To learn how to use the library, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) and [How To Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML) diff --git a/include/yaml-cpp/anchor.h b/include/yaml-cpp/anchor.h index 06759c724..f46d1d79d 100644 --- a/include/yaml-cpp/anchor.h +++ b/include/yaml-cpp/anchor.h @@ -10,7 +10,7 @@ #include namespace YAML { -typedef std::size_t anchor_t; +using anchor_t = std::size_t; const anchor_t NullAnchor = 0; } diff --git a/include/yaml-cpp/binary.h b/include/yaml-cpp/binary.h index 29d5dbd02..1050dae98 100644 --- a/include/yaml-cpp/binary.h +++ b/include/yaml-cpp/binary.h @@ -19,9 +19,13 @@ YAML_CPP_API std::vector DecodeBase64(const std::string &input); class YAML_CPP_API Binary { public: - Binary() : m_unownedData(0), m_unownedSize(0) {} Binary(const unsigned char *data_, std::size_t size_) - : m_unownedData(data_), m_unownedSize(size_) {} + : m_data{}, m_unownedData(data_), m_unownedSize(size_) {} + Binary() : Binary(nullptr, 0) {} + Binary(const Binary &) = default; + Binary(Binary &&) = default; + Binary &operator=(const Binary &) = default; + Binary &operator=(Binary &&) = default; bool owned() const { return !m_unownedData; } std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; } @@ -35,7 +39,7 @@ class YAML_CPP_API Binary { rhs.clear(); rhs.resize(m_unownedSize); std::copy(m_unownedData, m_unownedData + m_unownedSize, rhs.begin()); - m_unownedData = 0; + m_unownedData = nullptr; m_unownedSize = 0; } else { m_data.swap(rhs); @@ -62,6 +66,6 @@ class YAML_CPP_API Binary { const unsigned char *m_unownedData; std::size_t m_unownedSize; }; -} +} // namespace YAML #endif // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/contrib/anchordict.h b/include/yaml-cpp/contrib/anchordict.h index 78db9ec92..1b7809b87 100644 --- a/include/yaml-cpp/contrib/anchordict.h +++ b/include/yaml-cpp/contrib/anchordict.h @@ -22,6 +22,7 @@ namespace YAML { template class AnchorDict { public: + AnchorDict() : m_data{} {} void Register(anchor_t anchor, T value) { if (anchor > m_data.size()) { m_data.resize(anchor); @@ -34,6 +35,6 @@ class AnchorDict { private: std::vector m_data; }; -} +} // namespace YAML #endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h index f0a38f288..dbffd921e 100644 --- a/include/yaml-cpp/contrib/graphbuilder.h +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -15,7 +15,7 @@ class Parser; // GraphBuilderInterface // . Abstraction of node creation -// . pParentNode is always NULL or the return value of one of the NewXXX() +// . pParentNode is always nullptr or the return value of one of the NewXXX() // functions. class GraphBuilderInterface { public: @@ -73,9 +73,9 @@ class GraphBuilder : public GraphBuilderInterface { typedef typename Impl::Map Map; GraphBuilder(Impl &impl) : m_impl(impl) { - Map *pMap = NULL; - Sequence *pSeq = NULL; - Node *pNode = NULL; + Map *pMap = nullptr; + Sequence *pSeq = nullptr; + Node *pNode = nullptr; // Type consistency checks pNode = pMap; diff --git a/include/yaml-cpp/depthguard.h b/include/yaml-cpp/depthguard.h new file mode 100644 index 000000000..8ca61ac6c --- /dev/null +++ b/include/yaml-cpp/depthguard.h @@ -0,0 +1,77 @@ +#ifndef DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 +#define DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "exceptions.h" + +namespace YAML { + +/** + * @brief The DeepRecursion class + * An exception class which is thrown by DepthGuard. Ideally it should be + * a member of DepthGuard. However, DepthGuard is a templated class which means + * that any catch points would then need to know the template parameters. It is + * simpler for clients to not have to know at the catch point what was the + * maximum depth. + */ +class DeepRecursion : public ParserException { +public: + virtual ~DeepRecursion() = default; + + DeepRecursion(int depth, const Mark& mark_, const std::string& msg_); + + // Returns the recursion depth when the exception was thrown + int depth() const { + return m_depth; + } + +private: + int m_depth = 0; +}; + +/** + * @brief The DepthGuard class + * DepthGuard takes a reference to an integer. It increments the integer upon + * construction of DepthGuard and decrements the integer upon destruction. + * + * If the integer would be incremented past max_depth, then an exception is + * thrown. This is ideally geared toward guarding against deep recursion. + * + * @param max_depth + * compile-time configurable maximum depth. + */ +template +class DepthGuard final { +public: + DepthGuard(int & depth_, const Mark& mark_, const std::string& msg_) : m_depth(depth_) { + ++m_depth; + if ( max_depth <= m_depth ) { + throw DeepRecursion{m_depth, mark_, msg_}; + } + } + + DepthGuard(const DepthGuard & copy_ctor) = delete; + DepthGuard(DepthGuard && move_ctor) = delete; + DepthGuard & operator=(const DepthGuard & copy_assign) = delete; + DepthGuard & operator=(DepthGuard && move_assign) = delete; + + ~DepthGuard() { + --m_depth; + } + + int current_depth() const { + return m_depth; + } + +private: + int & m_depth; +}; + +} // namespace YAML + +#endif // DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 diff --git a/include/yaml-cpp/dll.h b/include/yaml-cpp/dll.h index a32c06b2e..4e55ab8c2 100644 --- a/include/yaml-cpp/dll.h +++ b/include/yaml-cpp/dll.h @@ -1,33 +1,59 @@ #ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if defined(_MSC_VER) || \ - (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ - (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 -#pragma once +// Definition YAML_CPP_STATIC_DEFINE using to building YAML-CPP as static +// library (definition created by CMake or defined manually) + +// Definition yaml_cpp_EXPORTS using to building YAML-CPP as dll/so library +// (definition created by CMake or defined manually) + +#ifdef YAML_CPP_STATIC_DEFINE +# define YAML_CPP_API +# define YAML_CPP_NO_EXPORT +#else +# if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) +# ifndef YAML_CPP_API +# ifdef yaml_cpp_EXPORTS + /* We are building this library */ +# define YAML_CPP_API __declspec(dllexport) +# else + /* We are using this library */ +# define YAML_CPP_API __declspec(dllimport) +# endif +# endif +# ifndef YAML_CPP_NO_EXPORT +# define YAML_CPP_NO_EXPORT +# endif +# else /* No _MSC_VER */ +# ifndef YAML_CPP_API +# ifdef yaml_cpp_EXPORTS + /* We are building this library */ +# define YAML_CPP_API __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define YAML_CPP_API __attribute__((visibility("default"))) +# endif +# endif +# ifndef YAML_CPP_NO_EXPORT +# define YAML_CPP_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +# endif /* _MSC_VER */ +#endif /* YAML_CPP_STATIC_DEFINE */ + +#ifndef YAML_CPP_DEPRECATED +# ifdef _MSC_VER +# define YAML_CPP_DEPRECATED __declspec(deprecated) +# else +# define YAML_CPP_DEPRECATED __attribute__ ((__deprecated__)) +# endif #endif -// The following ifdef block is the standard way of creating macros which make -// exporting from a DLL simpler. All files within this DLL are compiled with the -// yaml_cpp_EXPORTS symbol defined on the command line. This symbol should not -// be defined on any project that uses this DLL. This way any other project -// whose source files include this file see YAML_CPP_API functions as being -// imported from a DLL, whereas this DLL sees symbols defined with this macro as -// being exported. -#undef YAML_CPP_API +#ifndef YAML_CPP_DEPRECATED_EXPORT +# define YAML_CPP_DEPRECATED_EXPORT YAML_CPP_API YAML_CPP_DEPRECATED +#endif -#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined - // manually) -#ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake - // or defined manually) -// #pragma message( "Defining YAML_CPP_API for DLL export" ) -#define YAML_CPP_API __declspec(dllexport) -#else // yaml_cpp_EXPORTS -// #pragma message( "Defining YAML_CPP_API for DLL import" ) -#define YAML_CPP_API __declspec(dllimport) -#endif // yaml_cpp_EXPORTS -#else // YAML_CPP_DLL -#define YAML_CPP_API -#endif // YAML_CPP_DLL +#ifndef YAML_CPP_DEPRECATED_NO_EXPORT +# define YAML_CPP_DEPRECATED_NO_EXPORT YAML_CPP_NO_EXPORT YAML_CPP_DEPRECATED +#endif -#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#endif /* DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 */ diff --git a/include/yaml-cpp/emitfromevents.h b/include/yaml-cpp/emitfromevents.h index f14b051ab..c00d26e74 100644 --- a/include/yaml-cpp/emitfromevents.h +++ b/include/yaml-cpp/emitfromevents.h @@ -23,22 +23,23 @@ class Emitter; class EmitFromEvents : public EventHandler { public: EmitFromEvents(Emitter& emitter); + ~EmitFromEvents() override = default; - virtual void OnDocumentStart(const Mark& mark); - virtual void OnDocumentEnd(); + void OnDocumentStart(const Mark& mark) override; + void OnDocumentEnd() override; - virtual void OnNull(const Mark& mark, anchor_t anchor); - virtual void OnAlias(const Mark& mark, anchor_t anchor); - virtual void OnScalar(const Mark& mark, const std::string& tag, - anchor_t anchor, const std::string& value); + void OnNull(const Mark& mark, anchor_t anchor) override; + void OnAlias(const Mark& mark, anchor_t anchor) override; + void OnScalar(const Mark& mark, const std::string& tag, + anchor_t anchor, const std::string& value) override; - virtual void OnSequenceStart(const Mark& mark, const std::string& tag, - anchor_t anchor, EmitterStyle::value style); - virtual void OnSequenceEnd(); + void OnSequenceStart(const Mark& mark, const std::string& tag, + anchor_t anchor, EmitterStyle::value style) override; + void OnSequenceEnd() override; - virtual void OnMapStart(const Mark& mark, const std::string& tag, - anchor_t anchor, EmitterStyle::value style); - virtual void OnMapEnd(); + void OnMapStart(const Mark& mark, const std::string& tag, + anchor_t anchor, EmitterStyle::value style) override; + void OnMapEnd() override; private: void BeginNode(); diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index ef92cc403..67810ef34 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -7,18 +7,26 @@ #pragma once #endif +#include #include +#include +#include #include #include #include +#include + +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +#include +#endif #include "yaml-cpp/binary.h" #include "yaml-cpp/dll.h" #include "yaml-cpp/emitterdef.h" #include "yaml-cpp/emittermanip.h" -#include "yaml-cpp/noncopyable.h" #include "yaml-cpp/null.h" #include "yaml-cpp/ostream_wrapper.h" +#include "yaml-cpp/fptostring.h" namespace YAML { class Binary; @@ -28,10 +36,12 @@ struct _Null; namespace YAML { class EmitterState; -class YAML_CPP_API Emitter : private noncopyable { +class YAML_CPP_API Emitter { public: Emitter(); explicit Emitter(std::ostream& stream); + Emitter(const Emitter&) = delete; + Emitter& operator=(const Emitter&) = delete; ~Emitter(); // output @@ -46,6 +56,7 @@ class YAML_CPP_API Emitter : private noncopyable { bool SetOutputCharset(EMITTER_MANIP value); bool SetStringFormat(EMITTER_MANIP value); bool SetBoolFormat(EMITTER_MANIP value); + bool SetNullFormat(EMITTER_MANIP value); bool SetIntBase(EMITTER_MANIP value); bool SetSeqFormat(EMITTER_MANIP value); bool SetMapFormat(EMITTER_MANIP value); @@ -54,6 +65,7 @@ class YAML_CPP_API Emitter : private noncopyable { bool SetPostCommentIndent(std::size_t n); bool SetFloatPrecision(std::size_t n); bool SetDoublePrecision(std::size_t n); + void RestoreGlobalModifiedSettings(); // local setters Emitter& SetLocalValue(EMITTER_MANIP value); @@ -61,6 +73,7 @@ class YAML_CPP_API Emitter : private noncopyable { Emitter& SetLocalPrecision(const _Precision& precision); // overloads of write + Emitter& Write(const char* str, std::size_t size); Emitter& Write(const std::string& str); Emitter& Write(bool b); Emitter& Write(char ch); @@ -119,6 +132,7 @@ class YAML_CPP_API Emitter : private noncopyable { void SpaceOrIndentTo(bool requireSpace, std::size_t indent); const char* ComputeFullBoolName(bool b) const; + const char* ComputeNullName() const; bool CanEmitNewline() const; private: @@ -134,6 +148,7 @@ inline Emitter& Emitter::WriteIntegralType(T value) { PrepareNode(EmitterNodeType::Scalar); std::stringstream stream; + stream.imbue(std::locale::classic()); PrepareIntegralStream(stream); stream << value; m_stream << stream.str(); @@ -151,8 +166,29 @@ inline Emitter& Emitter::WriteStreamable(T value) { PrepareNode(EmitterNodeType::Scalar); std::stringstream stream; + stream.imbue(std::locale::classic()); SetStreamablePrecision(stream); - stream << value; + + bool special = false; + if (std::is_floating_point::value) { + if ((std::numeric_limits::has_quiet_NaN || + std::numeric_limits::has_signaling_NaN) && + std::isnan(value)) { + special = true; + stream << ".nan"; + } else if (std::numeric_limits::has_infinity && std::isinf(value)) { + special = true; + if (std::signbit(value)) { + stream << "-.inf"; + } else { + stream << ".inf"; + } + } + } + + if (!special) { + stream << FpToString(value, stream.precision()); + } m_stream << stream.str(); StartedScalar(); @@ -171,8 +207,13 @@ inline void Emitter::SetStreamablePrecision(std::stringstream& stream) { } // overloads of insertion +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +inline Emitter& operator<<(Emitter& emitter, const std::string_view& v) { + return emitter.Write(v.data(), v.size()); +} +#endif inline Emitter& operator<<(Emitter& emitter, const std::string& v) { - return emitter.Write(v); + return emitter.Write(v.data(), v.size()); } inline Emitter& operator<<(Emitter& emitter, bool v) { return emitter.Write(v); @@ -203,7 +244,7 @@ inline Emitter& operator<<(Emitter& emitter, const Binary& b) { } inline Emitter& operator<<(Emitter& emitter, const char* v) { - return emitter.Write(std::string(v)); + return emitter.Write(v, std::strlen(v)); } inline Emitter& operator<<(Emitter& emitter, int v) { @@ -249,6 +290,6 @@ inline Emitter& operator<<(Emitter& emitter, _Indent indent) { inline Emitter& operator<<(Emitter& emitter, _Precision precision) { return emitter.SetLocalPrecision(precision); } -} +} // namespace YAML #endif // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 89f725671..976d14950 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -19,6 +19,7 @@ enum EMITTER_MANIP { // output character set EmitNonAscii, EscapeNonAscii, + EscapeAsJson, // string manipulators // Auto, // duplicate @@ -26,6 +27,12 @@ enum EMITTER_MANIP { DoubleQuoted, Literal, + // null manipulators + LowerNull, + UpperNull, + CamelNull, + TildeNull, + // bool manipulators YesNoBool, // yes, no TrueFalseBool, // true, false @@ -74,14 +81,14 @@ struct _Alias { std::string content; }; -inline _Alias Alias(const std::string content) { return _Alias(content); } +inline _Alias Alias(const std::string& content) { return _Alias(content); } struct _Anchor { _Anchor(const std::string& content_) : content(content_) {} std::string content; }; -inline _Anchor Anchor(const std::string content) { return _Anchor(content); } +inline _Anchor Anchor(const std::string& content) { return _Anchor(content); } struct _Tag { struct Type { @@ -96,11 +103,11 @@ struct _Tag { Type::value type; }; -inline _Tag VerbatimTag(const std::string content) { +inline _Tag VerbatimTag(const std::string& content) { return _Tag("", content, _Tag::Type::Verbatim); } -inline _Tag LocalTag(const std::string content) { +inline _Tag LocalTag(const std::string& content) { return _Tag("", content, _Tag::Type::PrimaryHandle); } @@ -108,7 +115,7 @@ inline _Tag LocalTag(const std::string& prefix, const std::string content) { return _Tag(prefix, content, _Tag::Type::NamedHandle); } -inline _Tag SecondaryTag(const std::string content) { +inline _Tag SecondaryTag(const std::string& content) { return _Tag("", content, _Tag::Type::NamedHandle); } @@ -117,7 +124,7 @@ struct _Comment { std::string content; }; -inline _Comment Comment(const std::string content) { return _Comment(content); } +inline _Comment Comment(const std::string& content) { return _Comment(content); } struct _Precision { _Precision(int floatPrecision_, int doublePrecision_) diff --git a/include/yaml-cpp/emitterstyle.h b/include/yaml-cpp/emitterstyle.h index 67bb3981b..5a6355fa2 100644 --- a/include/yaml-cpp/emitterstyle.h +++ b/include/yaml-cpp/emitterstyle.h @@ -8,9 +8,10 @@ #endif namespace YAML { -struct EmitterStyle { - enum value { Default, Block, Flow }; -}; +namespace EmitterStyle { +enum value { Default, Block, Flow }; +} + } #endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/eventhandler.h b/include/yaml-cpp/eventhandler.h index efe381c62..7242fe1f5 100644 --- a/include/yaml-cpp/eventhandler.h +++ b/include/yaml-cpp/eventhandler.h @@ -17,7 +17,7 @@ struct Mark; class EventHandler { public: - virtual ~EventHandler() {} + virtual ~EventHandler() = default; virtual void OnDocumentStart(const Mark& mark) = 0; virtual void OnDocumentEnd() = 0; @@ -34,7 +34,12 @@ class EventHandler { virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor, EmitterStyle::value style) = 0; virtual void OnMapEnd() = 0; + + virtual void OnAnchor(const Mark& /*mark*/, + const std::string& /*anchor_name*/) { + // empty default implementation for compatibility + } }; -} +} // namespace YAML #endif // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index 9c96859b2..99e06b24e 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -8,19 +8,12 @@ #endif #include "yaml-cpp/mark.h" +#include "yaml-cpp/noexcept.h" #include "yaml-cpp/traits.h" #include #include #include -// This is here for compatibility with older versions of Visual Studio -// which don't support noexcept -#ifdef _MSC_VER - #define YAML_CPP_NOEXCEPT _NOEXCEPT -#else - #define YAML_CPP_NOEXCEPT noexcept -#endif - namespace YAML { // error messages namespace ErrorMsg { @@ -55,6 +48,8 @@ const char* const UNKNOWN_TOKEN = "unknown token"; const char* const DOC_IN_SCALAR = "illegal document indicator in scalar"; const char* const EOF_IN_SCALAR = "illegal EOF in scalar"; const char* const CHAR_IN_SCALAR = "illegal character in scalar"; +const char* const UNEXPECTED_SCALAR = "unexpected scalar"; +const char* const UNEXPECTED_FLOW = "plain value cannot start with flow indicator character"; const char* const TAB_IN_INDENTATION = "illegal tab when looking for indentation"; const char* const FLOW_END = "illegal flow end"; @@ -72,7 +67,7 @@ const char* const ZERO_INDENT_IN_BLOCK = const char* const CHAR_IN_BLOCK = "unexpected character in block scalar"; const char* const AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes"; -const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined"; +const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined: "; const char* const INVALID_NODE = "invalid node; this may result from using a map iterator as a sequence " @@ -107,6 +102,12 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) { return stream.str(); } +inline const std::string KEY_NOT_FOUND_WITH_KEY(const char* key) { + std::stringstream stream; + stream << KEY_NOT_FOUND << ": " << key; + return stream.str(); +} + template inline const std::string KEY_NOT_FOUND_WITH_KEY( const T& key, typename enable_if>::type* = 0) { @@ -114,13 +115,48 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY( stream << KEY_NOT_FOUND << ": " << key; return stream.str(); } + +template +inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T&, typename disable_if>::type* = nullptr) { + return BAD_SUBSCRIPT; } +inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")"; + return stream.str(); +} + +inline const std::string BAD_SUBSCRIPT_WITH_KEY(const char* key) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")"; + return stream.str(); +} + +template +inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T& key, typename enable_if>::type* = nullptr) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")"; + return stream.str(); +} + +inline const std::string INVALID_NODE_WITH_KEY(const std::string& key) { + std::stringstream stream; + if (key.empty()) { + return INVALID_NODE; + } + stream << "invalid node; first invalid key: \"" << key << "\""; + return stream.str(); +} +} // namespace ErrorMsg + class YAML_CPP_API Exception : public std::runtime_error { public: Exception(const Mark& mark_, const std::string& msg_) : std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {} - virtual ~Exception() YAML_CPP_NOEXCEPT; + ~Exception() YAML_CPP_NOEXCEPT override; Exception(const Exception&) = default; @@ -131,7 +167,7 @@ class YAML_CPP_API Exception : public std::runtime_error { static const std::string build_what(const Mark& mark, const std::string& msg) { if (mark.is_null()) { - return msg.c_str(); + return msg; } std::stringstream output; @@ -146,7 +182,7 @@ class YAML_CPP_API ParserException : public Exception { ParserException(const Mark& mark_, const std::string& msg_) : Exception(mark_, msg_) {} ParserException(const ParserException&) = default; - virtual ~ParserException() YAML_CPP_NOEXCEPT; + ~ParserException() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API RepresentationException : public Exception { @@ -154,7 +190,7 @@ class YAML_CPP_API RepresentationException : public Exception { RepresentationException(const Mark& mark_, const std::string& msg_) : Exception(mark_, msg_) {} RepresentationException(const RepresentationException&) = default; - virtual ~RepresentationException() YAML_CPP_NOEXCEPT; + ~RepresentationException() YAML_CPP_NOEXCEPT override; }; // representation exceptions @@ -163,7 +199,7 @@ class YAML_CPP_API InvalidScalar : public RepresentationException { InvalidScalar(const Mark& mark_) : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {} InvalidScalar(const InvalidScalar&) = default; - virtual ~InvalidScalar() YAML_CPP_NOEXCEPT; + ~InvalidScalar() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API KeyNotFound : public RepresentationException { @@ -173,7 +209,7 @@ class YAML_CPP_API KeyNotFound : public RepresentationException { : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) { } KeyNotFound(const KeyNotFound&) = default; - virtual ~KeyNotFound() YAML_CPP_NOEXCEPT; + ~KeyNotFound() YAML_CPP_NOEXCEPT override; }; template @@ -181,7 +217,7 @@ class YAML_CPP_API TypedKeyNotFound : public KeyNotFound { public: TypedKeyNotFound(const Mark& mark_, const T& key_) : KeyNotFound(mark_, key_), key(key_) {} - virtual ~TypedKeyNotFound() YAML_CPP_NOEXCEPT {} + ~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default; T key; }; @@ -194,10 +230,11 @@ inline TypedKeyNotFound MakeTypedKeyNotFound(const Mark& mark, class YAML_CPP_API InvalidNode : public RepresentationException { public: - InvalidNode() - : RepresentationException(Mark::null_mark(), ErrorMsg::INVALID_NODE) {} + InvalidNode(const std::string& key) + : RepresentationException(Mark::null_mark(), + ErrorMsg::INVALID_NODE_WITH_KEY(key)) {} InvalidNode(const InvalidNode&) = default; - virtual ~InvalidNode() YAML_CPP_NOEXCEPT; + ~InvalidNode() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API BadConversion : public RepresentationException { @@ -205,7 +242,7 @@ class YAML_CPP_API BadConversion : public RepresentationException { explicit BadConversion(const Mark& mark_) : RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {} BadConversion(const BadConversion&) = default; - virtual ~BadConversion() YAML_CPP_NOEXCEPT; + ~BadConversion() YAML_CPP_NOEXCEPT override; }; template @@ -219,15 +256,16 @@ class YAML_CPP_API BadDereference : public RepresentationException { BadDereference() : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {} BadDereference(const BadDereference&) = default; - virtual ~BadDereference() YAML_CPP_NOEXCEPT; + ~BadDereference() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API BadSubscript : public RepresentationException { public: - BadSubscript() - : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {} + template + BadSubscript(const Mark& mark_, const Key& key) + : RepresentationException(mark_, ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {} BadSubscript(const BadSubscript&) = default; - virtual ~BadSubscript() YAML_CPP_NOEXCEPT; + ~BadSubscript() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API BadPushback : public RepresentationException { @@ -235,7 +273,7 @@ class YAML_CPP_API BadPushback : public RepresentationException { BadPushback() : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {} BadPushback(const BadPushback&) = default; - virtual ~BadPushback() YAML_CPP_NOEXCEPT; + ~BadPushback() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API BadInsert : public RepresentationException { @@ -243,7 +281,7 @@ class YAML_CPP_API BadInsert : public RepresentationException { BadInsert() : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {} BadInsert(const BadInsert&) = default; - virtual ~BadInsert() YAML_CPP_NOEXCEPT; + ~BadInsert() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API EmitterException : public Exception { @@ -251,17 +289,17 @@ class YAML_CPP_API EmitterException : public Exception { EmitterException(const std::string& msg_) : Exception(Mark::null_mark(), msg_) {} EmitterException(const EmitterException&) = default; - virtual ~EmitterException() YAML_CPP_NOEXCEPT; + ~EmitterException() YAML_CPP_NOEXCEPT override; }; class YAML_CPP_API BadFile : public Exception { public: - BadFile() : Exception(Mark::null_mark(), ErrorMsg::BAD_FILE) {} + explicit BadFile(const std::string& filename) + : Exception(Mark::null_mark(), + std::string(ErrorMsg::BAD_FILE) + ": " + filename) {} BadFile(const BadFile&) = default; - virtual ~BadFile() YAML_CPP_NOEXCEPT; + ~BadFile() YAML_CPP_NOEXCEPT override; }; -} - -#undef YAML_CPP_NOEXCEPT +} // namespace YAML #endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/fptostring.h b/include/yaml-cpp/fptostring.h new file mode 100644 index 000000000..051053be9 --- /dev/null +++ b/include/yaml-cpp/fptostring.h @@ -0,0 +1,15 @@ +#ifndef YAML_H_FPTOSTRING +#define YAML_H_FPTOSTRING + +#include "yaml-cpp/dll.h" + +#include + +namespace YAML { +// "precision = 0" refers to shortest known unique representation of the value +YAML_CPP_API std::string FpToString(float v, size_t precision = 0); +YAML_CPP_API std::string FpToString(double v, size_t precision = 0); +YAML_CPP_API std::string FpToString(long double v, size_t precision = 0); +} + +#endif diff --git a/include/yaml-cpp/node/convert.h b/include/yaml-cpp/node/convert.h index 45a878ab0..0f04ea6fd 100644 --- a/include/yaml-cpp/node/convert.h +++ b/include/yaml-cpp/node/convert.h @@ -8,18 +8,28 @@ #endif #include +#include #include #include #include +#include #include +#include +#include #include +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +#include +#endif + #include "yaml-cpp/binary.h" #include "yaml-cpp/node/impl.h" #include "yaml-cpp/node/iterator.h" #include "yaml-cpp/node/node.h" #include "yaml-cpp/node/type.h" #include "yaml-cpp/null.h" +#include "yaml-cpp/fptostring.h" + namespace YAML { class Binary; @@ -71,14 +81,33 @@ struct convert { // C-strings can only be encoded template <> struct convert { - static Node encode(const char*& rhs) { return Node(rhs); } + static Node encode(const char* rhs) { return Node(rhs); } +}; + +template <> +struct convert { + static Node encode(const char* rhs) { return Node(rhs); } }; template -struct convert { - static Node encode(const char(&rhs)[N]) { return Node(rhs); } +struct convert { + static Node encode(const char* rhs) { return Node(rhs); } }; +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +template <> +struct convert { + static Node encode(std::string_view rhs) { return Node(std::string(rhs)); } + + static bool decode(const Node& node, std::string_view& rhs) { + if (!node.IsScalar()) + return false; + rhs = node.Scalar(); + return true; + } +}; +#endif + template <> struct convert<_Null> { static Node encode(const _Null& /* rhs */) { return Node(); } @@ -88,42 +117,100 @@ struct convert<_Null> { } }; -#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ - template <> \ - struct convert { \ - static Node encode(const type& rhs) { \ - std::stringstream stream; \ - stream.precision(std::numeric_limits::digits10 + 1); \ - stream << rhs; \ - return Node(stream.str()); \ - } \ - \ - static bool decode(const Node& node, type& rhs) { \ - if (node.Type() != NodeType::Scalar) \ - return false; \ - const std::string& input = node.Scalar(); \ - std::stringstream stream(input); \ - stream.unsetf(std::ios::dec); \ - if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \ - return true; \ - if (std::numeric_limits::has_infinity) { \ - if (conversion::IsInfinity(input)) { \ - rhs = std::numeric_limits::infinity(); \ - return true; \ - } else if (conversion::IsNegativeInfinity(input)) { \ - rhs = negative_op std::numeric_limits::infinity(); \ - return true; \ - } \ - } \ - \ - if (std::numeric_limits::has_quiet_NaN && \ - conversion::IsNaN(input)) { \ - rhs = std::numeric_limits::quiet_NaN(); \ - return true; \ - } \ - \ - return false; \ - } \ +namespace conversion { +template +typename std::enable_if< std::is_floating_point::value, void>::type +inner_encode(const T& rhs, std::stringstream& stream){ + if (std::isnan(rhs)) { + stream << ".nan"; + } else if (std::isinf(rhs)) { + if (std::signbit(rhs)) { + stream << "-.inf"; + } else { + stream << ".inf"; + } + } else { + stream << FpToString(rhs, stream.precision()); + } +} + +template +typename std::enable_if::value, void>::type +inner_encode(const T& rhs, std::stringstream& stream){ + stream << rhs; +} + +template +typename std::enable_if<(std::is_same::value || + std::is_same::value), bool>::type +ConvertStreamTo(std::stringstream& stream, T& rhs) { + int num; + if ((stream >> std::noskipws >> num) && (stream >> std::ws).eof()) { + if (num >= (std::numeric_limits::min)() && + num <= (std::numeric_limits::max)()) { + rhs = static_cast(num); + return true; + } + } + return false; +} + +template +typename std::enable_if::value || + std::is_same::value), bool>::type +ConvertStreamTo(std::stringstream& stream, T& rhs) { + if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) { + return true; + } + return false; +} +} + +#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ + template <> \ + struct convert { \ + \ + static Node encode(const type& rhs) { \ + std::stringstream stream; \ + stream.imbue(std::locale::classic()); \ + stream.precision(std::numeric_limits::max_digits10); \ + conversion::inner_encode(rhs, stream); \ + return Node(stream.str()); \ + } \ + \ + static bool decode(const Node& node, type& rhs) { \ + if (node.Type() != NodeType::Scalar) { \ + return false; \ + } \ + const std::string& input = node.Scalar(); \ + std::stringstream stream(input); \ + stream.imbue(std::locale::classic()); \ + stream.unsetf(std::ios::dec); \ + if ((stream.peek() == '-') && std::is_unsigned::value) { \ + return false; \ + } \ + if (conversion::ConvertStreamTo(stream, rhs)) { \ + return true; \ + } \ + if (std::numeric_limits::has_infinity) { \ + if (conversion::IsInfinity(input)) { \ + rhs = std::numeric_limits::infinity(); \ + return true; \ + } else if (conversion::IsNegativeInfinity(input)) { \ + rhs = negative_op std::numeric_limits::infinity(); \ + return true; \ + } \ + } \ + \ + if (std::numeric_limits::has_quiet_NaN) { \ + if (conversion::IsNaN(input)) { \ + rhs = std::numeric_limits::quiet_NaN(); \ + return true; \ + } \ + } \ + \ + return false; \ + } \ } #define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \ @@ -162,81 +249,104 @@ struct convert { }; // std::map -template -struct convert> { - static Node encode(const std::map& rhs) { +template +struct convert> { + static Node encode(const std::map& rhs) { Node node(NodeType::Map); - for (typename std::map::const_iterator it = rhs.begin(); - it != rhs.end(); ++it) - node.force_insert(it->first, it->second); + for (const auto& element : rhs) + node.force_insert(element.first, element.second); return node; } - static bool decode(const Node& node, std::map& rhs) { + static bool decode(const Node& node, std::map& rhs) { if (!node.IsMap()) return false; rhs.clear(); - for (const_iterator it = node.begin(); it != node.end(); ++it) + for (const auto& element : node) #if defined(__GNUC__) && __GNUC__ < 4 // workaround for GCC 3: - rhs[it->first.template as()] = it->second.template as(); + rhs[element.first.template as()] = element.second.template as(); #else - rhs[it->first.as()] = it->second.as(); + rhs[element.first.as()] = element.second.as(); +#endif + return true; + } +}; + +// std::unordered_map +template +struct convert> { + static Node encode(const std::unordered_map& rhs) { + Node node(NodeType::Map); + for (const auto& element : rhs) + node.force_insert(element.first, element.second); + return node; + } + + static bool decode(const Node& node, std::unordered_map& rhs) { + if (!node.IsMap()) + return false; + + rhs.clear(); + for (const auto& element : node) +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs[element.first.template as()] = element.second.template as(); +#else + rhs[element.first.as()] = element.second.as(); #endif return true; } }; // std::vector -template -struct convert> { - static Node encode(const std::vector& rhs) { +template +struct convert> { + static Node encode(const std::vector& rhs) { Node node(NodeType::Sequence); - for (typename std::vector::const_iterator it = rhs.begin(); - it != rhs.end(); ++it) - node.push_back(*it); + for (const auto& element : rhs) + node.push_back(element); return node; } - static bool decode(const Node& node, std::vector& rhs) { + static bool decode(const Node& node, std::vector& rhs) { if (!node.IsSequence()) return false; rhs.clear(); - for (const_iterator it = node.begin(); it != node.end(); ++it) + for (const auto& element : node) #if defined(__GNUC__) && __GNUC__ < 4 // workaround for GCC 3: - rhs.push_back(it->template as()); + rhs.push_back(element.template as()); #else - rhs.push_back(it->as()); + rhs.push_back(element.as()); #endif return true; } }; // std::list -template -struct convert> { - static Node encode(const std::list& rhs) { +template +struct convert> { + static Node encode(const std::list& rhs) { Node node(NodeType::Sequence); - for (typename std::list::const_iterator it = rhs.begin(); - it != rhs.end(); ++it) - node.push_back(*it); + for (const auto& element : rhs) + node.push_back(element); return node; } - static bool decode(const Node& node, std::list& rhs) { + static bool decode(const Node& node, std::list& rhs) { if (!node.IsSequence()) return false; rhs.clear(); - for (const_iterator it = node.begin(); it != node.end(); ++it) + for (const auto& element : node) #if defined(__GNUC__) && __GNUC__ < 4 // workaround for GCC 3: - rhs.push_back(it->template as()); + rhs.push_back(element.template as()); #else - rhs.push_back(it->as()); + rhs.push_back(element.as()); #endif return true; } @@ -275,6 +385,37 @@ struct convert> { } }; + +// std::valarray +template +struct convert> { + static Node encode(const std::valarray& rhs) { + Node node(NodeType::Sequence); + for (const auto& element : rhs) { + node.push_back(element); + } + return node; + } + + static bool decode(const Node& node, std::valarray& rhs) { + if (!node.IsSequence()) { + return false; + } + + rhs.resize(node.size()); + for (auto i = 0u; i < node.size(); ++i) { +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs[i] = node[i].template as(); +#else + rhs[i] = node[i].as(); +#endif + } + return true; + } +}; + + // std::pair template struct convert> { diff --git a/include/yaml-cpp/node/detail/bool_type.h b/include/yaml-cpp/node/detail/bool_type.h deleted file mode 100644 index 2c80705c9..000000000 --- a/include/yaml-cpp/node/detail/bool_type.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if defined(_MSC_VER) || \ - (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ - (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - -namespace YAML { -namespace detail { -struct unspecified_bool { - struct NOT_ALLOWED; - static void true_value(NOT_ALLOWED*) {} -}; -typedef void (*unspecified_bool_type)(unspecified_bool::NOT_ALLOWED*); -} -} - -#define YAML_CPP_OPERATOR_BOOL() \ - operator YAML::detail::unspecified_bool_type() const { \ - return this->operator!() ? 0 \ - : &YAML::detail::unspecified_bool::true_value; \ - } - -#endif // NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/detail/impl.h b/include/yaml-cpp/node/detail/impl.h index 09e55f838..b38038dfd 100644 --- a/include/yaml-cpp/node/detail/impl.h +++ b/include/yaml-cpp/node/detail/impl.h @@ -9,6 +9,8 @@ #include "yaml-cpp/node/detail/node.h" #include "yaml-cpp/node/detail/node_data.h" + +#include #include namespace YAML { @@ -17,7 +19,7 @@ template struct get_idx { static node* get(const std::vector& /* sequence */, const Key& /* key */, shared_memory_holder /* pMemory */) { - return 0; + return nullptr; } }; @@ -27,13 +29,13 @@ struct get_idx::value>::type> { static node* get(const std::vector& sequence, const Key& key, shared_memory_holder /* pMemory */) { - return key < sequence.size() ? sequence[key] : 0; + return key < sequence.size() ? sequence[key] : nullptr; } static node* get(std::vector& sequence, const Key& key, shared_memory_holder pMemory) { - if (key > sequence.size() || (key > 0 && !sequence[key-1]->is_defined())) - return 0; + if (key > sequence.size() || (key > 0 && !sequence[key - 1]->is_defined())) + return nullptr; if (key == sequence.size()) sequence.push_back(&pMemory->create_node()); return sequence[key]; @@ -46,13 +48,51 @@ struct get_idx::value>::type> { shared_memory_holder pMemory) { return key >= 0 ? get_idx::get( sequence, static_cast(key), pMemory) - : 0; + : nullptr; } static node* get(std::vector& sequence, const Key& key, shared_memory_holder pMemory) { return key >= 0 ? get_idx::get( sequence, static_cast(key), pMemory) - : 0; + : nullptr; + } +}; + +template +struct remove_idx { + static bool remove(std::vector&, const Key&, std::size_t&) { + return false; + } +}; + +template +struct remove_idx< + Key, typename std::enable_if::value && + !std::is_same::value>::type> { + + static bool remove(std::vector& sequence, const Key& key, + std::size_t& seqSize) { + if (key >= sequence.size()) { + return false; + } else { + sequence.erase(sequence.begin() + key); + if (seqSize > key) { + --seqSize; + } + return true; + } + } +}; + +template +struct remove_idx::value>::type> { + + static bool remove(std::vector& sequence, const Key& key, + std::size_t& seqSize) { + return key >= 0 ? remove_idx::remove( + sequence, static_cast(key), seqSize) + : false; } }; @@ -66,7 +106,11 @@ inline bool node::equals(const T& rhs, shared_memory_holder pMemory) { } inline bool node::equals(const char* rhs, shared_memory_holder pMemory) { - return equals(rhs, pMemory); + std::string lhs; + if (convert::decode(Node(*this, std::move(pMemory)), lhs)) { + return lhs == rhs; + } + return false; } // indexing @@ -78,22 +122,20 @@ inline node* node_data::get(const Key& key, break; case NodeType::Undefined: case NodeType::Null: - return NULL; + return nullptr; case NodeType::Sequence: if (node* pNode = get_idx::get(m_sequence, key, pMemory)) return pNode; - return NULL; + return nullptr; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(m_mark, key); } - for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { - if (it->first->equals(key, pMemory)) { - return it->second; - } - } + auto it = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) { + return m.first->equals(key, pMemory); + }); - return NULL; + return it != m_map.end() ? it->second : nullptr; } template @@ -112,13 +154,15 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) { convert_to_map(pMemory); break; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(m_mark, key); } - for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { - if (it->first->equals(key, pMemory)) { - return *it->second; - } + auto it = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) { + return m.first->equals(key, pMemory); + }); + + if (it != m_map.end()) { + return *it->second; } node& k = convert_to_node(key, pMemory); @@ -129,20 +173,26 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) { template inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) { - if (m_type != NodeType::Map) - return false; - - for (kv_pairs::iterator it = m_undefinedPairs.begin(); - it != m_undefinedPairs.end();) { - kv_pairs::iterator jt = std::next(it); - if (it->first->equals(key, pMemory)) - m_undefinedPairs.erase(it); - it = jt; + if (m_type == NodeType::Sequence) { + return remove_idx::remove(m_sequence, key, m_seqSize); } - for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) { - if (it->first->equals(key, pMemory)) { - m_map.erase(it); + if (m_type == NodeType::Map) { + kv_pairs::iterator it = m_undefinedPairs.begin(); + while (it != m_undefinedPairs.end()) { + kv_pairs::iterator jt = std::next(it); + if (it->first->equals(key, pMemory)) { + m_undefinedPairs.erase(it); + } + it = jt; + } + + auto iter = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) { + return m.first->equals(key, pMemory); + }); + + if (iter != m_map.end()) { + m_map.erase(iter); return true; } } diff --git a/include/yaml-cpp/node/detail/iterator.h b/include/yaml-cpp/node/detail/iterator.h index deec8fb62..04d2da4fc 100644 --- a/include/yaml-cpp/node/detail/iterator.h +++ b/include/yaml-cpp/node/detail/iterator.h @@ -8,25 +8,25 @@ #endif #include "yaml-cpp/dll.h" +#include "yaml-cpp/node/detail/node_iterator.h" #include "yaml-cpp/node/node.h" #include "yaml-cpp/node/ptr.h" -#include "yaml-cpp/node/detail/node_iterator.h" #include #include + namespace YAML { namespace detail { struct iterator_value; template -class iterator_base : public std::iterator { +class iterator_base { private: template friend class iterator_base; struct enabler {}; - typedef node_iterator base_type; + using base_type = node_iterator; struct proxy { explicit proxy(const V& x) : m_ref(x) {} @@ -37,7 +37,11 @@ class iterator_base : public std::iterator class iterator_base; } -typedef detail::iterator_base iterator; -typedef detail::iterator_base const_iterator; +using iterator = detail::iterator_base; +using const_iterator = detail::iterator_base; } #endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/detail/memory.h b/include/yaml-cpp/node/detail/memory.h index 8f2bc2657..942ab668d 100644 --- a/include/yaml-cpp/node/detail/memory.h +++ b/include/yaml-cpp/node/detail/memory.h @@ -22,11 +22,13 @@ namespace YAML { namespace detail { class YAML_CPP_API memory { public: + memory() : m_nodes{} {} node& create_node(); void merge(const memory& rhs); + size_t size() const; private: - typedef std::set Nodes; + using Nodes = std::set; Nodes m_nodes; }; @@ -40,7 +42,7 @@ class YAML_CPP_API memory_holder { private: shared_memory m_pMemory; }; -} -} +} // namespace detail +} // namespace YAML #endif // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/detail/node.h b/include/yaml-cpp/node/detail/node.h index 8a776f62a..acf60ffb6 100644 --- a/include/yaml-cpp/node/detail/node.h +++ b/include/yaml-cpp/node/detail/node.h @@ -7,18 +7,24 @@ #pragma once #endif -#include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/dll.h" -#include "yaml-cpp/node/type.h" -#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/node/detail/node_ref.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/type.h" #include +#include namespace YAML { namespace detail { class node { + private: + struct less { + bool operator ()(const node* l, const node* r) const {return l->m_index < r->m_index;} + }; + public: - node() : m_pRef(new node_ref) {} + node() : m_pRef(new node_ref), m_dependencies{}, m_index{} {} node(const node&) = delete; node& operator=(const node&) = delete; @@ -42,9 +48,8 @@ class node { return; m_pRef->mark_defined(); - for (nodes::iterator it = m_dependencies.begin(); - it != m_dependencies.end(); ++it) - (*it)->mark_defined(); + for (node* dependency : m_dependencies) + dependency->mark_defined(); m_dependencies.clear(); } @@ -109,6 +114,7 @@ class node { void push_back(node& input, shared_memory_holder pMemory) { m_pRef->push_back(input, pMemory); input.add_dependency(*this); + m_index = m_amount.fetch_add(1); } void insert(node& key, node& value, shared_memory_holder pMemory) { m_pRef->insert(key, value, pMemory); @@ -120,7 +126,7 @@ class node { template node* get(const Key& key, shared_memory_holder pMemory) const { // NOTE: this returns a non-const node so that the top-level Node can wrap - // it, and returns a pointer so that it can be NULL (if there is no such + // it, and returns a pointer so that it can be nullptr (if there is no such // key). return static_cast(*m_pRef).get(key, pMemory); } @@ -137,7 +143,7 @@ class node { node* get(node& key, shared_memory_holder pMemory) const { // NOTE: this returns a non-const node so that the top-level Node can wrap - // it, and returns a pointer so that it can be NULL (if there is no such + // it, and returns a pointer so that it can be nullptr (if there is no such // key). return static_cast(*m_pRef).get(key, pMemory); } @@ -160,10 +166,12 @@ class node { private: shared_node_ref m_pRef; - typedef std::set nodes; + using nodes = std::set; nodes m_dependencies; + size_t m_index; + static YAML_CPP_API std::atomic m_amount; }; -} -} +} // namespace detail +} // namespace YAML #endif // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/detail/node_data.h b/include/yaml-cpp/node/detail/node_data.h index 50bcd7435..07cf81aa0 100644 --- a/include/yaml-cpp/node/detail/node_data.h +++ b/include/yaml-cpp/node/detail/node_data.h @@ -60,8 +60,8 @@ class YAML_CPP_API node_data { node_iterator end(); // sequence - void push_back(node& node, shared_memory_holder pMemory); - void insert(node& key, node& value, shared_memory_holder pMemory); + void push_back(node& node, const shared_memory_holder& pMemory); + void insert(node& key, node& value, const shared_memory_holder& pMemory); // indexing template @@ -71,9 +71,9 @@ class YAML_CPP_API node_data { template bool remove(const Key& key, shared_memory_holder pMemory); - node* get(node& key, shared_memory_holder pMemory) const; - node& get(node& key, shared_memory_holder pMemory); - bool remove(node& key, shared_memory_holder pMemory); + node* get(node& key, const shared_memory_holder& pMemory) const; + node& get(node& key, const shared_memory_holder& pMemory); + bool remove(node& key, const shared_memory_holder& pMemory); // map template @@ -81,7 +81,7 @@ class YAML_CPP_API node_data { shared_memory_holder pMemory); public: - static std::string empty_scalar; + static const std::string& empty_scalar(); private: void compute_seq_size() const; @@ -91,8 +91,8 @@ class YAML_CPP_API node_data { void reset_map(); void insert_map_pair(node& key, node& value); - void convert_to_map(shared_memory_holder pMemory); - void convert_sequence_to_map(shared_memory_holder pMemory); + void convert_to_map(const shared_memory_holder& pMemory); + void convert_sequence_to_map(const shared_memory_holder& pMemory); template static node& convert_to_node(const T& rhs, shared_memory_holder pMemory); @@ -108,17 +108,17 @@ class YAML_CPP_API node_data { std::string m_scalar; // sequence - typedef std::vector node_seq; + using node_seq = std::vector; node_seq m_sequence; mutable std::size_t m_seqSize; // map - typedef std::vector> node_map; + using node_map = std::vector>; node_map m_map; - typedef std::pair kv_pair; - typedef std::list kv_pairs; + using kv_pair = std::pair; + using kv_pairs = std::list; mutable kv_pairs m_undefinedPairs; }; } diff --git a/include/yaml-cpp/node/detail/node_iterator.h b/include/yaml-cpp/node/detail/node_iterator.h index 088090fe7..6eb4ddc13 100644 --- a/include/yaml-cpp/node/detail/node_iterator.h +++ b/include/yaml-cpp/node/detail/node_iterator.h @@ -24,11 +24,11 @@ struct iterator_type { template struct node_iterator_value : public std::pair { - typedef std::pair kv; + using kv = std::pair; - node_iterator_value() : kv(), pNode(0) {} + node_iterator_value() : kv(), pNode(nullptr) {} explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {} - explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(0) {} + explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(nullptr) {} V& operator*() const { return *pNode; } V& operator->() const { return *pNode; } @@ -36,26 +36,23 @@ struct node_iterator_value : public std::pair { V* pNode; }; -typedef std::vector node_seq; -typedef std::vector> node_map; +using node_seq = std::vector; +using node_map = std::vector>; template struct node_iterator_type { - typedef node_seq::iterator seq; - typedef node_map::iterator map; + using seq = node_seq::iterator; + using map = node_map::iterator; }; template struct node_iterator_type { - typedef node_seq::const_iterator seq; - typedef node_map::const_iterator map; + using seq = node_seq::const_iterator; + using map = node_map::const_iterator; }; template -class node_iterator_base - : public std::iterator, - std::ptrdiff_t, node_iterator_value*, - node_iterator_value> { +class node_iterator_base { private: struct enabler {}; @@ -68,9 +65,13 @@ class node_iterator_base }; public: - typedef typename node_iterator_type::seq SeqIter; - typedef typename node_iterator_type::map MapIter; - typedef node_iterator_value value_type; + using iterator_category = std::forward_iterator_tag; + using value_type = node_iterator_value; + using difference_type = std::ptrdiff_t; + using pointer = node_iterator_value*; + using reference = node_iterator_value&; + using SeqIter = typename node_iterator_type::seq; + using MapIter = typename node_iterator_type::map; node_iterator_base() : m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {} @@ -172,8 +173,8 @@ class node_iterator_base MapIter m_mapIt, m_mapEnd; }; -typedef node_iterator_base node_iterator; -typedef node_iterator_base const_node_iterator; +using node_iterator = node_iterator_base; +using const_node_iterator = node_iterator_base; } } diff --git a/include/yaml-cpp/node/impl.h b/include/yaml-cpp/node/impl.h index 20c487a68..f5d622b25 100644 --- a/include/yaml-cpp/node/impl.h +++ b/include/yaml-cpp/node/impl.h @@ -7,18 +7,21 @@ #pragma once #endif -#include "yaml-cpp/node/node.h" -#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/exceptions.h" #include "yaml-cpp/node/detail/memory.h" #include "yaml-cpp/node/detail/node.h" -#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/node/node.h" +#include #include namespace YAML { -inline Node::Node() : m_isValid(true), m_pNode(NULL) {} +inline Node::Node() + : m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {} inline Node::Node(NodeType::value type) : m_isValid(true), + m_invalidKey{}, m_pMemory(new detail::memory_holder), m_pNode(&m_pMemory->create_node()) { m_pNode->set_type(type); @@ -27,6 +30,7 @@ inline Node::Node(NodeType::value type) template inline Node::Node(const T& rhs) : m_isValid(true), + m_invalidKey{}, m_pMemory(new detail::memory_holder), m_pNode(&m_pMemory->create_node()) { Assign(rhs); @@ -34,24 +38,26 @@ inline Node::Node(const T& rhs) inline Node::Node(const detail::iterator_value& rhs) : m_isValid(rhs.m_isValid), + m_invalidKey(rhs.m_invalidKey), m_pMemory(rhs.m_pMemory), m_pNode(rhs.m_pNode) {} -inline Node::Node(const Node& rhs) - : m_isValid(rhs.m_isValid), - m_pMemory(rhs.m_pMemory), - m_pNode(rhs.m_pNode) {} +inline Node::Node(const Node&) = default; + +inline Node::Node(Zombie) + : m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {} -inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {} +inline Node::Node(Zombie, const std::string& key) + : m_isValid(false), m_invalidKey(key), m_pMemory{}, m_pNode(nullptr) {} inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory) - : m_isValid(true), m_pMemory(pMemory), m_pNode(&node) {} + : m_isValid(true), m_invalidKey{}, m_pMemory(pMemory), m_pNode(&node) {} -inline Node::~Node() {} +inline Node::~Node() = default; inline void Node::EnsureNodeExists() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); if (!m_pNode) { m_pMemory.reset(new detail::memory_holder); m_pNode = &m_pMemory->create_node(); @@ -68,14 +74,14 @@ inline bool Node::IsDefined() const { inline Mark Node::Mark() const { if (!m_isValid) { - throw InvalidNode(); + throw InvalidNode(m_invalidKey); } return m_pNode ? m_pNode->mark() : Mark::null_mark(); } inline NodeType::value Node::Type() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->type() : NodeType::Null; } @@ -91,7 +97,7 @@ struct as_if { if (!node.m_pNode) return fallback; - T t; + T t = fallback; if (convert::decode(node, t)) return t; return fallback; @@ -104,6 +110,8 @@ struct as_if { const Node& node; std::string operator()(const S& fallback) const { + if (node.Type() == NodeType::Null) + return "null"; if (node.Type() != NodeType::Scalar) return fallback; return node.Scalar(); @@ -116,8 +124,8 @@ struct as_if { const Node& node; T operator()() const { - if (!node.m_pNode) - throw TypedBadConversion(node.Mark()); + if (!node.m_pNode) // no fallback + throw InvalidNode(node.m_invalidKey); T t; if (convert::decode(node, t)) @@ -132,6 +140,10 @@ struct as_if { const Node& node; std::string operator()() const { + if (node.Type() == NodeType::Undefined) // no fallback + throw InvalidNode(node.m_invalidKey); + if (node.Type() == NodeType::Null) + return "null"; if (node.Type() != NodeType::Scalar) throw TypedBadConversion(node.Mark()); return node.Scalar(); @@ -142,7 +154,7 @@ struct as_if { template inline T Node::as() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return as_if(*this)(); } @@ -155,32 +167,28 @@ inline T Node::as(const S& fallback) const { inline const std::string& Node::Scalar() const { if (!m_isValid) - throw InvalidNode(); - return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar; + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar(); } inline const std::string& Node::Tag() const { if (!m_isValid) - throw InvalidNode(); - return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar; + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar(); } inline void Node::SetTag(const std::string& tag) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); m_pNode->set_tag(tag); } inline EmitterStyle::value Node::Style() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->style() : EmitterStyle::Default; } inline void Node::SetStyle(EmitterStyle::value style) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); m_pNode->set_style(style); } @@ -188,7 +196,7 @@ inline void Node::SetStyle(EmitterStyle::value style) { // assignment inline bool Node::is(const Node& rhs) const { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); if (!m_pNode || !rhs.m_pNode) return false; return m_pNode->is(*rhs.m_pNode); @@ -196,15 +204,20 @@ inline bool Node::is(const Node& rhs) const { template inline Node& Node::operator=(const T& rhs) { - if (!m_isValid) - throw InvalidNode(); Assign(rhs); return *this; } +inline Node& Node::operator=(const Node& rhs) { + if (is(rhs)) + return *this; + AssignNode(rhs); + return *this; +} + inline void Node::reset(const YAML::Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); m_pMemory = rhs.m_pMemory; m_pNode = rhs.m_pNode; } @@ -212,44 +225,27 @@ inline void Node::reset(const YAML::Node& rhs) { template inline void Node::Assign(const T& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); AssignData(convert::encode(rhs)); } template <> inline void Node::Assign(const std::string& rhs) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); m_pNode->set_scalar(rhs); } inline void Node::Assign(const char* rhs) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); m_pNode->set_scalar(rhs); } inline void Node::Assign(char* rhs) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); m_pNode->set_scalar(rhs); } -inline Node& Node::operator=(const Node& rhs) { - if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); - if (is(rhs)) - return *this; - AssignNode(rhs); - return *this; -} - inline void Node::AssignData(const Node& rhs) { - if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); EnsureNodeExists(); rhs.EnsureNodeExists(); @@ -258,8 +254,8 @@ inline void Node::AssignData(const Node& rhs) { } inline void Node::AssignNode(const Node& rhs) { - if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + if (!m_isValid) + throw InvalidNode(m_invalidKey); rhs.EnsureNodeExists(); if (!m_pNode) { @@ -276,7 +272,7 @@ inline void Node::AssignNode(const Node& rhs) { // size/iterator inline std::size_t Node::size() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->size() : 0; } @@ -309,13 +305,11 @@ inline iterator Node::end() { template inline void Node::push_back(const T& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); push_back(Node(rhs)); } inline void Node::push_back(const Node& rhs) { - if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); EnsureNodeExists(); rhs.EnsureNodeExists(); @@ -323,99 +317,49 @@ inline void Node::push_back(const Node& rhs) { m_pMemory->merge(*rhs.m_pMemory); } -// helpers for indexing -namespace detail { -template -struct to_value_t { - explicit to_value_t(const T& t_) : t(t_) {} - const T& t; - typedef const T& return_type; - - const T& operator()() const { return t; } -}; - -template <> -struct to_value_t { - explicit to_value_t(const char* t_) : t(t_) {} - const char* t; - typedef std::string return_type; - - const std::string operator()() const { return t; } -}; - -template <> -struct to_value_t { - explicit to_value_t(char* t_) : t(t_) {} - const char* t; - typedef std::string return_type; - - const std::string operator()() const { return t; } -}; - -template -struct to_value_t { - explicit to_value_t(const char* t_) : t(t_) {} - const char* t; - typedef std::string return_type; - - const std::string operator()() const { return t; } -}; - -// converts C-strings to std::strings so they can be copied -template -inline typename to_value_t::return_type to_value(const T& t) { - return to_value_t(t)(); -} +template +std::string key_to_string(const Key& key) { + return streamable_to_string::value>().impl(key); } // indexing template inline const Node Node::operator[](const Key& key) const { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); - detail::node* value = static_cast(*m_pNode) - .get(detail::to_value(key), m_pMemory); + detail::node* value = + static_cast(*m_pNode).get(key, m_pMemory); if (!value) { - return Node(ZombieNode); + return Node(ZombieNode, key_to_string(key)); } return Node(*value, m_pMemory); } template inline Node Node::operator[](const Key& key) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); - detail::node& value = m_pNode->get(detail::to_value(key), m_pMemory); + detail::node& value = m_pNode->get(key, m_pMemory); return Node(value, m_pMemory); } template inline bool Node::remove(const Key& key) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); - return m_pNode->remove(detail::to_value(key), m_pMemory); + return m_pNode->remove(key, m_pMemory); } inline const Node Node::operator[](const Node& key) const { - if (!m_isValid || !key.m_isValid) - throw InvalidNode(); EnsureNodeExists(); key.EnsureNodeExists(); m_pMemory->merge(*key.m_pMemory); detail::node* value = static_cast(*m_pNode).get(*key.m_pNode, m_pMemory); if (!value) { - return Node(ZombieNode); + return Node(ZombieNode, key_to_string(key)); } return Node(*value, m_pMemory); } inline Node Node::operator[](const Node& key) { - if (!m_isValid || !key.m_isValid) - throw InvalidNode(); EnsureNodeExists(); key.EnsureNodeExists(); m_pMemory->merge(*key.m_pMemory); @@ -424,8 +368,6 @@ inline Node Node::operator[](const Node& key) { } inline bool Node::remove(const Node& key) { - if (!m_isValid || !key.m_isValid) - throw InvalidNode(); EnsureNodeExists(); key.EnsureNodeExists(); return m_pNode->remove(*key.m_pNode, m_pMemory); @@ -434,15 +376,12 @@ inline bool Node::remove(const Node& key) { // map template inline void Node::force_insert(const Key& key, const Value& value) { - if (!m_isValid) - throw InvalidNode(); EnsureNodeExists(); - m_pNode->force_insert(detail::to_value(key), detail::to_value(value), - m_pMemory); + m_pNode->force_insert(key, value, m_pMemory); } // free functions inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); } -} +} // namespace YAML #endif // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/iterator.h b/include/yaml-cpp/node/iterator.h index 366a9c807..1fcf6e400 100644 --- a/include/yaml-cpp/node/iterator.h +++ b/include/yaml-cpp/node/iterator.h @@ -15,10 +15,13 @@ #include #include +// Assert in place so gcc + libc++ combination properly builds +static_assert(std::is_constructible::value, "Node must be copy constructable"); + namespace YAML { namespace detail { struct iterator_value : public Node, std::pair { - iterator_value() {} + iterator_value() = default; explicit iterator_value(const Node& rhs) : Node(rhs), std::pair(Node(Node::ZombieNode), Node(Node::ZombieNode)) {} diff --git a/include/yaml-cpp/node/node.h b/include/yaml-cpp/node/node.h index 1ded7d27b..c9e9a0a4b 100644 --- a/include/yaml-cpp/node/node.h +++ b/include/yaml-cpp/node/node.h @@ -8,11 +8,11 @@ #endif #include +#include #include "yaml-cpp/dll.h" #include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/mark.h" -#include "yaml-cpp/node/detail/bool_type.h" #include "yaml-cpp/node/detail/iterator_fwd.h" #include "yaml-cpp/node/ptr.h" #include "yaml-cpp/node/type.h" @@ -38,8 +38,8 @@ class YAML_CPP_API Node { template friend struct as_if; - typedef YAML::iterator iterator; - typedef YAML::const_iterator const_iterator; + using iterator = YAML::iterator; + using const_iterator = YAML::const_iterator; Node(); explicit Node(NodeType::value type); @@ -58,7 +58,7 @@ class YAML_CPP_API Node { bool IsMap() const { return Type() == NodeType::Map; } // bool conversions - YAML_CPP_OPERATOR_BOOL() + explicit operator bool() const { return IsDefined(); } bool operator!() const { return !IsDefined(); } // access @@ -116,6 +116,7 @@ class YAML_CPP_API Node { private: enum Zombie { ZombieNode }; explicit Node(Zombie); + explicit Node(Zombie, const std::string&); explicit Node(detail::node& node, detail::shared_memory_holder pMemory); void EnsureNodeExists() const; @@ -130,6 +131,8 @@ class YAML_CPP_API Node { private: bool m_isValid; + // String representation of invalid key, if the node is invalid. + std::string m_invalidKey; mutable detail::shared_memory_holder m_pMemory; mutable detail::node* m_pNode; }; diff --git a/include/yaml-cpp/node/ptr.h b/include/yaml-cpp/node/ptr.h index ce085dd5c..f55d95ed9 100644 --- a/include/yaml-cpp/node/ptr.h +++ b/include/yaml-cpp/node/ptr.h @@ -7,7 +7,6 @@ #pragma once #endif -#include "yaml-cpp/dll.h" #include namespace YAML { @@ -18,11 +17,11 @@ class node_data; class memory; class memory_holder; -typedef std::shared_ptr shared_node; -typedef std::shared_ptr shared_node_ref; -typedef std::shared_ptr shared_node_data; -typedef std::shared_ptr shared_memory_holder; -typedef std::shared_ptr shared_memory; +using shared_node = std::shared_ptr; +using shared_node_ref = std::shared_ptr; +using shared_node_data = std::shared_ptr; +using shared_memory_holder = std::shared_ptr; +using shared_memory = std::shared_ptr; } } diff --git a/include/yaml-cpp/node/type.h b/include/yaml-cpp/node/type.h index 9d55ca966..b1237670c 100644 --- a/include/yaml-cpp/node/type.h +++ b/include/yaml-cpp/node/type.h @@ -8,9 +8,10 @@ #endif namespace YAML { -struct NodeType { - enum value { Undefined, Null, Scalar, Sequence, Map }; -}; +namespace NodeType { +enum value { Undefined, Null, Scalar, Sequence, Map }; +} + } #endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/noexcept.h b/include/yaml-cpp/noexcept.h new file mode 100644 index 000000000..6aac63516 --- /dev/null +++ b/include/yaml-cpp/noexcept.h @@ -0,0 +1,18 @@ +#ifndef NOEXCEPT_H_768872DA_476C_11EA_88B8_90B11C0C0FF8 +#define NOEXCEPT_H_768872DA_476C_11EA_88B8_90B11C0C0FF8 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +// This is here for compatibility with older versions of Visual Studio +// which don't support noexcept. +#if defined(_MSC_VER) && _MSC_VER < 1900 + #define YAML_CPP_NOEXCEPT _NOEXCEPT +#else + #define YAML_CPP_NOEXCEPT noexcept +#endif + +#endif diff --git a/include/yaml-cpp/noncopyable.h b/include/yaml-cpp/noncopyable.h deleted file mode 100644 index a26104073..000000000 --- a/include/yaml-cpp/noncopyable.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if defined(_MSC_VER) || \ - (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ - (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - -#include "yaml-cpp/dll.h" - -namespace YAML { -// this is basically boost::noncopyable -class YAML_CPP_API noncopyable { - protected: - noncopyable() {} - ~noncopyable() {} - - private: - noncopyable(const noncopyable&); - const noncopyable& operator=(const noncopyable&); -}; -} - -#endif // NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/null.h b/include/yaml-cpp/null.h index b9521d488..472e961ea 100644 --- a/include/yaml-cpp/null.h +++ b/include/yaml-cpp/null.h @@ -8,7 +8,7 @@ #endif #include "yaml-cpp/dll.h" -#include +#include namespace YAML { class Node; @@ -18,7 +18,7 @@ inline bool operator==(const _Null&, const _Null&) { return true; } inline bool operator!=(const _Null&, const _Null&) { return false; } YAML_CPP_API bool IsNull(const Node& node); // old API only -YAML_CPP_API bool IsNullString(const std::string& str); +YAML_CPP_API bool IsNullString(const char* str, std::size_t size); extern YAML_CPP_API _Null Null; } diff --git a/include/yaml-cpp/ostream_wrapper.h b/include/yaml-cpp/ostream_wrapper.h index 09d45f39b..cf89741d0 100644 --- a/include/yaml-cpp/ostream_wrapper.h +++ b/include/yaml-cpp/ostream_wrapper.h @@ -17,6 +17,10 @@ class YAML_CPP_API ostream_wrapper { public: ostream_wrapper(); explicit ostream_wrapper(std::ostream& stream); + ostream_wrapper(const ostream_wrapper&) = delete; + ostream_wrapper(ostream_wrapper&&) = delete; + ostream_wrapper& operator=(const ostream_wrapper&) = delete; + ostream_wrapper& operator=(ostream_wrapper&&) = delete; ~ostream_wrapper(); void write(const std::string& str); @@ -26,7 +30,7 @@ class YAML_CPP_API ostream_wrapper { const char* str() const { if (m_pStream) { - return 0; + return nullptr; } else { m_buffer[m_pos] = '\0'; return &m_buffer[0]; @@ -52,7 +56,7 @@ class YAML_CPP_API ostream_wrapper { template inline ostream_wrapper& operator<<(ostream_wrapper& stream, - const char(&str)[N]) { + const char (&str)[N]) { stream.write(str, N - 1); return stream; } @@ -67,6 +71,6 @@ inline ostream_wrapper& operator<<(ostream_wrapper& stream, char ch) { stream.write(&ch, 1); return stream; } -} +} // namespace YAML #endif // OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/parser.h b/include/yaml-cpp/parser.h index ceac22d02..2f403c350 100644 --- a/include/yaml-cpp/parser.h +++ b/include/yaml-cpp/parser.h @@ -11,7 +11,6 @@ #include #include "yaml-cpp/dll.h" -#include "yaml-cpp/noncopyable.h" namespace YAML { class EventHandler; @@ -24,11 +23,16 @@ struct Token; * A parser turns a stream of bytes into one stream of "events" per YAML * document in the input stream. */ -class YAML_CPP_API Parser : private noncopyable { +class YAML_CPP_API Parser { public: /** Constructs an empty parser (with no input. */ Parser(); + Parser(const Parser&) = delete; + Parser(Parser&&) = delete; + Parser& operator=(const Parser&) = delete; + Parser& operator=(Parser&&) = delete; + /** * Constructs a parser from the given input stream. The input stream must * live as long as the parser. @@ -81,6 +85,6 @@ class YAML_CPP_API Parser : private noncopyable { std::unique_ptr m_pScanner; std::unique_ptr m_pDirectives; }; -} +} // namespace YAML #endif // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/stlemitter.h b/include/yaml-cpp/stlemitter.h index 06780c861..210a2f64e 100644 --- a/include/yaml-cpp/stlemitter.h +++ b/include/yaml-cpp/stlemitter.h @@ -16,8 +16,8 @@ namespace YAML { template inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) { emitter << BeginSeq; - for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it) - emitter << *it; + for (const auto& v : seq) + emitter << v; emitter << EndSeq; return emitter; } @@ -39,10 +39,9 @@ inline Emitter& operator<<(Emitter& emitter, const std::set& v) { template inline Emitter& operator<<(Emitter& emitter, const std::map& m) { - typedef typename std::map map; emitter << BeginMap; - for (typename map::const_iterator it = m.begin(); it != m.end(); ++it) - emitter << Key << it->first << Value << it->second; + for (const auto& v : m) + emitter << Key << v.first << Value << v.second; emitter << EndMap; return emitter; } diff --git a/include/yaml-cpp/traits.h b/include/yaml-cpp/traits.h index f33d0e1f6..8df939305 100644 --- a/include/yaml-cpp/traits.h +++ b/include/yaml-cpp/traits.h @@ -7,6 +7,11 @@ #pragma once #endif +#include +#include +#include +#include + namespace YAML { template struct is_numeric { @@ -79,7 +84,7 @@ struct is_numeric { template struct enable_if_c { - typedef T type; + using type = T; }; template @@ -90,7 +95,7 @@ struct enable_if : public enable_if_c {}; template struct disable_if_c { - typedef T type; + using type = T; }; template @@ -100,4 +105,32 @@ template struct disable_if : public disable_if_c {}; } +template +struct is_streamable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); + + template + static auto test(...) -> std::false_type; + + static const bool value = decltype(test(0))::value; +}; + +template +struct streamable_to_string { + static std::string impl(const Key& key) { + std::stringstream ss; + ss.imbue(std::locale::classic()); + ss << key; + return ss.str(); + } +}; + +template +struct streamable_to_string { + static std::string impl(const Key&) { + return ""; + } +}; #endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/yaml.h b/include/yaml-cpp/yaml.h index 7f515efb9..7da7cf333 100644 --- a/include/yaml-cpp/yaml.h +++ b/include/yaml-cpp/yaml.h @@ -7,6 +7,8 @@ #pragma once #endif +// IWYU pragma: begin_exports + #include "yaml-cpp/parser.h" #include "yaml-cpp/emitter.h" #include "yaml-cpp/emitterstyle.h" @@ -21,4 +23,6 @@ #include "yaml-cpp/node/parse.h" #include "yaml-cpp/node/emit.h" +// IWYU pragma: end_exports + #endif // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/binary.cpp b/src/binary.cpp index a7e51301b..d27762a24 100644 --- a/src/binary.cpp +++ b/src/binary.cpp @@ -1,5 +1,7 @@ #include "yaml-cpp/binary.h" +#include + namespace YAML { static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -64,7 +66,7 @@ static const unsigned char decoding[] = { }; std::vector DecodeBase64(const std::string &input) { - typedef std::vector ret_type; + using ret_type = std::vector; if (input.empty()) return ret_type(); @@ -72,22 +74,27 @@ std::vector DecodeBase64(const std::string &input) { unsigned char *out = &ret[0]; unsigned value = 0; - for (std::size_t i = 0; i < input.size(); i++) { - unsigned char d = decoding[static_cast(input[i])]; + for (std::size_t i = 0, cnt = 0; i < input.size(); i++) { + if (std::isspace(static_cast(input[i]))) { + // skip newlines + continue; + } + unsigned char d = decoding[static_cast(input[i])]; if (d == 255) return ret_type(); value = (value << 6) | d; - if (i % 4 == 3) { + if (cnt % 4 == 3) { *out++ = value >> 16; if (i > 0 && input[i - 1] != '=') *out++ = value >> 8; if (input[i] != '=') *out++ = value; } + ++cnt; } ret.resize(out - &ret[0]); return ret; } -} +} // namespace YAML diff --git a/src/collectionstack.h b/src/collectionstack.h index 2302786e0..9feba9679 100644 --- a/src/collectionstack.h +++ b/src/collectionstack.h @@ -7,8 +7,8 @@ #pragma once #endif -#include #include +#include namespace YAML { struct CollectionType { @@ -17,6 +17,7 @@ struct CollectionType { class CollectionStack { public: + CollectionStack() : collectionStack{} {} CollectionType::value GetCurCollectionType() const { if (collectionStack.empty()) return CollectionType::NoCollection; @@ -28,12 +29,13 @@ class CollectionStack { } void PopCollectionType(CollectionType::value type) { assert(type == GetCurCollectionType()); + (void)type; collectionStack.pop(); } private: std::stack collectionStack; }; -} +} // namespace YAML #endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/contrib/dragonbox.h b/src/contrib/dragonbox.h new file mode 100644 index 000000000..de5a79f11 --- /dev/null +++ b/src/contrib/dragonbox.h @@ -0,0 +1,4196 @@ +// SPDX-FileCopyrightText: 2020-2024 Junekey Jeon +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// SPDX-License-Identifier: BSL-1.0 +// SPDX-License-Identifier: MIT + +// This file is an adjusted copy of https://github.com/jk-jeon/dragonbox +// Junekey Jeon agreed to license this file under MIT license explicitly for +// usage in yaml-cpp. +// +// Changes to the original dragonbox library: +// - Added additional license information and information at top +// - Wrapped the 'jkj' namespace in an additional 'YAML' namespace + +#ifndef JKJ_HEADER_DRAGONBOX +#define JKJ_HEADER_DRAGONBOX + +// Attribute for storing static data into a dedicated place, e.g. flash memory. Every ODR-used +// static data declaration will be decorated with this macro. The users may define this macro, +// before including the library headers, into whatever they want. +#ifndef JKJ_STATIC_DATA_SECTION + #define JKJ_STATIC_DATA_SECTION +#else + #define JKJ_STATIC_DATA_SECTION_DEFINED 1 +#endif + +// To use the library with toolchains without standard C++ headers, the users may define this macro +// into their custom namespace which contains the defintions of all the standard C++ library +// features used in this header. (The list can be found below.) +#ifndef JKJ_STD_REPLACEMENT_NAMESPACE + #define JKJ_STD_REPLACEMENT_NAMESPACE std + #include + #include + #include + #include + #include + + #ifdef __has_include + #if __has_include() + #include + #endif + #endif +#else + #define JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Language feature detections. +//////////////////////////////////////////////////////////////////////////////////////// + +// C++14 constexpr +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L + #define JKJ_HAS_CONSTEXPR14 1 +#elif __cplusplus >= 201402L + #define JKJ_HAS_CONSTEXPR14 1 +#elif defined(_MSC_VER) && _MSC_VER >= 1910 && _MSVC_LANG >= 201402L + #define JKJ_HAS_CONSTEXPR14 1 +#else + #define JKJ_HAS_CONSTEXPR14 0 +#endif + +#if JKJ_HAS_CONSTEXPR14 + #define JKJ_CONSTEXPR14 constexpr +#else + #define JKJ_CONSTEXPR14 +#endif + +// C++17 constexpr lambdas +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201603L + #define JKJ_HAS_CONSTEXPR17 1 +#elif __cplusplus >= 201703L + #define JKJ_HAS_CONSTEXPR17 1 +#elif defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L + #define JKJ_HAS_CONSTEXPR17 1 +#else + #define JKJ_HAS_CONSTEXPR17 0 +#endif + +// C++17 inline variables +#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L + #define JKJ_HAS_INLINE_VARIABLE 1 +#elif __cplusplus >= 201703L + #define JKJ_HAS_INLINE_VARIABLE 1 +#elif defined(_MSC_VER) && _MSC_VER >= 1912 && _MSVC_LANG >= 201703L + #define JKJ_HAS_INLINE_VARIABLE 1 +#else + #define JKJ_HAS_INLINE_VARIABLE 0 +#endif + +#if JKJ_HAS_INLINE_VARIABLE + #define JKJ_INLINE_VARIABLE inline constexpr +#else + #define JKJ_INLINE_VARIABLE static constexpr +#endif + +// C++17 if constexpr +#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L + #define JKJ_HAS_IF_CONSTEXPR 1 +#elif __cplusplus >= 201703L + #define JKJ_HAS_IF_CONSTEXPR 1 +#elif defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L + #define JKJ_HAS_IF_CONSTEXPR 1 +#else + #define JKJ_HAS_IF_CONSTEXPR 0 +#endif + +#if JKJ_HAS_IF_CONSTEXPR + #define JKJ_IF_CONSTEXPR if constexpr +#else + #define JKJ_IF_CONSTEXPR if +#endif + +// C++20 std::bit_cast +#if JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED + #if JKJ_STD_REPLACEMENT_HAS_BIT_CAST + #define JKJ_HAS_BIT_CAST 1 + #else + #define JKJ_HAS_BIT_CAST 0 + #endif +#elif defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L + #include + #define JKJ_HAS_BIT_CAST 1 +#else + #define JKJ_HAS_BIT_CAST 0 +#endif + +// C++23 if consteval or C++20 std::is_constant_evaluated +#if defined(__cpp_if_consteval) && __cpp_is_consteval >= 202106L + #define JKJ_IF_CONSTEVAL if consteval + #define JKJ_IF_NOT_CONSTEVAL if !consteval + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 1 + #define JKJ_USE_IS_CONSTANT_EVALUATED 0 +#elif JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED + #if JKJ_STD_REPLACEMENT_HAS_IS_CONSTANT_EVALUATED + #define JKJ_IF_CONSTEVAL if (stdr::is_constant_evaluated()) + #define JKJ_IF_NOT_CONSTEVAL if (!stdr::is_constant_evaluated()) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 1 + #define JKJ_USE_IS_CONSTANT_EVALUATED 1 + #elif JKJ_HAS_IF_CONSTEXPR + #define JKJ_IF_CONSTEVAL if constexpr (false) + #define JKJ_IF_NOT_CONSTEVAL if constexpr (true) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 0 + #define JKJ_USE_IS_CONSTANT_EVALUATED 0 + #else + #define JKJ_IF_CONSTEVAL if (false) + #define JKJ_IF_NOT_CONSTEVAL if (true) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 0 + #define JKJ_USE_IS_CONSTANT_EVALUATED 0 + #endif +#else + #if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L + #define JKJ_IF_CONSTEVAL if (stdr::is_constant_evaluated()) + #define JKJ_IF_NOT_CONSTEVAL if (!stdr::is_constant_evaluated()) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 1 + #define JKJ_USE_IS_CONSTANT_EVALUATED 1 + #elif JKJ_HAS_IF_CONSTEXPR + #define JKJ_IF_CONSTEVAL if constexpr (false) + #define JKJ_IF_NOT_CONSTEVAL if constexpr (true) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 0 + #define JKJ_USE_IS_CONSTANT_EVALUATED 0 + #else + #define JKJ_IF_CONSTEVAL if (false) + #define JKJ_IF_NOT_CONSTEVAL if (true) + #define JKJ_CAN_BRANCH_ON_CONSTEVAL 0 + #define JKJ_USE_IS_CONSTANT_EVALUATED 0 + #endif +#endif + +#if JKJ_CAN_BRANCH_ON_CONSTEVAL && JKJ_HAS_BIT_CAST + #define JKJ_CONSTEXPR20 constexpr +#else + #define JKJ_CONSTEXPR20 +#endif + +// Suppress additional buffer overrun check. +// I have no idea why MSVC thinks some functions here are vulnerable to the buffer overrun +// attacks. No, they aren't. +#if defined(__GNUC__) || defined(__clang__) + #define JKJ_SAFEBUFFERS + #define JKJ_FORCEINLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define JKJ_SAFEBUFFERS __declspec(safebuffers) + #define JKJ_FORCEINLINE __forceinline +#else + #define JKJ_SAFEBUFFERS + #define JKJ_FORCEINLINE inline +#endif + +#if defined(__has_builtin) + #define JKJ_HAS_BUILTIN(x) __has_builtin(x) +#else + #define JKJ_HAS_BUILTIN(x) false +#endif + +#if defined(_MSC_VER) + #include +#elif defined(__INTEL_COMPILER) + #include +#endif + +namespace YAML { +namespace jkj { + namespace dragonbox { + //////////////////////////////////////////////////////////////////////////////////////// + // The Compatibility layer for toolchains without standard C++ headers. + //////////////////////////////////////////////////////////////////////////////////////// + namespace detail { + namespace stdr { + // +#if JKJ_HAS_BIT_CAST + using JKJ_STD_REPLACEMENT_NAMESPACE::bit_cast; +#endif + + // + // We need assert() macro, but it is not namespaced anyway, so nothing to do here. + + // + using JKJ_STD_REPLACEMENT_NAMESPACE::int_least8_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::int_least16_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::int_least32_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::int_fast8_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::int_fast16_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::int_fast32_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_least8_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_least16_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_least32_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_least64_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_fast8_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_fast16_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::uint_fast32_t; + // We need INT32_C, UINT32_C and UINT64_C macros too, but again there is nothing to do + // here. + + // + using JKJ_STD_REPLACEMENT_NAMESPACE::size_t; + using JKJ_STD_REPLACEMENT_NAMESPACE::memcpy; + + // + template + using numeric_limits = JKJ_STD_REPLACEMENT_NAMESPACE::numeric_limits; + + // + template + using enable_if = JKJ_STD_REPLACEMENT_NAMESPACE::enable_if; + template + using add_rvalue_reference = JKJ_STD_REPLACEMENT_NAMESPACE::add_rvalue_reference; + template + using conditional = JKJ_STD_REPLACEMENT_NAMESPACE::conditional; +#if JKJ_USE_IS_CONSTANT_EVALUATED + using JKJ_STD_REPLACEMENT_NAMESPACE::is_constant_evaluated; +#endif + template + using is_same = JKJ_STD_REPLACEMENT_NAMESPACE::is_same; +#if !JKJ_HAS_BIT_CAST + template + using is_trivially_copyable = JKJ_STD_REPLACEMENT_NAMESPACE::is_trivially_copyable; +#endif + template + using is_integral = JKJ_STD_REPLACEMENT_NAMESPACE::is_integral; + template + using is_signed = JKJ_STD_REPLACEMENT_NAMESPACE::is_signed; + template + using is_unsigned = JKJ_STD_REPLACEMENT_NAMESPACE::is_unsigned; + } + } + + + //////////////////////////////////////////////////////////////////////////////////////// + // Some general utilities for C++11-compatibility. + //////////////////////////////////////////////////////////////////////////////////////// + namespace detail { +#if !JKJ_HAS_CONSTEXPR17 + template + struct index_sequence {}; + + template + struct make_index_sequence_impl { + using type = typename make_index_sequence_impl::type; + }; + + template + struct make_index_sequence_impl { + using type = index_sequence; + }; + + template + using make_index_sequence = typename make_index_sequence_impl<0, N, void>::type; +#endif + + // Available since C++11, but including just for this is an overkill. + template + typename stdr::add_rvalue_reference::type declval() noexcept; + + // Similarly, including is an overkill. + template + struct array { + T data_[N]; + constexpr T operator[](stdr::size_t idx) const noexcept { return data_[idx]; } + JKJ_CONSTEXPR14 T& operator[](stdr::size_t idx) noexcept { return data_[idx]; } + }; + } + + + //////////////////////////////////////////////////////////////////////////////////////// + // Some basic features for encoding/decoding IEEE-754 formats. + //////////////////////////////////////////////////////////////////////////////////////// + namespace detail { + template + struct physical_bits { + static constexpr stdr::size_t value = + sizeof(T) * stdr::numeric_limits::digits; + }; + template + struct value_bits { + static constexpr stdr::size_t value = stdr::numeric_limits< + typename stdr::enable_if::value, T>::type>::digits; + }; + + template + JKJ_CONSTEXPR20 To bit_cast(const From& from) { +#if JKJ_HAS_BIT_CAST + return stdr::bit_cast(from); +#else + static_assert(sizeof(From) == sizeof(To), ""); + static_assert(stdr::is_trivially_copyable::value, ""); + static_assert(stdr::is_trivially_copyable::value, ""); + To to; + stdr::memcpy(&to, &from, sizeof(To)); + return to; +#endif + } + } + + // These classes expose encoding specs of IEEE-754-like floating-point formats. + // Currently available formats are IEEE-754 binary32 & IEEE-754 binary64. + + struct ieee754_binary32 { + static constexpr int total_bits = 32; + static constexpr int significand_bits = 23; + static constexpr int exponent_bits = 8; + static constexpr int min_exponent = -126; + static constexpr int max_exponent = 127; + static constexpr int exponent_bias = -127; + static constexpr int decimal_significand_digits = 9; + static constexpr int decimal_exponent_digits = 2; + }; + struct ieee754_binary64 { + static constexpr int total_bits = 64; + static constexpr int significand_bits = 52; + static constexpr int exponent_bits = 11; + static constexpr int min_exponent = -1022; + static constexpr int max_exponent = 1023; + static constexpr int exponent_bias = -1023; + static constexpr int decimal_significand_digits = 17; + static constexpr int decimal_exponent_digits = 3; + }; + + // A floating-point format traits class defines ways to interpret a bit pattern of given size as + // an encoding of floating-point number. This is an implementation of such a traits class, + // supporting ways to interpret IEEE-754 binary floating-point numbers. + template + struct ieee754_binary_traits { + // CarrierUInt needs to have enough size to hold the entire contents of floating-point + // numbers. The actual bits are assumed to be aligned to the LSB, and every other bits are + // assumed to be zeroed. + static_assert(detail::value_bits::value >= Format::total_bits, + "jkj::dragonbox: insufficient number of bits"); + static_assert(detail::stdr::is_unsigned::value, ""); + + // ExponentUInt needs to be large enough to hold (unsigned) exponent bits as well as the + // (signed) actual exponent. + // TODO: static overflow guard against intermediate computations. + static_assert(detail::value_bits::value >= Format::exponent_bits + 1, + "jkj::dragonbox: insufficient number of bits"); + static_assert(detail::stdr::is_signed::value, ""); + + using format = Format; + using carrier_uint = CarrierUInt; + static constexpr int carrier_bits = int(detail::value_bits::value); + using exponent_int = ExponentInt; + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + static constexpr exponent_int extract_exponent_bits(carrier_uint u) noexcept { + return exponent_int((u >> format::significand_bits) & + ((exponent_int(1) << format::exponent_bits) - 1)); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + static constexpr carrier_uint extract_significand_bits(carrier_uint u) noexcept { + return carrier_uint(u & ((carrier_uint(1) << format::significand_bits) - 1u)); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + static constexpr carrier_uint remove_exponent_bits(carrier_uint u) noexcept { + return carrier_uint(u & ~(((carrier_uint(1) << format::exponent_bits) - 1u) + << format::significand_bits)); + } + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + static constexpr carrier_uint remove_sign_bit_and_shift(carrier_uint u) noexcept { + return carrier_uint((carrier_uint(u) << 1) & + ((((carrier_uint(1) << (Format::total_bits - 1)) - 1u) << 1) | 1u)); + } + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr exponent_int binary_exponent(exponent_int exponent_bits) noexcept { + return exponent_int(exponent_bits == 0 ? format::min_exponent + : exponent_bits + format::exponent_bias); + } + + // Obtain the actual value of the binary significand from the extracted significand bits + // and exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, + exponent_int exponent_bits) noexcept { + return carrier_uint( + exponent_bits == 0 + ? significand_bits + : (significand_bits | (carrier_uint(1) << format::significand_bits))); + } + + /* Various boolean observer functions */ + + static constexpr bool is_nonzero(carrier_uint u) noexcept { + return (u & ((carrier_uint(1) << (format::significand_bits + format::exponent_bits)) - + 1u)) != 0; + } + static constexpr bool is_positive(carrier_uint u) noexcept { + return u < (carrier_uint(1) << (format::significand_bits + format::exponent_bits)); + } + static constexpr bool is_negative(carrier_uint u) noexcept { return !is_positive(u); } + static constexpr bool is_finite(exponent_int exponent_bits) noexcept { + return exponent_bits != ((exponent_int(1) << format::exponent_bits) - 1); + } + static constexpr bool has_all_zero_significand_bits(carrier_uint u) noexcept { + return ((u << 1) & + ((((carrier_uint(1) << (Format::total_bits - 1)) - 1u) << 1) | 1u)) == 0; + } + static constexpr bool has_even_significand_bits(carrier_uint u) noexcept { + return u % 2 == 0; + } + }; + + // Convert between bit patterns stored in carrier_uint and instances of an actual + // floating-point type. Depending on format and carrier_uint, this operation might not + // be possible for some specific bit patterns. However, the contract is that u always + // denotes a valid bit pattern, so the functions here are assumed to be noexcept. + // Users might specialize this class to change the behavior for certain types. + // The default provided by the library is to treat the given floating-point type Float as either + // IEEE-754 binary32 or IEEE-754 binary64, depending on the bitwise size of Float. + template + struct default_float_bit_carrier_conversion_traits { + // Guards against types that have different internal representations than IEEE-754 + // binary32/64. I don't know if there is a truly reliable way of detecting IEEE-754 binary + // formats. I just did my best here. Note that in some cases + // numeric_limits::is_iec559 may report false even if the internal representation is + // IEEE-754 compatible. In such a case, the user can specialize this traits template and + // remove this static sanity check in order to make Dragonbox work for Float. + static_assert(detail::stdr::numeric_limits::is_iec559 && + detail::stdr::numeric_limits::radix == 2 && + (detail::physical_bits::value == 32 || + detail::physical_bits::value == 64), + "jkj::dragonbox: Float may not be of IEEE-754 binary32/binary64"); + + // Specifies the unsigned integer type to hold bitwise value of Float. + using carrier_uint = + typename detail::stdr::conditional::value == 32, + detail::stdr::uint_least32_t, + detail::stdr::uint_least64_t>::type; + + // Specifies the floating-point format. + using format = typename detail::stdr::conditional::value == 32, + ieee754_binary32, ieee754_binary64>::type; + + // Converts the floating-point type into the bit-carrier unsigned integer type. + static JKJ_CONSTEXPR20 carrier_uint float_to_carrier(Float x) noexcept { + return detail::bit_cast(x); + } + + // Converts the bit-carrier unsigned integer type into the floating-point type. + static JKJ_CONSTEXPR20 Float carrier_to_float(carrier_uint x) noexcept { + return detail::bit_cast(x); + } + }; + + // Convenient wrappers for floating-point traits classes. + // In order to reduce the argument passing overhead, these classes should be as simple as + // possible (e.g., no inheritance, no private non-static data member, etc.; this is an + // unfortunate fact about common ABI convention). + + template + struct signed_significand_bits { + using format_traits = FormatTraits; + using carrier_uint = typename format_traits::carrier_uint; + + carrier_uint u; + + signed_significand_bits() = default; + constexpr explicit signed_significand_bits(carrier_uint bit_pattern) noexcept + : u{bit_pattern} {} + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + constexpr carrier_uint remove_sign_bit_and_shift() const noexcept { + return format_traits::remove_sign_bit_and_shift(u); + } + + constexpr bool is_positive() const noexcept { return format_traits::is_positive(u); } + constexpr bool is_negative() const noexcept { return format_traits::is_negative(u); } + constexpr bool has_all_zero_significand_bits() const noexcept { + return format_traits::has_all_zero_significand_bits(u); + } + constexpr bool has_even_significand_bits() const noexcept { + return format_traits::has_even_significand_bits(u); + } + }; + + template + struct float_bits { + using format_traits = FormatTraits; + using carrier_uint = typename format_traits::carrier_uint; + using exponent_int = typename format_traits::exponent_int; + + carrier_uint u; + + float_bits() = default; + constexpr explicit float_bits(carrier_uint bit_pattern) noexcept : u{bit_pattern} {} + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + constexpr exponent_int extract_exponent_bits() const noexcept { + return format_traits::extract_exponent_bits(u); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + constexpr carrier_uint extract_significand_bits() const noexcept { + return format_traits::extract_significand_bits(u); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + constexpr signed_significand_bits remove_exponent_bits() const noexcept { + return signed_significand_bits(format_traits::remove_exponent_bits(u)); + } + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr exponent_int binary_exponent(exponent_int exponent_bits) noexcept { + return format_traits::binary_exponent(exponent_bits); + } + constexpr exponent_int binary_exponent() const noexcept { + return binary_exponent(extract_exponent_bits()); + } + + // Obtain the actual value of the binary exponent from the extracted significand bits + // and exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, + exponent_int exponent_bits) noexcept { + return format_traits::binary_significand(significand_bits, exponent_bits); + } + constexpr carrier_uint binary_significand() const noexcept { + return binary_significand(extract_significand_bits(), extract_exponent_bits()); + } + + constexpr bool is_nonzero() const noexcept { return format_traits::is_nonzero(u); } + constexpr bool is_positive() const noexcept { return format_traits::is_positive(u); } + constexpr bool is_negative() const noexcept { return format_traits::is_negative(u); } + constexpr bool is_finite(exponent_int exponent_bits) const noexcept { + return format_traits::is_finite(exponent_bits); + } + constexpr bool is_finite() const noexcept { + return format_traits::is_finite(extract_exponent_bits()); + } + constexpr bool has_even_significand_bits() const noexcept { + return format_traits::has_even_significand_bits(u); + } + }; + + template , + class FormatTraits = ieee754_binary_traits> + JKJ_CONSTEXPR20 float_bits make_float_bits(Float x) noexcept { + return float_bits(ConversionTraits::float_to_carrier(x)); + } + + namespace detail { + //////////////////////////////////////////////////////////////////////////////////////// + // Bit operation intrinsics. + //////////////////////////////////////////////////////////////////////////////////////// + + namespace bits { + // Most compilers should be able to optimize this into the ROR instruction. + // n is assumed to be at most of bit_width bits. + template + JKJ_CONSTEXPR14 UInt rotr(UInt n, unsigned int r) noexcept { + static_assert(bit_width > 0, "jkj::dragonbox: rotation bit-width must be positive"); + static_assert(bit_width <= value_bits::value, + "jkj::dragonbox: rotation bit-width is too large"); + r &= (bit_width - 1); + return (n >> r) | (n << ((bit_width - r) & (bit_width - 1))); + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Utilities for wide unsigned integer arithmetic. + //////////////////////////////////////////////////////////////////////////////////////// + + namespace wuint { + // Compilers might support built-in 128-bit integer types. However, it seems that + // emulating them with a pair of 64-bit integers actually produces a better code, + // so we avoid using those built-ins. That said, they are still useful for + // implementing 64-bit x 64-bit -> 128-bit multiplication. + + // clang-format off +#if defined(__SIZEOF_INT128__) + // To silence "error: ISO C++ does not support '__int128' for 'type name' + // [-Wpedantic]" +#if defined(__GNUC__) + __extension__ +#endif + using builtin_uint128_t = unsigned __int128; +#endif + // clang-format on + + struct uint128 { + uint128() = default; + + stdr::uint_least64_t high_; + stdr::uint_least64_t low_; + + constexpr uint128(stdr::uint_least64_t high, stdr::uint_least64_t low) noexcept + : high_{high}, low_{low} {} + + constexpr stdr::uint_least64_t high() const noexcept { return high_; } + constexpr stdr::uint_least64_t low() const noexcept { return low_; } + + JKJ_CONSTEXPR20 uint128& operator+=(stdr::uint_least64_t n) & noexcept { + auto const generic_impl = [&] { + auto const sum = (low_ + n) & UINT64_C(0xffffffffffffffff); + high_ += (sum < low_ ? 1 : 0); + low_ = sum; + }; + // To suppress warning. + static_cast(generic_impl); + + JKJ_IF_CONSTEXPR(value_bits::value > 64) { + generic_impl(); + return *this; + } + + JKJ_IF_CONSTEVAL { + generic_impl(); + return *this; + } + + // See https://github.com/fmtlib/fmt/pull/2985. +#if JKJ_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR( + stdr::is_same::value) { + unsigned long long carry{}; + low_ = stdr::uint_least64_t(__builtin_addcll(low_, n, 0, &carry)); + high_ = stdr::uint_least64_t(__builtin_addcll(high_, 0, carry, &carry)); + return *this; + } +#endif +#if JKJ_HAS_BUILTIN(__builtin_addcl) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR(stdr::is_same::value) { + unsigned long carry{}; + low_ = stdr::uint_least64_t( + __builtin_addcl(static_cast(low_), + static_cast(n), 0, &carry)); + high_ = stdr::uint_least64_t( + __builtin_addcl(static_cast(high_), 0, carry, &carry)); + return *this; + } +#endif +#if JKJ_HAS_BUILTIN(__builtin_addc) && !defined(__ibmxl__) + JKJ_IF_CONSTEXPR(stdr::is_same::value) { + unsigned int carry{}; + low_ = stdr::uint_least64_t(__builtin_addc(static_cast(low_), + static_cast(n), 0, + &carry)); + high_ = stdr::uint_least64_t( + __builtin_addc(static_cast(high_), 0, carry, &carry)); + return *this; + } +#endif + +#if JKJ_HAS_BUILTIN(__builtin_ia32_addcarry_u64) + // __builtin_ia32_addcarry_u64 is not documented, but it seems it takes unsigned + // long long arguments. + unsigned long long result{}; + auto const carry = __builtin_ia32_addcarry_u64(0, low_, n, &result); + low_ = stdr::uint_least64_t(result); + __builtin_ia32_addcarry_u64(carry, high_, 0, &result); + high_ = stdr::uint_least64_t(result); +#elif defined(_MSC_VER) && defined(_M_X64) + // On MSVC, uint_least64_t and __int64 must be unsigned long long; see + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/standard-types + // and https://learn.microsoft.com/en-us/cpp/cpp/int8-int16-int32-int64. + static_assert(stdr::is_same::value, + ""); + auto const carry = _addcarry_u64(0, low_, n, &low_); + _addcarry_u64(carry, high_, 0, &high_); +#elif defined(__INTEL_COMPILER) && (defined(_M_X64) || defined(__x86_64)) + // Cannot find any documentation on how things are defined, but hopefully this + // is always true... + static_assert(stdr::is_same::value, ""); + auto const carry = _addcarry_u64(0, low_, n, &low_); + _addcarry_u64(carry, high_, 0, &high_); +#else + generic_impl(); +#endif + return *this; + } + }; + + inline JKJ_CONSTEXPR20 stdr::uint_least64_t umul64(stdr::uint_least32_t x, + stdr::uint_least32_t y) noexcept { +#if defined(_MSC_VER) && defined(_M_IX86) + JKJ_IF_NOT_CONSTEVAL { return __emulu(x, y); } +#endif + return x * stdr::uint_least64_t(y); + } + + // Get 128-bit result of multiplication of two 64-bit unsigned integers. + JKJ_SAFEBUFFERS inline JKJ_CONSTEXPR20 uint128 + umul128(stdr::uint_least64_t x, stdr::uint_least64_t y) noexcept { + auto const generic_impl = [=]() -> uint128 { + auto const a = stdr::uint_least32_t(x >> 32); + auto const b = stdr::uint_least32_t(x); + auto const c = stdr::uint_least32_t(y >> 32); + auto const d = stdr::uint_least32_t(y); + + auto const ac = umul64(a, c); + auto const bc = umul64(b, c); + auto const ad = umul64(a, d); + auto const bd = umul64(b, d); + + auto const intermediate = + (bd >> 32) + stdr::uint_least32_t(ad) + stdr::uint_least32_t(bc); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + stdr::uint_least32_t(bd)}; + }; + // To silence warning. + static_cast(generic_impl); + +#if defined(__SIZEOF_INT128__) + auto const result = builtin_uint128_t(x) * builtin_uint128_t(y); + return {stdr::uint_least64_t(result >> 64), stdr::uint_least64_t(result)}; +#elif defined(_MSC_VER) && defined(_M_X64) + JKJ_IF_CONSTEVAL { + // This redundant variable is to workaround MSVC's codegen bug caused by the + // interaction of NRVO and intrinsics. + auto const result = generic_impl(); + return result; + } + uint128 result; + #if defined(__AVX2__) + result.low_ = _mulx_u64(x, y, &result.high_); + #else + result.low_ = _umul128(x, y, &result.high_); + #endif + return result; +#else + return generic_impl(); +#endif + } + + // Get high half of the 128-bit result of multiplication of two 64-bit unsigned + // integers. + JKJ_SAFEBUFFERS inline JKJ_CONSTEXPR20 stdr::uint_least64_t + umul128_upper64(stdr::uint_least64_t x, stdr::uint_least64_t y) noexcept { + auto const generic_impl = [=]() -> stdr::uint_least64_t { + auto const a = stdr::uint_least32_t(x >> 32); + auto const b = stdr::uint_least32_t(x); + auto const c = stdr::uint_least32_t(y >> 32); + auto const d = stdr::uint_least32_t(y); + + auto const ac = umul64(a, c); + auto const bc = umul64(b, c); + auto const ad = umul64(a, d); + auto const bd = umul64(b, d); + + auto const intermediate = + (bd >> 32) + stdr::uint_least32_t(ad) + stdr::uint_least32_t(bc); + + return ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32); + }; + // To silence warning. + static_cast(generic_impl); + +#if defined(__SIZEOF_INT128__) + auto const result = builtin_uint128_t(x) * builtin_uint128_t(y); + return stdr::uint_least64_t(result >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + JKJ_IF_CONSTEVAL { + // This redundant variable is to workaround MSVC's codegen bug caused by the + // interaction of NRVO and intrinsics. + auto const result = generic_impl(); + return result; + } + stdr::uint_least64_t result; + #if defined(__AVX2__) + _mulx_u64(x, y, &result); + #else + result = __umulh(x, y); + #endif + return result; +#else + return generic_impl(); +#endif + } + + // Get upper 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit + // unsigned integer. + JKJ_SAFEBUFFERS inline JKJ_CONSTEXPR20 uint128 umul192_upper128(stdr::uint_least64_t x, + uint128 y) noexcept { + auto r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; + } + + // Get upper 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit + // unsigned integer. + inline JKJ_CONSTEXPR20 stdr::uint_least64_t + umul96_upper64(stdr::uint_least32_t x, stdr::uint_least64_t y) noexcept { +#if defined(__SIZEOF_INT128__) || (defined(_MSC_VER) && defined(_M_X64)) + return umul128_upper64(stdr::uint_least64_t(x) << 32, y); +#else + auto const yh = stdr::uint_least32_t(y >> 32); + auto const yl = stdr::uint_least32_t(y); + + auto const xyh = umul64(x, yh); + auto const xyl = umul64(x, yl); + + return xyh + (xyl >> 32); +#endif + } + + // Get lower 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit + // unsigned integer. + JKJ_SAFEBUFFERS inline JKJ_CONSTEXPR20 uint128 umul192_lower128(stdr::uint_least64_t x, + uint128 y) noexcept { + auto const high = x * y.high(); + auto const high_low = umul128(x, y.low()); + return {(high + high_low.high()) & UINT64_C(0xffffffffffffffff), high_low.low()}; + } + + // Get lower 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit + // unsigned integer. + constexpr stdr::uint_least64_t umul96_lower64(stdr::uint_least32_t x, + stdr::uint_least64_t y) noexcept { + return (x * y) & UINT64_C(0xffffffffffffffff); + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Some simple utilities for constexpr computation. + //////////////////////////////////////////////////////////////////////////////////////// + + template + constexpr Int compute_power(Int a) noexcept { + static_assert(k >= 0, ""); +#if JKJ_HAS_CONSTEXPR14 + Int p = 1; + for (int i = 0; i < k; ++i) { + p *= a; + } + return p; +#else + return k == 0 ? 1 + : k % 2 == 0 ? compute_power(a * a) + : a * compute_power(a * a); +#endif + } + + template + constexpr int count_factors(UInt n) noexcept { + static_assert(a > 1, ""); +#if JKJ_HAS_CONSTEXPR14 + int c = 0; + while (n % a == 0) { + n /= a; + ++c; + } + return c; +#else + return n % a == 0 ? count_factors(n / a) + 1 : 0; +#endif + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Utilities for fast/constexpr log computation. + //////////////////////////////////////////////////////////////////////////////////////// + + namespace log { + static_assert((stdr::int_fast32_t(-1) >> 1) == stdr::int_fast32_t(-1) && + (stdr::int_fast16_t(-1) >> 1) == stdr::int_fast16_t(-1), + "jkj::dragonbox: right-shift for signed integers must be arithmetic"); + + // For constexpr computation. + // Returns -1 when n = 0. + template + constexpr int floor_log2(UInt n) noexcept { +#if JKJ_HAS_CONSTEXPR14 + int count = -1; + while (n != 0) { + ++count; + n >>= 1; + } + return count; +#else + return n == 0 ? -1 : floor_log2(n / 2) + 1; +#endif + } + + template