mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Compare commits
166 Commits
release-0.
...
travis-upd
Author | SHA1 | Date | |
---|---|---|---|
![]() |
33bdf167e0 | ||
![]() |
b43575f89c | ||
![]() |
6f7ead5171 | ||
![]() |
cf93f4c57b | ||
![]() |
26faac387c | ||
![]() |
120863ba5a | ||
![]() |
b2f89386d8 | ||
![]() |
1bfbd2be4c | ||
![]() |
de8253fcb0 | ||
![]() |
29dcf92f87 | ||
![]() |
ce056acab7 | ||
![]() |
9ab22ef493 | ||
![]() |
1928bca4a4 | ||
![]() |
c9460110e0 | ||
![]() |
3dca8668b1 | ||
![]() |
587b24e2ee | ||
![]() |
5b3e30bfe9 | ||
![]() |
72f699f5ce | ||
![]() |
a8ba6a8dca | ||
![]() |
14c87258cd | ||
![]() |
f531f8a8c3 | ||
![]() |
52a1378e48 | ||
![]() |
c9a0077024 | ||
![]() |
b650bc8287 | ||
![]() |
21d75fa4cd | ||
![]() |
848091124d | ||
![]() |
6e87b37034 | ||
![]() |
0fddd1e5bd | ||
![]() |
99d95d8edc | ||
![]() |
a6ed66abca | ||
![]() |
e6b3a92e67 | ||
![]() |
47d32aadf0 | ||
![]() |
9d7e556ed5 | ||
![]() |
62ff351432 | ||
![]() |
5e9cb0128d | ||
![]() |
9a3624205e | ||
![]() |
968e0c1f02 | ||
![]() |
b218787b98 | ||
![]() |
db0bda7087 | ||
![]() |
6cdf363625 | ||
![]() |
d638508d33 | ||
![]() |
90350662c9 | ||
![]() |
e0e01d53c2 | ||
![]() |
0122697561 | ||
![]() |
bd7f8c60c8 | ||
![]() |
82e9571213 | ||
![]() |
0d5c57150c | ||
![]() |
eca9cfd648 | ||
![]() |
a2a113c6ff | ||
![]() |
283d06f9f7 | ||
![]() |
b87c76a2ef | ||
![]() |
abf941b20d | ||
![]() |
b659858b19 | ||
![]() |
2443da5224 | ||
![]() |
54fc4dadbb | ||
![]() |
774f25800e | ||
![]() |
ca77ef716e | ||
![]() |
ee99c4151c | ||
![]() |
d0da14404e | ||
![]() |
45d9035a33 | ||
![]() |
b71e672caf | ||
![]() |
5e79f5eed3 | ||
![]() |
c90c08ccc9 | ||
![]() |
3e33bb3166 | ||
![]() |
1698b47b65 | ||
![]() |
0f9a586ca1 | ||
![]() |
4fb1c4b92b | ||
![]() |
ab5f9259a4 | ||
![]() |
124ae47600 | ||
![]() |
f996468a6a | ||
![]() |
562aefc114 | ||
![]() |
5d5bb52ec2 | ||
![]() |
f5d5604a2c | ||
![]() |
aac4df342b | ||
![]() |
4c9e3d87e1 | ||
![]() |
cfb7606a84 | ||
![]() |
86ae3a5aa7 | ||
![]() |
752804372c | ||
![]() |
3f33f337a7 | ||
![]() |
5a519a4c6c | ||
![]() |
58687ee7c4 | ||
![]() |
dc9c750efd | ||
![]() |
d96826f12b | ||
![]() |
46dcdc3ea2 | ||
![]() |
beb44b872c | ||
![]() |
5e24f35816 | ||
![]() |
e2818c423e | ||
![]() |
efbfa1c7c7 | ||
![]() |
11607eb5bf | ||
![]() |
0fdb1b910c | ||
![]() |
c5457e1c6a | ||
![]() |
bedb28fdb4 | ||
![]() |
86c69bb73c | ||
![]() |
f82861001a | ||
![]() |
3757b2023b | ||
![]() |
147d909fe6 | ||
![]() |
e3492bb3fa | ||
![]() |
8ff7d76e19 | ||
![]() |
2b58c9bc42 | ||
![]() |
0f20ddcdcb | ||
![]() |
d025040049 | ||
![]() |
1f4b6d5c85 | ||
![]() |
3d9ad75af7 | ||
![]() |
380ecb404e | ||
![]() |
994cf97b59 | ||
![]() |
96598c5c25 | ||
![]() |
b5b03bb9ad | ||
![]() |
086fec5c35 | ||
![]() |
85af926ddc | ||
![]() |
519d33fea3 | ||
![]() |
f0b15cd6a0 | ||
![]() |
f74ae543b4 | ||
![]() |
7c33b3cdab | ||
![]() |
728e26e426 | ||
![]() |
3392ab980e | ||
![]() |
6c569e58b0 | ||
![]() |
148da47114 | ||
![]() |
a45a61742b | ||
![]() |
6e79997bb2 | ||
![]() |
f35f4a19fa | ||
![]() |
7d2873ce9f | ||
![]() |
091ddfa52d | ||
![]() |
883a1e8540 | ||
![]() |
0d810ad6d5 | ||
![]() |
51b59d11ba | ||
![]() |
bfb5703ce9 | ||
![]() |
cc229e87b3 | ||
![]() |
ca34a379c7 | ||
![]() |
2a02cee1c8 | ||
![]() |
2176fd994e | ||
![]() |
0535811c18 | ||
![]() |
c5f6482325 | ||
![]() |
d155b0d0d2 | ||
![]() |
52bcefa1f1 | ||
![]() |
34bd1a7083 | ||
![]() |
500db60f89 | ||
![]() |
178c8d1f27 | ||
![]() |
0a1352525a | ||
![]() |
f327b565ba | ||
![]() |
57805dfd6a | ||
![]() |
005a6a19ee | ||
![]() |
8c35a8ffab | ||
![]() |
9e37409b4b | ||
![]() |
a5b72f7ae6 | ||
![]() |
dfbb388409 | ||
![]() |
e92321aee5 | ||
![]() |
24fa1b3380 | ||
![]() |
4376ebacaa | ||
![]() |
b57efe94e7 | ||
![]() |
36fd93a8d5 | ||
![]() |
97d56c3f36 | ||
![]() |
320b02b14a | ||
![]() |
03d6e7d672 | ||
![]() |
b426fafff6 | ||
![]() |
b0a4de3dd9 | ||
![]() |
b43db54810 | ||
![]() |
5c390e8d6c | ||
![]() |
aa928b925b | ||
![]() |
908d38ebef | ||
![]() |
ec8aa4fa62 | ||
![]() |
5de38a76b6 | ||
![]() |
25f3935b7c | ||
![]() |
4d44602a5d | ||
![]() |
897cfd5b2e | ||
![]() |
1a6cb7376a | ||
![]() |
66acd0d54b |
@@ -30,7 +30,7 @@ PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerBindsToType: true
|
||||
SpacesBeforeTrailingComments: 2
|
||||
Cpp11BracedListStyle: true
|
||||
Standard: Auto
|
||||
Standard: Cpp11
|
||||
IndentWidth: 2
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
|
50
.codedocs
Normal file
50
.codedocs
Normal file
@@ -0,0 +1,50 @@
|
||||
# CodeDocs.xyz Configuration File
|
||||
|
||||
# Optional project name, if left empty the GitHub repository name will be used.
|
||||
PROJECT_NAME =
|
||||
|
||||
# One or more directories and files that contain example code to be included.
|
||||
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/
|
||||
|
||||
# One or more wildcard patterns to exclude files and directories from document
|
||||
# generation.
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# One or more symbols to exclude from document generation. Symbols can be
|
||||
# namespaces, classes, or functions.
|
||||
EXCLUDE_SYMBOLS =
|
||||
|
||||
# Override the default parser (language) used for each file extension.
|
||||
EXTENSION_MAPPING =
|
||||
|
||||
# Set the wildcard patterns used to filter out the source-files.
|
||||
# If left blank the default is:
|
||||
# *.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
|
||||
# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php,
|
||||
# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox, *.py,
|
||||
# *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
|
||||
FILE_PATTERNS =
|
||||
|
||||
# Hide undocumented class members.
|
||||
HIDE_UNDOC_MEMBERS =
|
||||
|
||||
# Hide undocumented classes.
|
||||
HIDE_UNDOC_CLASSES =
|
||||
|
||||
# Specify a markdown page whose contents should be used as the main page
|
||||
# (index.html). This will override a page marked as \mainpage. For example, a
|
||||
# README.md file usually serves as a useful main page.
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
|
||||
# Specify external repository to link documentation with.
|
||||
# This is similar to Doxygen's TAGFILES option, but will automatically link to
|
||||
# tags of other repositories already using CodeDocs. List each repository to
|
||||
# link with by giving its location in the form of owner/repository.
|
||||
# For example:
|
||||
# TAGLINKS = doxygen/doxygen CodeDocs/osg
|
||||
# Note: these repositories must already be built on CodeDocs.
|
||||
TAGLINKS =
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build/
|
||||
/tags
|
||||
/bazel-*
|
37
.travis.yml
Normal file
37
.travis.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
language: c++
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: clang
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
env:
|
||||
- CTEST_OUTPUT_ON_FAILURE=1
|
||||
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
- cd ..
|
||||
script:
|
||||
- cmake --build build
|
||||
- cmake --build build --target test
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.9
|
||||
packages:
|
||||
- g++-4.9
|
||||
- clang-3.9
|
||||
update: true
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- gcc@4.9
|
||||
- llvm@4
|
||||
update: true
|
14
BUILD.bazel
Normal file
14
BUILD.bazel
Normal file
@@ -0,0 +1,14 @@
|
||||
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"]),
|
||||
)
|
445
CMakeLists.txt
445
CMakeLists.txt
@@ -1,340 +1,161 @@
|
||||
###
|
||||
### 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()
|
||||
# 3.5 is actually available almost everywhere, but this a good minimum
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
project(YAML_CPP VERSION 0.7.0 LANGUAGES CXX)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(GNUInstallDirs)
|
||||
include(CTest)
|
||||
|
||||
find_program(YAML_CPP_CLANG_FORMAT_EXE NAMES clang-format)
|
||||
|
||||
###
|
||||
### Project settings
|
||||
###
|
||||
project(YAML_CPP)
|
||||
option(YAML_CPP_BUILD_CONTRIB "Enable yaml-cpp contrib in library" ON)
|
||||
option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON)
|
||||
option(YAML_BUILD_SHARED_LIBS "Build yaml-cpp shared library" ${BUILD_SHARED_LIBS})
|
||||
|
||||
set(YAML_CPP_VERSION_MAJOR "0")
|
||||
set(YAML_CPP_VERSION_MINOR "5")
|
||||
set(YAML_CPP_VERSION_PATCH "2")
|
||||
set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}")
|
||||
cmake_dependent_option(YAML_CPP_BUILD_TESTS
|
||||
"Enable yaml-cpp tests" ON
|
||||
"BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
cmake_dependent_option(YAML_CPP_INSTALL
|
||||
"Enable generation of yaml-cpp install targets" ON
|
||||
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
|
||||
cmake_dependent_option(YAML_MSVC_SHARED_RT
|
||||
"MSVC: Build yaml-cpp with shared runtime libs (/MD)" ON
|
||||
"MSVC" OFF)
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
||||
###
|
||||
### Project options
|
||||
###
|
||||
## Project stuff
|
||||
option(YAML_CPP_BUILD_TOOLS "Enable testing and 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")
|
||||
else()
|
||||
add_definitions(-DYAML_CPP_NO_CONTRIB)
|
||||
set(yaml-cpp-type STATIC)
|
||||
set(yaml-cpp-label-postfix "static")
|
||||
if (YAML_BUILD_SHARED_LIBS)
|
||||
set(yaml-cpp-type SHARED)
|
||||
set(yaml-cpp-label-postfix "shared")
|
||||
endif()
|
||||
|
||||
set(library_sources
|
||||
${sources}
|
||||
${public_headers}
|
||||
${private_headers}
|
||||
${contrib_sources}
|
||||
${contrib_public_headers}
|
||||
${contrib_private_headers}
|
||||
)
|
||||
add_sources(${library_sources})
|
||||
set(build-shared $<BOOL:${YAML_BUILD_SHARED_LIBS}>)
|
||||
set(build-windows-dll $<AND:$<BOOL:${CMAKE_HOST_WIN32}>,${build-shared}>)
|
||||
set(not-msvc $<NOT:$<CXX_COMPILER_ID:MSVC>>)
|
||||
|
||||
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}")
|
||||
if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY
|
||||
MultiThreaded$<$<CONFIG:Debug>:Debug>$<${build-shared}:DLL>)
|
||||
endif()
|
||||
|
||||
include_directories(${YAML_CPP_SOURCE_DIR}/src)
|
||||
include_directories(${YAML_CPP_SOURCE_DIR}/include)
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
|
||||
###
|
||||
### General compilation settings
|
||||
###
|
||||
set(yaml_c_flags ${CMAKE_C_FLAGS})
|
||||
set(yaml_cxx_flags ${CMAKE_CXX_FLAGS})
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(LABEL_SUFFIX "shared")
|
||||
else()
|
||||
set(LABEL_SUFFIX "static")
|
||||
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()
|
||||
|
||||
if(APPLE)
|
||||
if(APPLE_UNIVERSAL_BIN)
|
||||
set(CMAKE_OSX_ARCHITECTURES ppc;i386)
|
||||
endif()
|
||||
file(GLOB yaml-cpp-contrib-sources ${contrib-pattern})
|
||||
file(GLOB yaml-cpp-sources ${src-pattern})
|
||||
|
||||
set(msvc-rt $<TARGET_PROPERTY:MSVC_RUNTIME_LIBRARY>)
|
||||
|
||||
set(msvc-rt-mtd-static $<STREQUAL:${msvc-rt},MultiThreadedDebug>)
|
||||
set(msvc-rt-mt-static $<STREQUAL:${msvc-rt},MultiThreaded>)
|
||||
|
||||
set(msvc-rt-mtd-dll $<STREQUAL:${msvc-rt},MultiThreadedDebugDLL>)
|
||||
set(msvc-rt-mt-dll $<STREQUAL:${msvc-rt},MultiThreadedDLL>)
|
||||
|
||||
set(backport-msvc-runtime $<VERSION_LESS:${CMAKE_VERSION},3.15>)
|
||||
|
||||
add_library(yaml-cpp ${yaml-cpp-type} "")
|
||||
add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp)
|
||||
|
||||
set_property(TARGET yaml-cpp
|
||||
PROPERTY
|
||||
MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY})
|
||||
set_property(TARGET yaml-cpp
|
||||
PROPERTY
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
target_include_directories(yaml-cpp
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
PRIVATE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)
|
||||
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set_target_properties(yaml-cpp
|
||||
PROPERTIES
|
||||
CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
if(IPHONE)
|
||||
set(CMAKE_OSX_SYSROOT "iphoneos4.2")
|
||||
set(CMAKE_OSX_ARCHITECTURES "armv6;armv7")
|
||||
endif()
|
||||
target_compile_options(yaml-cpp
|
||||
PRIVATE
|
||||
$<${not-msvc}:-Wall -Wextra -Wshadow -Weffc++ -Wno-long-long>
|
||||
$<${not-msvc}:-pedantic -pedantic-errors>
|
||||
|
||||
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()
|
||||
$<$<AND:${backport-msvc-runtime},${msvc-rt-mtd-static}>:-MTd>
|
||||
$<$<AND:${backport-msvc-runtime},${msvc-rt-mt-static}>:-MT>
|
||||
$<$<AND:${backport-msvc-runtime},${msvc-rt-mtd-dll}>:-MDd>
|
||||
$<$<AND:${backport-msvc-runtime},${msvc-rt-mt-dll}>:-MD>
|
||||
|
||||
# GCC or Clang specialities
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR
|
||||
"${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
### 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()
|
||||
# /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
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W3 /wd4127 /wd4355>)
|
||||
|
||||
### 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 "")
|
||||
#
|
||||
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 ${yaml_cxx_flags}")
|
||||
target_compile_definitions(yaml-cpp
|
||||
PRIVATE
|
||||
$<${build-windows-dll}:${PROJECT_NAME}_DLL>
|
||||
$<$<NOT:$<BOOL:${YAML_CPP_BUILD_CONTRIB}>>:YAML_CPP_NO_CONTRIB>)
|
||||
|
||||
### 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()
|
||||
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 yaml_c_flags yaml_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}}")
|
||||
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}")
|
||||
endif()
|
||||
|
||||
|
||||
###
|
||||
### General install settings
|
||||
###
|
||||
if(WIN32)
|
||||
set(_library_dir bin) # .dll are in PATH, like executables
|
||||
else()
|
||||
set(_library_dir lib)
|
||||
endif()
|
||||
|
||||
set(INCLUDE_INSTALL_ROOT_DIR include)
|
||||
|
||||
set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_ROOT_DIR}/yaml-cpp)
|
||||
set(LIB_INSTALL_DIR "${_library_dir}${LIB_SUFFIX}")
|
||||
|
||||
set(_INSTALL_DESTINATIONS
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
|
||||
)
|
||||
|
||||
|
||||
###
|
||||
### Library
|
||||
###
|
||||
add_library(yaml-cpp ${library_sources})
|
||||
set_target_properties(yaml-cpp PROPERTIES
|
||||
COMPILE_FLAGS "${yaml_c_flags} ${yaml_cxx_flags}"
|
||||
)
|
||||
target_sources(yaml-cpp
|
||||
PRIVATE
|
||||
$<$<BOOL:${YAML_CPP_BUILD_CONTRIB}>:${yaml-cpp-contrib-sources}>
|
||||
${yaml-cpp-sources})
|
||||
|
||||
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}"
|
||||
)
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
PROJECT_LABEL "yaml-cpp ${yaml-cpp-label-postfix}"
|
||||
DEBUG_POSTFIX d)
|
||||
|
||||
if(IPHONE)
|
||||
set_target_properties(yaml-cpp PROPERTIES
|
||||
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0"
|
||||
)
|
||||
configure_package_config_file(
|
||||
"${PROJECT_SOURCE_DIR}/yaml-cpp-config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yaml-cpp")
|
||||
|
||||
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
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yaml-cpp")
|
||||
install(FILES
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/yaml-cpp")
|
||||
install(FILES "${PROJECT_BINARY_DIR}/yaml-cpp.pc"
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/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()
|
||||
endif()
|
||||
|
||||
install(TARGETS yaml-cpp ${_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)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config-version.cmake.in
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" @ONLY)
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
||||
###
|
||||
### Extras
|
||||
###
|
||||
if(YAML_CPP_BUILD_TOOLS)
|
||||
if(YAML_CPP_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
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)
|
||||
if (YAML_CPP_CLANG_FORMAT_EXE)
|
||||
add_custom_target(format
|
||||
COMMAND clang-format --style=file -i $<TARGET_PROPERTY:yaml-cpp,SOURCES>
|
||||
COMMENT "Running clang-format"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
26
CONTRIBUTING.md
Normal file
26
CONTRIBUTING.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Style
|
||||
|
||||
This project is formatted with [clang-format][fmt] using the style file at the root of the repository. Please run clang-format before sending a pull request.
|
||||
|
||||
In general, try to follow the style of surrounding code. We mostly follow the [Google C++ style guide][cpp-style].
|
||||
|
||||
Commit messages should be in the imperative mood, as described in the [Git contributing file][git-contrib]:
|
||||
|
||||
> Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
|
||||
> instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
|
||||
> to do frotz", as if you are giving orders to the codebase to change
|
||||
> its behaviour.
|
||||
|
||||
[fmt]: http://clang.llvm.org/docs/ClangFormat.html
|
||||
[cpp-style]: https://google.github.io/styleguide/cppguide.html
|
||||
[git-contrib]: http://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches?id=HEAD
|
||||
|
||||
# Tests
|
||||
|
||||
Please verify the tests pass by running the target `tests/run_tests`.
|
||||
|
||||
If you are adding functionality, add tests accordingly.
|
||||
|
||||
# Pull request process
|
||||
|
||||
Every pull request undergoes a code review. Unfortunately, github's code review process isn't great, but we'll manage. During the code review, if you make changes, add new commits to the pull request for each change. Once the code review is complete, rebase against the master branch and squash into a single commit.
|
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2008 Jesse Beder.
|
||||
Copyright (c) 2008-2015 Jesse Beder.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
55
README.md
Normal file
55
README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# yaml-cpp [](https://travis-ci.org/jbeder/yaml-cpp) [](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).
|
||||
|
||||
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)).
|
||||
|
||||
# Problems? #
|
||||
|
||||
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).
|
||||
|
||||
# How to Build #
|
||||
|
||||
yaml-cpp uses [CMake](http://www.cmake.org) to support cross-platform building. The basic steps to build are:
|
||||
|
||||
1. Download and install [CMake](http://www.cmake.org) (Resources -> Download).
|
||||
|
||||
**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:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
```
|
||||
|
||||
3. Run CMake. The basic syntax is:
|
||||
|
||||
```
|
||||
cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=ON|OFF] ..
|
||||
```
|
||||
|
||||
* 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
|
||||
|
||||
* yaml-cpp defaults to building a static library, but you may build a shared library by specifying `-DYAML_BUILD_SHARED_LIBS=ON`.
|
||||
|
||||
* 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!
|
||||
|
||||
5. To clean up, just remove the `build` directory.
|
||||
|
||||
# Recent Release #
|
||||
|
||||
[yaml-cpp 0.6.0](https://github.com/jbeder/yaml-cpp/releases/tag/yaml-cpp-0.6.0) has been released! This release requires C++11, and no longer depends on Boost.
|
||||
|
||||
[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.
|
||||
|
||||
# API Documentation
|
||||
|
||||
The autogenerated API reference is hosted on [CodeDocs](https://codedocs.xyz/jbeder/yaml-cpp/index.html)
|
10
WORKSPACE
Normal file
10
WORKSPACE
Normal file
@@ -0,0 +1,10 @@
|
||||
workspace(name = "com_github_jbeder_yaml_cpp")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
strip_prefix = "googletest-release-1.8.1",
|
||||
url = "https://github.com/google/googletest/archive/release-1.8.1.tar.gz",
|
||||
sha256 = "9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c",
|
||||
)
|
@@ -10,7 +10,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
namespace YAML {
|
||||
typedef std::size_t anchor_t;
|
||||
using anchor_t = std::size_t;
|
||||
const anchor_t NullAnchor = 0;
|
||||
}
|
||||
|
||||
|
@@ -19,9 +19,13 @@ YAML_CPP_API std::vector<unsigned char> 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
|
||||
|
@@ -12,14 +12,17 @@
|
||||
#include "../anchor.h"
|
||||
|
||||
namespace YAML {
|
||||
/// AnchorDict
|
||||
/// . An object that stores and retrieves values correlating to anchor_t
|
||||
/// values.
|
||||
/// . Efficient implementation that can make assumptions about how anchor_t
|
||||
/// values are assigned by the Parser class.
|
||||
/**
|
||||
* An object that stores and retrieves values correlating to {@link anchor_t}
|
||||
* values.
|
||||
*
|
||||
* <p>Efficient implementation that can make assumptions about how
|
||||
* {@code anchor_t} values are assigned by the {@link Parser} class.
|
||||
*/
|
||||
template <class T>
|
||||
class AnchorDict {
|
||||
public:
|
||||
AnchorDict() : m_data{} {}
|
||||
void Register(anchor_t anchor, T value) {
|
||||
if (anchor > m_data.size()) {
|
||||
m_data.resize(anchor);
|
||||
@@ -32,6 +35,6 @@ class AnchorDict {
|
||||
private:
|
||||
std::vector<T> m_data;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -15,10 +15,12 @@ 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:
|
||||
virtual ~GraphBuilderInterface() = 0;
|
||||
|
||||
// Create and return a new node with a null value.
|
||||
virtual void *NewNull(const Mark &mark, void *pParentNode) = 0;
|
||||
|
||||
@@ -71,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;
|
||||
|
@@ -8,16 +8,12 @@
|
||||
#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.
|
||||
// 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
|
||||
|
||||
#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined
|
||||
|
@@ -24,21 +24,21 @@ class EmitFromEvents : public EventHandler {
|
||||
public:
|
||||
EmitFromEvents(Emitter& emitter);
|
||||
|
||||
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();
|
||||
|
@@ -7,16 +7,18 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#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"
|
||||
|
||||
@@ -28,10 +30,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
|
||||
@@ -122,7 +126,7 @@ class YAML_CPP_API Emitter : private noncopyable {
|
||||
bool CanEmitNewline() const;
|
||||
|
||||
private:
|
||||
std::auto_ptr<EmitterState> m_pState;
|
||||
std::unique_ptr<EmitterState> m_pState;
|
||||
ostream_wrapper m_stream;
|
||||
};
|
||||
|
||||
@@ -152,7 +156,27 @@ inline Emitter& Emitter::WriteStreamable(T value) {
|
||||
|
||||
std::stringstream stream;
|
||||
SetStreamablePrecision<T>(stream);
|
||||
stream << value;
|
||||
|
||||
bool special = false;
|
||||
if (std::is_floating_point<T>::value) {
|
||||
if ((std::numeric_limits<T>::has_quiet_NaN ||
|
||||
std::numeric_limits<T>::has_signaling_NaN) &&
|
||||
std::isnan(value)) {
|
||||
special = true;
|
||||
stream << ".nan";
|
||||
} else if (std::numeric_limits<T>::has_infinity && std::isinf(value)) {
|
||||
special = true;
|
||||
if (std::signbit(value)) {
|
||||
stream << "-.inf";
|
||||
} else {
|
||||
stream << ".inf";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!special) {
|
||||
stream << value;
|
||||
}
|
||||
m_stream << stream.str();
|
||||
|
||||
StartedScalar();
|
||||
@@ -162,12 +186,12 @@ inline Emitter& Emitter::WriteStreamable(T value) {
|
||||
|
||||
template <>
|
||||
inline void Emitter::SetStreamablePrecision<float>(std::stringstream& stream) {
|
||||
stream.precision(GetFloatPrecision());
|
||||
stream.precision(static_cast<std::streamsize>(GetFloatPrecision()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
|
||||
stream.precision(GetDoublePrecision());
|
||||
stream.precision(static_cast<std::streamsize>(GetDoublePrecision()));
|
||||
}
|
||||
|
||||
// overloads of insertion
|
||||
@@ -249,6 +273,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
|
||||
|
@@ -74,14 +74,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 +96,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 +108,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 +117,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_)
|
||||
|
@@ -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
|
||||
|
@@ -8,10 +8,11 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include "yaml-cpp/noexcept.h"
|
||||
#include "yaml-cpp/traits.h"
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace YAML {
|
||||
// error messages
|
||||
@@ -89,7 +90,7 @@ const char* const BAD_FILE = "bad file";
|
||||
|
||||
template <typename T>
|
||||
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
||||
const T&, typename disable_if<is_numeric<T> >::type* = 0) {
|
||||
const T&, typename disable_if<is_numeric<T>>::type* = 0) {
|
||||
return KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -101,18 +102,49 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
|
||||
|
||||
template <typename T>
|
||||
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
||||
const T& key, typename enable_if<is_numeric<T> >::type* = 0) {
|
||||
const T& key, typename enable_if<is_numeric<T>>::type* = 0) {
|
||||
std::stringstream stream;
|
||||
stream << KEY_NOT_FOUND << ": " << key;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const std::string BAD_SUBSCRIPT_WITH_KEY(
|
||||
const T&, typename disable_if<is_numeric<T>>::type* = nullptr) {
|
||||
return BAD_SUBSCRIPT;
|
||||
}
|
||||
|
||||
class Exception : public std::runtime_error {
|
||||
inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) {
|
||||
std::stringstream stream;
|
||||
stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const std::string BAD_SUBSCRIPT_WITH_KEY(
|
||||
const T& key, typename enable_if<is_numeric<T>>::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();
|
||||
}
|
||||
}
|
||||
|
||||
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() throw() {}
|
||||
~Exception() YAML_CPP_NOEXCEPT override;
|
||||
|
||||
Exception(const Exception&) = default;
|
||||
|
||||
Mark mark;
|
||||
std::string msg;
|
||||
@@ -120,6 +152,10 @@ class Exception : public std::runtime_error {
|
||||
private:
|
||||
static const std::string build_what(const Mark& mark,
|
||||
const std::string& msg) {
|
||||
if (mark.is_null()) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::stringstream output;
|
||||
output << "yaml-cpp: error at line " << mark.line + 1 << ", column "
|
||||
<< mark.column + 1 << ": " << msg;
|
||||
@@ -127,39 +163,47 @@ class Exception : public std::runtime_error {
|
||||
}
|
||||
};
|
||||
|
||||
class ParserException : public Exception {
|
||||
class YAML_CPP_API ParserException : public Exception {
|
||||
public:
|
||||
ParserException(const Mark& mark_, const std::string& msg_)
|
||||
: Exception(mark_, msg_) {}
|
||||
ParserException(const ParserException&) = default;
|
||||
~ParserException() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class RepresentationException : public Exception {
|
||||
class YAML_CPP_API RepresentationException : public Exception {
|
||||
public:
|
||||
RepresentationException(const Mark& mark_, const std::string& msg_)
|
||||
: Exception(mark_, msg_) {}
|
||||
RepresentationException(const RepresentationException&) = default;
|
||||
~RepresentationException() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
// representation exceptions
|
||||
class InvalidScalar : public RepresentationException {
|
||||
class YAML_CPP_API InvalidScalar : public RepresentationException {
|
||||
public:
|
||||
InvalidScalar(const Mark& mark_)
|
||||
: RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
|
||||
InvalidScalar(const InvalidScalar&) = default;
|
||||
~InvalidScalar() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class KeyNotFound : public RepresentationException {
|
||||
class YAML_CPP_API KeyNotFound : public RepresentationException {
|
||||
public:
|
||||
template <typename T>
|
||||
KeyNotFound(const Mark& mark_, const T& key_)
|
||||
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
|
||||
}
|
||||
KeyNotFound(const KeyNotFound&) = default;
|
||||
~KeyNotFound() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedKeyNotFound : public KeyNotFound {
|
||||
class YAML_CPP_API TypedKeyNotFound : public KeyNotFound {
|
||||
public:
|
||||
TypedKeyNotFound(const Mark& mark_, const T& key_)
|
||||
: KeyNotFound(mark_, key_), key(key_) {}
|
||||
virtual ~TypedKeyNotFound() throw() {}
|
||||
~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default;
|
||||
|
||||
T key;
|
||||
};
|
||||
@@ -170,57 +214,76 @@ inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
|
||||
return TypedKeyNotFound<T>(mark, key);
|
||||
}
|
||||
|
||||
class InvalidNode : public RepresentationException {
|
||||
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;
|
||||
~InvalidNode() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class BadConversion : public RepresentationException {
|
||||
class YAML_CPP_API BadConversion : public RepresentationException {
|
||||
public:
|
||||
BadConversion()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_CONVERSION) {}
|
||||
explicit BadConversion(const Mark& mark_)
|
||||
: RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
|
||||
BadConversion(const BadConversion&) = default;
|
||||
~BadConversion() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedBadConversion : public BadConversion {
|
||||
public:
|
||||
TypedBadConversion() : BadConversion() {}
|
||||
explicit TypedBadConversion(const Mark& mark_) : BadConversion(mark_) {}
|
||||
};
|
||||
|
||||
class BadDereference : public RepresentationException {
|
||||
class YAML_CPP_API BadDereference : public RepresentationException {
|
||||
public:
|
||||
BadDereference()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
|
||||
BadDereference(const BadDereference&) = default;
|
||||
~BadDereference() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class BadSubscript : public RepresentationException {
|
||||
class YAML_CPP_API BadSubscript : public RepresentationException {
|
||||
public:
|
||||
BadSubscript()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {}
|
||||
template <typename Key>
|
||||
BadSubscript(const Mark& mark_, const Key& key)
|
||||
: RepresentationException(mark_,
|
||||
ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {}
|
||||
BadSubscript(const BadSubscript&) = default;
|
||||
~BadSubscript() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class BadPushback : public RepresentationException {
|
||||
class YAML_CPP_API BadPushback : public RepresentationException {
|
||||
public:
|
||||
BadPushback()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
|
||||
BadPushback(const BadPushback&) = default;
|
||||
~BadPushback() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class BadInsert : public RepresentationException {
|
||||
class YAML_CPP_API BadInsert : public RepresentationException {
|
||||
public:
|
||||
BadInsert()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
|
||||
BadInsert(const BadInsert&) = default;
|
||||
~BadInsert() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class EmitterException : public Exception {
|
||||
class YAML_CPP_API EmitterException : public Exception {
|
||||
public:
|
||||
EmitterException(const std::string& msg_)
|
||||
: Exception(Mark::null_mark(), msg_) {}
|
||||
EmitterException(const EmitterException&) = default;
|
||||
~EmitterException() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
|
||||
class BadFile : public Exception {
|
||||
class YAML_CPP_API BadFile : public Exception {
|
||||
public:
|
||||
BadFile() : Exception(Mark::null_mark(), ErrorMsg::BAD_FILE) {}
|
||||
BadFile(const BadFile&) = default;
|
||||
~BadFile() YAML_CPP_NOEXCEPT override;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,8 @@ struct YAML_CPP_API Mark {
|
||||
|
||||
static const Mark null_mark() { return Mark(-1, -1, -1); }
|
||||
|
||||
bool is_null() const { return pos == -1 && line == -1 && column == -1; }
|
||||
|
||||
int pos;
|
||||
int line, column;
|
||||
|
||||
|
@@ -7,10 +7,13 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/binary.h"
|
||||
@@ -20,6 +23,7 @@
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
@@ -43,6 +47,17 @@ inline bool IsNaN(const std::string& input) {
|
||||
}
|
||||
}
|
||||
|
||||
// Node
|
||||
template <>
|
||||
struct convert<Node> {
|
||||
static Node encode(const Node& rhs) { return rhs; }
|
||||
|
||||
static bool decode(const Node& node, Node& rhs) {
|
||||
rhs.reset(node);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// std::string
|
||||
template <>
|
||||
struct convert<std::string> {
|
||||
@@ -76,42 +91,70 @@ struct convert<_Null> {
|
||||
}
|
||||
};
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
|
||||
template <> \
|
||||
struct convert<type> { \
|
||||
static Node encode(const type& rhs) { \
|
||||
std::stringstream stream; \
|
||||
stream.precision(std::numeric_limits<type>::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<type>::has_infinity) { \
|
||||
if (conversion::IsInfinity(input)) { \
|
||||
rhs = std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} else if (conversion::IsNegativeInfinity(input)) { \
|
||||
rhs = negative_op std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (std::numeric_limits<type>::has_quiet_NaN && \
|
||||
conversion::IsNaN(input)) { \
|
||||
rhs = std::numeric_limits<type>::quiet_NaN(); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
namespace conversion {
|
||||
template <typename T>
|
||||
typename std::enable_if< std::is_floating_point<T>::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 << rhs;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_floating_point<T>::value, void>::type
|
||||
inner_encode(const T& rhs, std::stringstream& stream){
|
||||
stream << rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
|
||||
template <> \
|
||||
struct convert<type> { \
|
||||
\
|
||||
static Node encode(const type& rhs) { \
|
||||
std::stringstream stream; \
|
||||
stream.precision(std::numeric_limits<type>::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.unsetf(std::ios::dec); \
|
||||
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) { \
|
||||
return true; \
|
||||
} \
|
||||
if (std::numeric_limits<type>::has_infinity) { \
|
||||
if (conversion::IsInfinity(input)) { \
|
||||
rhs = std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} else if (conversion::IsNegativeInfinity(input)) { \
|
||||
rhs = negative_op std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (std::numeric_limits<type>::has_quiet_NaN) { \
|
||||
if (conversion::IsNaN(input)) { \
|
||||
rhs = std::numeric_limits<type>::quiet_NaN(); \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \
|
||||
@@ -151,7 +194,7 @@ struct convert<bool> {
|
||||
|
||||
// std::map
|
||||
template <typename K, typename V>
|
||||
struct convert<std::map<K, V> > {
|
||||
struct convert<std::map<K, V>> {
|
||||
static Node encode(const std::map<K, V>& rhs) {
|
||||
Node node(NodeType::Map);
|
||||
for (typename std::map<K, V>::const_iterator it = rhs.begin();
|
||||
@@ -178,7 +221,7 @@ struct convert<std::map<K, V> > {
|
||||
|
||||
// std::vector
|
||||
template <typename T>
|
||||
struct convert<std::vector<T> > {
|
||||
struct convert<std::vector<T>> {
|
||||
static Node encode(const std::vector<T>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (typename std::vector<T>::const_iterator it = rhs.begin();
|
||||
@@ -205,7 +248,7 @@ struct convert<std::vector<T> > {
|
||||
|
||||
// std::list
|
||||
template <typename T>
|
||||
struct convert<std::list<T> > {
|
||||
struct convert<std::list<T>> {
|
||||
static Node encode(const std::list<T>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (typename std::list<T>::const_iterator it = rhs.begin();
|
||||
@@ -230,9 +273,42 @@ struct convert<std::list<T> > {
|
||||
}
|
||||
};
|
||||
|
||||
// std::array
|
||||
template <typename T, std::size_t N>
|
||||
struct convert<std::array<T, N>> {
|
||||
static Node encode(const std::array<T, N>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (const auto& element : rhs) {
|
||||
node.push_back(element);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::array<T, N>& rhs) {
|
||||
if (!isNodeValid(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < node.size(); ++i) {
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs[i] = node[i].template as<T>();
|
||||
#else
|
||||
rhs[i] = node[i].as<T>();
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isNodeValid(const Node& node) {
|
||||
return node.IsSequence() && node.size() == N;
|
||||
}
|
||||
};
|
||||
|
||||
// std::pair
|
||||
template <typename T, typename U>
|
||||
struct convert<std::pair<T, U> > {
|
||||
struct convert<std::pair<T, U>> {
|
||||
static Node encode(const std::pair<T, U>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
node.push_back(rhs.first);
|
||||
|
@@ -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
|
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "yaml-cpp/node/detail/node.h"
|
||||
#include "yaml-cpp/node/detail/node_data.h"
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
@@ -17,23 +17,23 @@ template <typename Key, typename Enable = void>
|
||||
struct get_idx {
|
||||
static node* get(const std::vector<node*>& /* sequence */,
|
||||
const Key& /* key */, shared_memory_holder /* pMemory */) {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct get_idx<
|
||||
Key, typename boost::enable_if_c<boost::is_unsigned<Key>::value &&
|
||||
!boost::is_same<Key, bool>::value>::type> {
|
||||
struct get_idx<Key,
|
||||
typename std::enable_if<std::is_unsigned<Key>::value &&
|
||||
!std::is_same<Key, bool>::value>::type> {
|
||||
static node* get(const std::vector<node*>& 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<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
if (key > sequence.size())
|
||||
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];
|
||||
@@ -41,18 +41,56 @@ struct get_idx<
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct get_idx<Key, typename boost::enable_if<boost::is_signed<Key> >::type> {
|
||||
struct get_idx<Key, typename std::enable_if<std::is_signed<Key>::value>::type> {
|
||||
static node* get(const std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
return key >= 0 ? get_idx<std::size_t>::get(
|
||||
sequence, static_cast<std::size_t>(key), pMemory)
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
static node* get(std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
return key >= 0 ? get_idx<std::size_t>::get(
|
||||
sequence, static_cast<std::size_t>(key), pMemory)
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Enable = void>
|
||||
struct remove_idx {
|
||||
static bool remove(std::vector<node*>&, const Key&, std::size_t&) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct remove_idx<
|
||||
Key, typename std::enable_if<std::is_unsigned<Key>::value &&
|
||||
!std::is_same<Key, bool>::value>::type> {
|
||||
|
||||
static bool remove(std::vector<node*>& 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 <typename Key>
|
||||
struct remove_idx<Key,
|
||||
typename std::enable_if<std::is_signed<Key>::value>::type> {
|
||||
|
||||
static bool remove(std::vector<node*>& sequence, const Key& key,
|
||||
std::size_t& seqSize) {
|
||||
return key >= 0 ? remove_idx<std::size_t>::remove(
|
||||
sequence, static_cast<std::size_t>(key), seqSize)
|
||||
: false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,13 +116,13 @@ 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<Key>::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) {
|
||||
@@ -93,7 +131,7 @@ inline node* node_data::get(const Key& key,
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
@@ -112,7 +150,7 @@ 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) {
|
||||
@@ -129,13 +167,23 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
|
||||
|
||||
template <typename Key>
|
||||
inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
|
||||
if (m_type != NodeType::Map)
|
||||
return false;
|
||||
if (m_type == NodeType::Sequence) {
|
||||
return remove_idx<Key>::remove(m_sequence, key, m_seqSize);
|
||||
} else 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;
|
||||
}
|
||||
|
||||
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
if (equals(*it->first, key, pMemory)) {
|
||||
m_map.erase(it);
|
||||
return true;
|
||||
for (node_map::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) {
|
||||
if (iter->first->equals(key, pMemory)) {
|
||||
m_map.erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,47 +8,75 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/detail/node_iterator.h"
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_value;
|
||||
|
||||
template <typename V>
|
||||
class iterator_base
|
||||
: public boost::iterator_adaptor<iterator_base<V>, node_iterator, V,
|
||||
std::forward_iterator_tag, V> {
|
||||
class iterator_base {
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class iterator_base;
|
||||
struct enabler {};
|
||||
typedef typename iterator_base::base_type base_type;
|
||||
using base_type = node_iterator;
|
||||
|
||||
struct proxy {
|
||||
explicit proxy(const V& x) : m_ref(x) {}
|
||||
V* operator->() { return std::addressof(m_ref); }
|
||||
operator V*() { return std::addressof(m_ref); }
|
||||
|
||||
V m_ref;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename iterator_base::value_type value_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = V;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = V*;
|
||||
using reference = V;
|
||||
|
||||
public:
|
||||
iterator_base() {}
|
||||
iterator_base() : m_iterator(), m_pMemory() {}
|
||||
explicit iterator_base(base_type rhs, shared_memory_holder pMemory)
|
||||
: iterator_base::iterator_adaptor_(rhs), m_pMemory(pMemory) {}
|
||||
: m_iterator(rhs), m_pMemory(pMemory) {}
|
||||
|
||||
template <class W>
|
||||
iterator_base(const iterator_base<W>& rhs,
|
||||
typename boost::enable_if<boost::is_convertible<W*, V*>,
|
||||
enabler>::type = enabler())
|
||||
: iterator_base::iterator_adaptor_(rhs.base()),
|
||||
m_pMemory(rhs.m_pMemory) {}
|
||||
typename std::enable_if<std::is_convertible<W*, V*>::value,
|
||||
enabler>::type = enabler())
|
||||
: m_iterator(rhs.m_iterator), m_pMemory(rhs.m_pMemory) {}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
iterator_base<V>& operator++() {
|
||||
++m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void increment() { this->base_reference() = boost::next(this->base()); }
|
||||
iterator_base<V> operator++(int) {
|
||||
iterator_base<V> iterator_pre(*this);
|
||||
++(*this);
|
||||
return iterator_pre;
|
||||
}
|
||||
|
||||
value_type dereference() const {
|
||||
const typename base_type::value_type& v = *this->base();
|
||||
template <typename W>
|
||||
bool operator==(const iterator_base<W>& rhs) const {
|
||||
return m_iterator == rhs.m_iterator;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!=(const iterator_base<W>& rhs) const {
|
||||
return m_iterator != rhs.m_iterator;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
const typename base_type::value_type& v = *m_iterator;
|
||||
if (v.pNode)
|
||||
return value_type(Node(*v, m_pMemory));
|
||||
if (v.first && v.second)
|
||||
@@ -56,10 +84,13 @@ class iterator_base
|
||||
return value_type();
|
||||
}
|
||||
|
||||
proxy operator->() const { return proxy(**this); }
|
||||
|
||||
private:
|
||||
base_type m_iterator;
|
||||
shared_memory_holder m_pMemory;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
#endif // VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
class node;
|
||||
|
||||
namespace detail {
|
||||
struct iterator_value;
|
||||
@@ -21,8 +20,8 @@ template <typename V>
|
||||
class iterator_base;
|
||||
}
|
||||
|
||||
typedef detail::iterator_base<detail::iterator_value> iterator;
|
||||
typedef detail::iterator_base<const detail::iterator_value> const_iterator;
|
||||
using iterator = detail::iterator_base<detail::iterator_value>;
|
||||
using const_iterator = detail::iterator_base<const detail::iterator_value>;
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -7,8 +7,6 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <set>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
@@ -24,11 +22,12 @@ namespace YAML {
|
||||
namespace detail {
|
||||
class YAML_CPP_API memory {
|
||||
public:
|
||||
memory() : m_nodes{} {}
|
||||
node& create_node();
|
||||
void merge(const memory& rhs);
|
||||
|
||||
private:
|
||||
typedef std::set<shared_node> Nodes;
|
||||
using Nodes = std::set<shared_node>;
|
||||
Nodes m_nodes;
|
||||
};
|
||||
|
||||
@@ -40,9 +39,9 @@ class YAML_CPP_API memory_holder {
|
||||
void merge(memory_holder& rhs);
|
||||
|
||||
private:
|
||||
boost::shared_ptr<memory> m_pMemory;
|
||||
shared_memory m_pMemory;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
#endif // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -7,24 +7,32 @@
|
||||
#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 <set>
|
||||
#include <boost/utility.hpp>
|
||||
#include <atomic>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node : private boost::noncopyable {
|
||||
class node {
|
||||
private:
|
||||
struct less {
|
||||
bool operator ()(const node* l, const node* r) {return l->m_index < r->m_index;}
|
||||
};
|
||||
|
||||
public:
|
||||
node() : m_pRef(new node_ref) {}
|
||||
node() : m_pRef(new node_ref), m_dependencies{} {}
|
||||
node(const node&) = delete;
|
||||
node& operator=(const node&) = delete;
|
||||
|
||||
bool is(const node& rhs) const { return m_pRef == rhs.m_pRef; }
|
||||
const node_ref* ref() const { return m_pRef.get(); }
|
||||
|
||||
bool is_defined() const { return m_pRef->is_defined(); }
|
||||
const Mark& mark() const { return m_pRef->mark(); }
|
||||
NodeType::value type() const { return m_pRef->type(); }
|
||||
|
||||
const std::string& scalar() const { return m_pRef->scalar(); }
|
||||
@@ -40,9 +48,8 @@ class node : private boost::noncopyable {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -64,6 +71,8 @@ class node : private boost::noncopyable {
|
||||
m_pRef->set_data(*rhs.m_pRef);
|
||||
}
|
||||
|
||||
void set_mark(const Mark& mark) { m_pRef->set_mark(mark); }
|
||||
|
||||
void set_type(NodeType::value type) {
|
||||
if (type != NodeType::Undefined)
|
||||
mark_defined();
|
||||
@@ -102,9 +111,10 @@ class node : private boost::noncopyable {
|
||||
node_iterator end() { return m_pRef->end(); }
|
||||
|
||||
// sequence
|
||||
void push_back(node& node, shared_memory_holder pMemory) {
|
||||
m_pRef->push_back(node, pMemory);
|
||||
node.add_dependency(*this);
|
||||
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);
|
||||
@@ -116,7 +126,7 @@ class node : private boost::noncopyable {
|
||||
template <typename Key>
|
||||
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<const node_ref&>(*m_pRef).get(key, pMemory);
|
||||
}
|
||||
@@ -133,7 +143,7 @@ class node : private boost::noncopyable {
|
||||
|
||||
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<const node_ref&>(*m_pRef).get(key, pMemory);
|
||||
}
|
||||
@@ -156,10 +166,12 @@ class node : private boost::noncopyable {
|
||||
|
||||
private:
|
||||
shared_node_ref m_pRef;
|
||||
typedef std::set<node*> nodes;
|
||||
using nodes = std::set<node*, less>;
|
||||
nodes m_dependencies;
|
||||
size_t m_index;
|
||||
static std::atomic<size_t> m_amount;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
#endif // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -7,8 +7,6 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -29,11 +27,14 @@ class node;
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class YAML_CPP_API node_data : private boost::noncopyable {
|
||||
class YAML_CPP_API node_data {
|
||||
public:
|
||||
node_data();
|
||||
node_data(const node_data&) = delete;
|
||||
node_data& operator=(const node_data&) = delete;
|
||||
|
||||
void mark_defined();
|
||||
void set_mark(const Mark& mark);
|
||||
void set_type(NodeType::value type);
|
||||
void set_tag(const std::string& tag);
|
||||
void set_null();
|
||||
@@ -41,6 +42,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
|
||||
void set_style(EmitterStyle::value style);
|
||||
|
||||
bool is_defined() const { return m_isDefined; }
|
||||
const Mark& mark() const { return m_mark; }
|
||||
NodeType::value type() const {
|
||||
return m_isDefined ? m_type : NodeType::Undefined;
|
||||
}
|
||||
@@ -79,7 +81,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
|
||||
shared_memory_holder pMemory);
|
||||
|
||||
public:
|
||||
static std::string empty_scalar;
|
||||
static const std::string& empty_scalar();
|
||||
|
||||
private:
|
||||
void compute_seq_size() const;
|
||||
@@ -97,6 +99,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
|
||||
|
||||
private:
|
||||
bool m_isDefined;
|
||||
Mark m_mark;
|
||||
NodeType::value m_type;
|
||||
std::string m_tag;
|
||||
EmitterStyle::value m_style;
|
||||
@@ -105,17 +108,17 @@ class YAML_CPP_API node_data : private boost::noncopyable {
|
||||
std::string m_scalar;
|
||||
|
||||
// sequence
|
||||
typedef std::vector<node*> node_seq;
|
||||
using node_seq = std::vector<node *>;
|
||||
node_seq m_sequence;
|
||||
|
||||
mutable std::size_t m_seqSize;
|
||||
|
||||
// map
|
||||
typedef std::map<node*, node*> node_map;
|
||||
using node_map = std::vector<std::pair<node*, node*>>;
|
||||
node_map m_map;
|
||||
|
||||
typedef std::pair<node*, node*> kv_pair;
|
||||
typedef std::list<kv_pair> kv_pairs;
|
||||
using kv_pair = std::pair<node*, node*>;
|
||||
using kv_pairs = std::list<kv_pair>;
|
||||
mutable kv_pairs m_undefinedPairs;
|
||||
};
|
||||
}
|
||||
|
@@ -9,8 +9,9 @@
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -18,16 +19,16 @@
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_type {
|
||||
enum value { None, Sequence, Map };
|
||||
enum value { NoneType, Sequence, Map };
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct node_iterator_value : public std::pair<V*, V*> {
|
||||
typedef std::pair<V*, V*> kv;
|
||||
using kv = std::pair<V*, V*>;
|
||||
|
||||
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; }
|
||||
@@ -35,36 +36,45 @@ struct node_iterator_value : public std::pair<V*, V*> {
|
||||
V* pNode;
|
||||
};
|
||||
|
||||
typedef std::vector<node*> node_seq;
|
||||
typedef std::map<node*, node*> node_map;
|
||||
using node_seq = std::vector<node *>;
|
||||
using node_map = std::vector<std::pair<node*, node*>>;
|
||||
|
||||
template <typename V>
|
||||
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 <typename V>
|
||||
struct node_iterator_type<const V> {
|
||||
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 <typename V>
|
||||
class node_iterator_base
|
||||
: public boost::iterator_facade<
|
||||
node_iterator_base<V>, node_iterator_value<V>,
|
||||
std::forward_iterator_tag, node_iterator_value<V> > {
|
||||
class node_iterator_base {
|
||||
private:
|
||||
struct enabler {};
|
||||
|
||||
struct proxy {
|
||||
explicit proxy(const node_iterator_value<V>& x) : m_ref(x) {}
|
||||
node_iterator_value<V>* operator->() { return std::addressof(m_ref); }
|
||||
operator node_iterator_value<V>*() { return std::addressof(m_ref); }
|
||||
|
||||
node_iterator_value<V> m_ref;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename node_iterator_type<V>::seq SeqIter;
|
||||
typedef typename node_iterator_type<V>::map MapIter;
|
||||
typedef node_iterator_value<V> value_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = node_iterator_value<V>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = node_iterator_value<V>*;
|
||||
using reference = node_iterator_value<V>;
|
||||
using SeqIter = typename node_iterator_type<V>::seq;
|
||||
using MapIter = typename node_iterator_type<V>::map;
|
||||
|
||||
node_iterator_base()
|
||||
: m_type(iterator_type::None), m_seqIt(), m_mapIt(), m_mapEnd() {}
|
||||
: m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {}
|
||||
explicit node_iterator_base(SeqIter seqIt)
|
||||
: m_type(iterator_type::Sequence),
|
||||
m_seqIt(seqIt),
|
||||
@@ -80,25 +90,23 @@ class node_iterator_base
|
||||
|
||||
template <typename W>
|
||||
node_iterator_base(const node_iterator_base<W>& rhs,
|
||||
typename boost::enable_if<boost::is_convertible<W*, V*>,
|
||||
enabler>::type = enabler())
|
||||
typename std::enable_if<std::is_convertible<W*, V*>::value,
|
||||
enabler>::type = enabler())
|
||||
: m_type(rhs.m_type),
|
||||
m_seqIt(rhs.m_seqIt),
|
||||
m_mapIt(rhs.m_mapIt),
|
||||
m_mapEnd(rhs.m_mapEnd) {}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
template <typename>
|
||||
friend class node_iterator_base;
|
||||
|
||||
template <typename W>
|
||||
bool equal(const node_iterator_base<W>& rhs) const {
|
||||
bool operator==(const node_iterator_base<W>& rhs) const {
|
||||
if (m_type != rhs.m_type)
|
||||
return false;
|
||||
|
||||
switch (m_type) {
|
||||
case iterator_type::None:
|
||||
case iterator_type::NoneType:
|
||||
return true;
|
||||
case iterator_type::Sequence:
|
||||
return m_seqIt == rhs.m_seqIt;
|
||||
@@ -108,9 +116,14 @@ class node_iterator_base
|
||||
return true;
|
||||
}
|
||||
|
||||
void increment() {
|
||||
template <typename W>
|
||||
bool operator!=(const node_iterator_base<W>& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
node_iterator_base<V>& operator++() {
|
||||
switch (m_type) {
|
||||
case iterator_type::None:
|
||||
case iterator_type::NoneType:
|
||||
break;
|
||||
case iterator_type::Sequence:
|
||||
++m_seqIt;
|
||||
@@ -120,11 +133,18 @@ class node_iterator_base
|
||||
m_mapIt = increment_until_defined(m_mapIt);
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type dereference() const {
|
||||
node_iterator_base<V> operator++(int) {
|
||||
node_iterator_base<V> iterator_pre(*this);
|
||||
++(*this);
|
||||
return iterator_pre;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
switch (m_type) {
|
||||
case iterator_type::None:
|
||||
case iterator_type::NoneType:
|
||||
return value_type();
|
||||
case iterator_type::Sequence:
|
||||
return value_type(**m_seqIt);
|
||||
@@ -134,6 +154,8 @@ class node_iterator_base
|
||||
return value_type();
|
||||
}
|
||||
|
||||
proxy operator->() const { return proxy(**this); }
|
||||
|
||||
MapIter increment_until_defined(MapIter it) {
|
||||
while (it != m_mapEnd && !is_defined(it))
|
||||
++it;
|
||||
@@ -151,8 +173,8 @@ class node_iterator_base
|
||||
MapIter m_mapIt, m_mapEnd;
|
||||
};
|
||||
|
||||
typedef node_iterator_base<node> node_iterator;
|
||||
typedef node_iterator_base<const node> const_node_iterator;
|
||||
using node_iterator = node_iterator_base<node>;
|
||||
using const_node_iterator = node_iterator_base<const node>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,15 +11,17 @@
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/detail/node_data.h"
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node_ref : private boost::noncopyable {
|
||||
class node_ref {
|
||||
public:
|
||||
node_ref() : m_pData(new node_data) {}
|
||||
node_ref(const node_ref&) = delete;
|
||||
node_ref& operator=(const node_ref&) = delete;
|
||||
|
||||
bool is_defined() const { return m_pData->is_defined(); }
|
||||
const Mark& mark() const { return m_pData->mark(); }
|
||||
NodeType::value type() const { return m_pData->type(); }
|
||||
const std::string& scalar() const { return m_pData->scalar(); }
|
||||
const std::string& tag() const { return m_pData->tag(); }
|
||||
@@ -28,6 +30,7 @@ class node_ref : private boost::noncopyable {
|
||||
void mark_defined() { m_pData->mark_defined(); }
|
||||
void set_data(const node_ref& rhs) { m_pData = rhs.m_pData; }
|
||||
|
||||
void set_mark(const Mark& mark) { m_pData->set_mark(mark); }
|
||||
void set_type(NodeType::value type) { m_pData->set_type(type); }
|
||||
void set_tag(const std::string& tag) { m_pData->set_tag(tag); }
|
||||
void set_null() { m_pData->set_null(); }
|
||||
|
@@ -16,10 +16,17 @@ namespace YAML {
|
||||
class Emitter;
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* Emits the node to the given {@link Emitter}. If there is an error in writing,
|
||||
* {@link Emitter#good} will return false.
|
||||
*/
|
||||
YAML_CPP_API Emitter& operator<<(Emitter& out, const Node& node);
|
||||
|
||||
/** Emits the node to the given output stream. */
|
||||
YAML_CPP_API std::ostream& operator<<(std::ostream& out, const Node& node);
|
||||
|
||||
/** Converts the node to a YAML string. */
|
||||
YAML_CPP_API std::string Dump(const Node& node);
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -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 <sstream>
|
||||
#include <string>
|
||||
|
||||
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 <typename T>
|
||||
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& rhs) = default;
|
||||
|
||||
inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {}
|
||||
inline Node::Node(Zombie)
|
||||
: m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}
|
||||
|
||||
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();
|
||||
@@ -66,9 +72,16 @@ inline bool Node::IsDefined() const {
|
||||
return m_pNode ? m_pNode->is_defined() : true;
|
||||
}
|
||||
|
||||
inline Mark Node::Mark() const {
|
||||
if (!m_isValid) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -80,7 +93,7 @@ struct as_if {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
const T operator()(const S& fallback) const {
|
||||
T operator()(const S& fallback) const {
|
||||
if (!node.m_pNode)
|
||||
return fallback;
|
||||
|
||||
@@ -96,7 +109,7 @@ struct as_if<std::string, S> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
const std::string operator()(const S& fallback) const {
|
||||
std::string operator()(const S& fallback) const {
|
||||
if (node.Type() != NodeType::Scalar)
|
||||
return fallback;
|
||||
return node.Scalar();
|
||||
@@ -108,14 +121,14 @@ struct as_if<T, void> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
const T operator()() const {
|
||||
T operator()() const {
|
||||
if (!node.m_pNode)
|
||||
throw TypedBadConversion<T>();
|
||||
throw TypedBadConversion<T>(node.Mark());
|
||||
|
||||
T t;
|
||||
if (convert<T>::decode(node, t))
|
||||
return t;
|
||||
throw TypedBadConversion<T>();
|
||||
throw TypedBadConversion<T>(node.Mark());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,56 +137,52 @@ struct as_if<std::string, void> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
const std::string operator()() const {
|
||||
std::string operator()() const {
|
||||
if (node.Type() != NodeType::Scalar)
|
||||
throw TypedBadConversion<std::string>();
|
||||
throw TypedBadConversion<std::string>(node.Mark());
|
||||
return node.Scalar();
|
||||
}
|
||||
};
|
||||
|
||||
// access functions
|
||||
template <typename T>
|
||||
inline const T Node::as() const {
|
||||
inline T Node::as() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
throw InvalidNode(m_invalidKey);
|
||||
return as_if<T, void>(*this)();
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
inline const T Node::as(const S& fallback) const {
|
||||
inline T Node::as(const S& fallback) const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return fallback;
|
||||
return as_if<T, S>(*this)(fallback);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -181,7 +190,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);
|
||||
@@ -189,15 +198,20 @@ inline bool Node::is(const Node& rhs) const {
|
||||
|
||||
template <typename T>
|
||||
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;
|
||||
}
|
||||
@@ -205,44 +219,27 @@ inline void Node::reset(const YAML::Node& rhs) {
|
||||
template <typename T>
|
||||
inline void Node::Assign(const T& rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
throw InvalidNode(m_invalidKey);
|
||||
AssignData(convert<T>::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();
|
||||
|
||||
@@ -251,8 +248,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) {
|
||||
@@ -269,32 +266,32 @@ 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;
|
||||
}
|
||||
|
||||
inline const_iterator Node::begin() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return const_iterator();
|
||||
return m_pNode ? const_iterator(m_pNode->begin(), m_pMemory)
|
||||
: const_iterator();
|
||||
}
|
||||
|
||||
inline iterator Node::begin() {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return iterator();
|
||||
return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator();
|
||||
}
|
||||
|
||||
inline const_iterator Node::end() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return const_iterator();
|
||||
return m_pNode ? const_iterator(m_pNode->end(), m_pMemory) : const_iterator();
|
||||
}
|
||||
|
||||
inline iterator Node::end() {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return iterator();
|
||||
return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator();
|
||||
}
|
||||
|
||||
@@ -302,13 +299,11 @@ inline iterator Node::end() {
|
||||
template <typename T>
|
||||
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();
|
||||
|
||||
@@ -322,7 +317,7 @@ template <typename T>
|
||||
struct to_value_t {
|
||||
explicit to_value_t(const T& t_) : t(t_) {}
|
||||
const T& t;
|
||||
typedef const T& return_type;
|
||||
using return_type = const T &;
|
||||
|
||||
const T& operator()() const { return t; }
|
||||
};
|
||||
@@ -331,7 +326,7 @@ template <>
|
||||
struct to_value_t<const char*> {
|
||||
explicit to_value_t(const char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
using return_type = std::string;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
@@ -340,7 +335,7 @@ template <>
|
||||
struct to_value_t<char*> {
|
||||
explicit to_value_t(char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
using return_type = std::string;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
@@ -349,7 +344,7 @@ template <std::size_t N>
|
||||
struct to_value_t<char[N]> {
|
||||
explicit to_value_t(const char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
using return_type = std::string;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
@@ -359,26 +354,27 @@ template <typename T>
|
||||
inline typename to_value_t<T>::return_type to_value(const T& t) {
|
||||
return to_value_t<T>(t)();
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename Key>
|
||||
std::string key_to_string(const Key& key) {
|
||||
return streamable_to_string<Key, is_streamable<std::stringstream, Key>::value>().impl(key);
|
||||
}
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
inline const Node Node::operator[](const Key& key) const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
detail::node* value = static_cast<const detail::node&>(*m_pNode)
|
||||
.get(detail::to_value(key), m_pMemory);
|
||||
detail::node* value = static_cast<const detail::node&>(*m_pNode).get(
|
||||
detail::to_value(key), m_pMemory);
|
||||
if (!value) {
|
||||
return Node(ZombieNode);
|
||||
return Node(ZombieNode, key_to_string(key));
|
||||
}
|
||||
return Node(*value, m_pMemory);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
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);
|
||||
return Node(value, m_pMemory);
|
||||
@@ -386,29 +382,23 @@ inline Node Node::operator[](const Key& key) {
|
||||
|
||||
template <typename Key>
|
||||
inline bool Node::remove(const Key& key) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
return m_pNode->remove(detail::to_value(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<const detail::node&>(*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);
|
||||
@@ -417,8 +407,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);
|
||||
@@ -427,8 +415,6 @@ inline bool Node::remove(const Node& key) {
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
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);
|
||||
@@ -436,6 +422,6 @@ inline void Node::force_insert(const Key& key, const Value& value) {
|
||||
|
||||
// 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
|
||||
|
@@ -18,7 +18,7 @@
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_value : public Node, std::pair<Node, Node> {
|
||||
iterator_value() {}
|
||||
iterator_value() = default;
|
||||
explicit iterator_value(const Node& rhs)
|
||||
: Node(rhs),
|
||||
std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {}
|
||||
|
@@ -8,10 +8,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/node/detail/bool_type.h"
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include "yaml-cpp/node/detail/iterator_fwd.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
@@ -37,8 +38,8 @@ class YAML_CPP_API Node {
|
||||
template <typename T, typename S>
|
||||
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);
|
||||
@@ -48,6 +49,7 @@ class YAML_CPP_API Node {
|
||||
Node(const Node& rhs);
|
||||
~Node();
|
||||
|
||||
YAML::Mark Mark() const;
|
||||
NodeType::value Type() const;
|
||||
bool IsDefined() const;
|
||||
bool IsNull() const { return Type() == NodeType::Null; }
|
||||
@@ -56,14 +58,14 @@ 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
|
||||
template <typename T>
|
||||
const T as() const;
|
||||
T as() const;
|
||||
template <typename T, typename S>
|
||||
const T as(const S& fallback) const;
|
||||
T as(const S& fallback) const;
|
||||
const std::string& Scalar() const;
|
||||
|
||||
const std::string& Tag() const;
|
||||
@@ -114,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;
|
||||
@@ -128,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;
|
||||
};
|
||||
|
@@ -16,15 +16,63 @@
|
||||
namespace YAML {
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* Loads the input string as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(const std::string& input);
|
||||
|
||||
/**
|
||||
* Loads the input string as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(const char* input);
|
||||
|
||||
/**
|
||||
* Loads the input stream as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(std::istream& input);
|
||||
|
||||
/**
|
||||
* Loads the input file as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
* @throws {@link BadFile} if the file cannot be loaded.
|
||||
*/
|
||||
YAML_CPP_API Node LoadFile(const std::string& filename);
|
||||
|
||||
/**
|
||||
* Loads the input string as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(const std::string& input);
|
||||
|
||||
/**
|
||||
* Loads the input string as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(const char* input);
|
||||
|
||||
/**
|
||||
* Loads the input stream as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(std::istream& input);
|
||||
|
||||
/**
|
||||
* Loads the input file as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
* @throws {@link BadFile} if the file cannot be loaded.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAllFromFile(const std::string& filename);
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
@@ -18,11 +18,11 @@ class node_data;
|
||||
class memory;
|
||||
class memory_holder;
|
||||
|
||||
typedef boost::shared_ptr<node> shared_node;
|
||||
typedef boost::shared_ptr<node_ref> shared_node_ref;
|
||||
typedef boost::shared_ptr<node_data> shared_node_data;
|
||||
typedef boost::shared_ptr<memory_holder> shared_memory_holder;
|
||||
typedef boost::shared_ptr<memory> shared_memory;
|
||||
using shared_node = std::shared_ptr<node>;
|
||||
using shared_node_ref = std::shared_ptr<node_ref>;
|
||||
using shared_node_data = std::shared_ptr<node_data>;
|
||||
using shared_memory_holder = std::shared_ptr<memory_holder>;
|
||||
using shared_memory = std::shared_ptr<memory>;
|
||||
}
|
||||
}
|
||||
|
||||
|
18
include/yaml-cpp/noexcept.h
Normal file
18
include/yaml-cpp/noexcept.h
Normal file
@@ -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
|
@@ -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
|
@@ -8,6 +8,7 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
class Node;
|
||||
@@ -17,6 +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);
|
||||
|
||||
extern YAML_CPP_API _Null Null;
|
||||
}
|
||||
|
@@ -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 <std::size_t N>
|
||||
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
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
namespace YAML {
|
||||
class EventHandler;
|
||||
@@ -20,29 +19,72 @@ class Scanner;
|
||||
struct Directives;
|
||||
struct Token;
|
||||
|
||||
class YAML_CPP_API Parser : private noncopyable {
|
||||
/**
|
||||
* A parser turns a stream of bytes into one stream of "events" per YAML
|
||||
* document in the input stream.
|
||||
*/
|
||||
class YAML_CPP_API Parser {
|
||||
public:
|
||||
/** Constructs an empty parser (with no input. */
|
||||
Parser();
|
||||
Parser(std::istream& in);
|
||||
|
||||
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.
|
||||
*/
|
||||
explicit Parser(std::istream& in);
|
||||
|
||||
~Parser();
|
||||
|
||||
operator bool() const;
|
||||
/** Evaluates to true if the parser has some valid input to be read. */
|
||||
explicit operator bool() const;
|
||||
|
||||
/**
|
||||
* Resets the parser with the given input stream. Any existing state is
|
||||
* erased.
|
||||
*/
|
||||
void Load(std::istream& in);
|
||||
|
||||
/**
|
||||
* Handles the next document by calling events on the {@code eventHandler}.
|
||||
*
|
||||
* @throw a ParserException on error.
|
||||
* @return false if there are no more documents
|
||||
*/
|
||||
bool HandleNextDocument(EventHandler& eventHandler);
|
||||
|
||||
void PrintTokens(std::ostream& out);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Reads any directives that are next in the queue, setting the internal
|
||||
* {@code m_pDirectives} state.
|
||||
*/
|
||||
void ParseDirectives();
|
||||
|
||||
void HandleDirective(const Token& token);
|
||||
|
||||
/**
|
||||
* Handles a "YAML" directive, which should be of the form 'major.minor' (like
|
||||
* a version number).
|
||||
*/
|
||||
void HandleYamlDirective(const Token& token);
|
||||
|
||||
/**
|
||||
* Handles a "TAG" directive, which should be of the form 'handle prefix',
|
||||
* where 'handle' is converted to 'prefix' in the file.
|
||||
*/
|
||||
void HandleTagDirective(const Token& token);
|
||||
|
||||
private:
|
||||
std::auto_ptr<Scanner> m_pScanner;
|
||||
std::auto_ptr<Directives> m_pDirectives;
|
||||
std::unique_ptr<Scanner> m_pScanner;
|
||||
std::unique_ptr<Directives> m_pDirectives;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -7,6 +7,11 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace YAML {
|
||||
template <typename>
|
||||
struct is_numeric {
|
||||
@@ -79,7 +84,7 @@ struct is_numeric<long double> {
|
||||
|
||||
template <bool, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -90,7 +95,7 @@ struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||
|
||||
template <bool, class T = void>
|
||||
struct disable_if_c {
|
||||
typedef T type;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -100,4 +105,31 @@ template <class Cond, class T = void>
|
||||
struct disable_if : public disable_if_c<Cond::value, T> {};
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
struct is_streamable {
|
||||
template <typename SS, typename TT>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
|
||||
|
||||
template <typename, typename>
|
||||
static auto test(...) -> std::false_type;
|
||||
|
||||
static const bool value = decltype(test<S, T>(0))::value;
|
||||
};
|
||||
|
||||
template<typename Key, bool Streamable>
|
||||
struct streamable_to_string {
|
||||
static std::string impl(const Key& key) {
|
||||
std::stringstream ss;
|
||||
ss << key;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Key>
|
||||
struct streamable_to_string<Key, false> {
|
||||
static std::string impl(const Key&) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#include "yaml-cpp/binary.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace YAML {
|
||||
static const char encoding[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
@@ -64,7 +66,7 @@ static const unsigned char decoding[] = {
|
||||
};
|
||||
|
||||
std::vector<unsigned char> DecodeBase64(const std::string &input) {
|
||||
typedef std::vector<unsigned char> ret_type;
|
||||
using ret_type = std::vector<unsigned char>;
|
||||
if (input.empty())
|
||||
return ret_type();
|
||||
|
||||
@@ -72,19 +74,24 @@ std::vector<unsigned char> DecodeBase64(const std::string &input) {
|
||||
unsigned char *out = &ret[0];
|
||||
|
||||
unsigned value = 0;
|
||||
for (std::size_t i = 0; i < input.size(); i++) {
|
||||
for (std::size_t i = 0, cnt = 0; i < input.size(); i++) {
|
||||
if (std::isspace(input[i])) {
|
||||
// skip newlines
|
||||
continue;
|
||||
}
|
||||
unsigned char d = decoding[static_cast<unsigned>(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]);
|
||||
|
@@ -7,8 +7,8 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
|
||||
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<CollectionType::value> collectionStack;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -11,7 +11,7 @@ void* BuildGraphOfNextDocument(Parser& parser,
|
||||
if (parser.HandleNextDocument(eventHandler)) {
|
||||
return eventHandler.RootNode();
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ void GraphBuilderAdapter::OnMapStart(const Mark &mark, const std::string &tag,
|
||||
EmitterStyle::value /* style */) {
|
||||
void *pNode = m_builder.NewMap(mark, tag, GetCurrentParent());
|
||||
m_containers.push(ContainerFrame(pNode, m_pKeyNode));
|
||||
m_pKeyNode = NULL;
|
||||
m_pKeyNode = nullptr;
|
||||
RegisterAnchor(anchor, pNode);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ void GraphBuilderAdapter::OnMapEnd() {
|
||||
|
||||
void *GraphBuilderAdapter::GetCurrentParent() const {
|
||||
if (m_containers.empty()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return m_containers.top().pContainer;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ void GraphBuilderAdapter::DispositionNode(void *pNode) {
|
||||
if (m_containers.top().isMap()) {
|
||||
if (m_pKeyNode) {
|
||||
m_builder.AssignInMap(pContainer, m_pKeyNode, pNode);
|
||||
m_pKeyNode = NULL;
|
||||
m_pKeyNode = nullptr;
|
||||
} else {
|
||||
m_pKeyNode = pNode;
|
||||
}
|
||||
|
@@ -26,7 +26,15 @@ namespace YAML {
|
||||
class GraphBuilderAdapter : public EventHandler {
|
||||
public:
|
||||
GraphBuilderAdapter(GraphBuilderInterface& builder)
|
||||
: m_builder(builder), m_pRootNode(NULL), m_pKeyNode(NULL) {}
|
||||
: m_builder(builder),
|
||||
m_containers{},
|
||||
m_anchors{},
|
||||
m_pRootNode(nullptr),
|
||||
m_pKeyNode(nullptr) {}
|
||||
GraphBuilderAdapter(const GraphBuilderAdapter&) = delete;
|
||||
GraphBuilderAdapter(GraphBuilderAdapter&&) = delete;
|
||||
GraphBuilderAdapter& operator=(const GraphBuilderAdapter&) = delete;
|
||||
GraphBuilderAdapter& operator=(GraphBuilderAdapter&&) = delete;
|
||||
|
||||
virtual void OnDocumentStart(const Mark& mark) { (void)mark; }
|
||||
virtual void OnDocumentEnd() {}
|
||||
@@ -50,8 +58,8 @@ class GraphBuilderAdapter : public EventHandler {
|
||||
struct ContainerFrame {
|
||||
ContainerFrame(void* pSequence)
|
||||
: pContainer(pSequence), pPrevKeyNode(&sequenceMarker) {}
|
||||
ContainerFrame(void* pMap, void* pPrevKeyNode)
|
||||
: pContainer(pMap), pPrevKeyNode(pPrevKeyNode) {}
|
||||
ContainerFrame(void* pMap, void* pPreviousKeyNode)
|
||||
: pContainer(pMap), pPrevKeyNode(pPreviousKeyNode) {}
|
||||
|
||||
void* pContainer;
|
||||
void* pPrevKeyNode;
|
||||
@@ -74,6 +82,6 @@ class GraphBuilderAdapter : public EventHandler {
|
||||
void RegisterAnchor(anchor_t anchor, void* pNode);
|
||||
void DispositionNode(void* pNode);
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
32
src/contrib/yaml-cpp.natvis
Normal file
32
src/contrib/yaml-cpp.natvis
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- MSVC Debugger visualization hints for YAML::Node and YAML::detail::node -->
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="YAML::Node">
|
||||
<DisplayString Condition="!m_isValid">{{invalid}}</DisplayString>
|
||||
<DisplayString Condition="!m_pNode">{{pNode==nullptr}}</DisplayString>
|
||||
<DisplayString>{{ {*m_pNode} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Condition="m_pNode->m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Scalar" Name="scalar">m_pNode->m_pRef._Ptr->m_pData._Ptr->m_scalar</Item>
|
||||
<Item Condition="m_pNode->m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Sequence" Name="sequence">m_pNode->m_pRef._Ptr->m_pData._Ptr->m_sequence</Item>
|
||||
<Item Condition="m_pNode->m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Map" Name="map">m_pNode->m_pRef._Ptr->m_pData._Ptr->m_map</Item>
|
||||
<Item Name="[details]" >m_pNode->m_pRef._Ptr->m_pData._Ptr</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="YAML::detail::node">
|
||||
<DisplayString Condition="!m_pRef._Ptr">{{node:pRef==nullptr}}</DisplayString>
|
||||
<DisplayString Condition="!m_pRef._Ptr->m_pData._Ptr">{{node:pRef->pData==nullptr}}</DisplayString>
|
||||
<DisplayString Condition="!m_pRef._Ptr->m_pData._Ptr->m_isDefined">{{undefined}}</DisplayString>
|
||||
<DisplayString Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Scalar">{{{m_pRef._Ptr->m_pData._Ptr->m_scalar}}}</DisplayString>
|
||||
<DisplayString Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Map">{{ Map {m_pRef._Ptr->m_pData._Ptr->m_map}}}</DisplayString>
|
||||
<DisplayString Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Sequence">{{ Seq {m_pRef._Ptr->m_pData._Ptr->m_sequence}}}</DisplayString>
|
||||
<DisplayString>{{{m_pRef._Ptr->m_pData._Ptr->m_type}}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Scalar" Name="scalar">m_pRef._Ptr->m_pData._Ptr->m_scalar</Item>
|
||||
<Item Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Sequence" Name="sequence">m_pRef._Ptr->m_pData._Ptr->m_sequence</Item>
|
||||
<Item Condition="m_pRef._Ptr->m_pData._Ptr->m_type==YAML::NodeType::Map" Name="map">m_pRef._Ptr->m_pData._Ptr->m_map</Item>
|
||||
<Item Name="[details]" >m_pRef._Ptr->m_pData._Ptr</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
</AutoVisualizer>
|
9
src/contrib/yaml-cpp.natvis.md
Normal file
9
src/contrib/yaml-cpp.natvis.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# MSVC debugger visualizer for YAML::Node
|
||||
|
||||
## How to use
|
||||
Add yaml-cpp.natvis to your Visual C++ project like any other source file. It will be included in the debug information, and improve debugger display on YAML::Node and contained types.
|
||||
|
||||
## Compatibility and Troubleshooting
|
||||
|
||||
This has been tested for MSVC 2017. It is expected to be compatible with VS 2015 and VS 2019. If you have any problems, you can open an issue here: https://github.com/peterchen-cp/yaml-cpp-natvis
|
||||
|
@@ -16,8 +16,8 @@ std::string tolower(const std::string& str) {
|
||||
|
||||
template <typename T>
|
||||
bool IsEntirely(const std::string& str, T func) {
|
||||
for (std::size_t i = 0; i < str.size(); i++)
|
||||
if (!func(str[i]))
|
||||
for (char ch : str)
|
||||
if (!func(ch))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -39,7 +39,7 @@ bool IsFlexibleCase(const std::string& str) {
|
||||
std::string rest = str.substr(1);
|
||||
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace YAML {
|
||||
bool convert<bool>::decode(const Node& node, bool& rhs) {
|
||||
@@ -52,19 +52,22 @@ bool convert<bool>::decode(const Node& node, bool& rhs) {
|
||||
static const struct {
|
||||
std::string truename, falsename;
|
||||
} names[] = {
|
||||
{"y", "n"}, {"yes", "no"}, {"true", "false"}, {"on", "off"},
|
||||
{"y", "n"},
|
||||
{"yes", "no"},
|
||||
{"true", "false"},
|
||||
{"on", "off"},
|
||||
};
|
||||
|
||||
if (!IsFlexibleCase(node.Scalar()))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
|
||||
if (names[i].truename == tolower(node.Scalar())) {
|
||||
for (const auto& name : names) {
|
||||
if (name.truename == tolower(node.Scalar())) {
|
||||
rhs = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (names[i].falsename == tolower(node.Scalar())) {
|
||||
if (name.falsename == tolower(node.Scalar())) {
|
||||
rhs = false;
|
||||
return true;
|
||||
}
|
||||
@@ -72,4 +75,4 @@ bool convert<bool>::decode(const Node& node, bool& rhs) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -1,12 +1,7 @@
|
||||
#include "directives.h"
|
||||
|
||||
namespace YAML {
|
||||
Directives::Directives() {
|
||||
// version
|
||||
version.isDefault = true;
|
||||
version.major = 1;
|
||||
version.minor = 2;
|
||||
}
|
||||
Directives::Directives() : version{true, 1, 2}, tags{} {}
|
||||
|
||||
const std::string Directives::TranslateTagHandle(
|
||||
const std::string& handle) const {
|
||||
@@ -19,4 +14,4 @@ const std::string Directives::TranslateTagHandle(
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -22,4 +22,4 @@ std::string Dump(const Node& node) {
|
||||
emitter << node;
|
||||
return emitter.c_str();
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -16,10 +16,11 @@ std::string ToString(YAML::anchor_t anchor) {
|
||||
stream << anchor;
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace YAML {
|
||||
EmitFromEvents::EmitFromEvents(Emitter& emitter) : m_emitter(emitter) {}
|
||||
EmitFromEvents::EmitFromEvents(Emitter& emitter)
|
||||
: m_emitter(emitter), m_stateStack{} {}
|
||||
|
||||
void EmitFromEvents::OnDocumentStart(const Mark&) {}
|
||||
|
||||
@@ -111,9 +112,9 @@ void EmitFromEvents::BeginNode() {
|
||||
}
|
||||
|
||||
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) {
|
||||
if (!tag.empty() && tag != "?")
|
||||
if (!tag.empty() && tag != "?" && tag != "!")
|
||||
m_emitter << VerbatimTag(tag);
|
||||
if (anchor)
|
||||
m_emitter << Anchor(ToString(anchor));
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -11,12 +11,12 @@ namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
|
||||
Emitter::Emitter() : m_pState(new EmitterState) {}
|
||||
Emitter::Emitter() : m_pState(new EmitterState), m_stream{} {}
|
||||
|
||||
Emitter::Emitter(std::ostream& stream)
|
||||
: m_pState(new EmitterState), m_stream(stream) {}
|
||||
|
||||
Emitter::~Emitter() {}
|
||||
Emitter::~Emitter() = default;
|
||||
|
||||
const char* Emitter::c_str() const { return m_stream.str(); }
|
||||
|
||||
@@ -285,10 +285,8 @@ void Emitter::PrepareTopNode(EmitterNodeType::value child) {
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0) {
|
||||
if (child != EmitterNodeType::NoType)
|
||||
EmitBeginDoc();
|
||||
}
|
||||
if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0)
|
||||
EmitBeginDoc();
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
@@ -908,4 +906,4 @@ Emitter& Emitter::Write(const Binary& binary) {
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -6,29 +6,33 @@
|
||||
namespace YAML {
|
||||
EmitterState::EmitterState()
|
||||
: m_isGood(true),
|
||||
m_lastError{},
|
||||
// default global manipulators
|
||||
m_charset(EmitNonAscii),
|
||||
m_strFmt(Auto),
|
||||
m_boolFmt(TrueFalseBool),
|
||||
m_boolLengthFmt(LongBool),
|
||||
m_boolCaseFmt(LowerCase),
|
||||
m_intFmt(Dec),
|
||||
m_indent(2),
|
||||
m_preCommentIndent(2),
|
||||
m_postCommentIndent(1),
|
||||
m_seqFmt(Block),
|
||||
m_mapFmt(Block),
|
||||
m_mapKeyFmt(Auto),
|
||||
m_floatPrecision(std::numeric_limits<float>::max_digits10),
|
||||
m_doublePrecision(std::numeric_limits<double>::max_digits10),
|
||||
//
|
||||
m_modifiedSettings{},
|
||||
m_globalModifiedSettings{},
|
||||
m_groups{},
|
||||
m_curIndent(0),
|
||||
m_hasAnchor(false),
|
||||
m_hasTag(false),
|
||||
m_hasNonContent(false),
|
||||
m_docCount(0) {
|
||||
// set default global manipulators
|
||||
m_charset.set(EmitNonAscii);
|
||||
m_strFmt.set(Auto);
|
||||
m_boolFmt.set(TrueFalseBool);
|
||||
m_boolLengthFmt.set(LongBool);
|
||||
m_boolCaseFmt.set(LowerCase);
|
||||
m_intFmt.set(Dec);
|
||||
m_indent.set(2);
|
||||
m_preCommentIndent.set(2);
|
||||
m_postCommentIndent.set(1);
|
||||
m_seqFmt.set(Block);
|
||||
m_mapFmt.set(Block);
|
||||
m_mapKeyFmt.set(Auto);
|
||||
m_floatPrecision.set(std::numeric_limits<float>::digits10 + 1);
|
||||
m_doublePrecision.set(std::numeric_limits<double>::digits10 + 1);
|
||||
}
|
||||
m_docCount(0) {}
|
||||
|
||||
EmitterState::~EmitterState() {}
|
||||
EmitterState::~EmitterState() = default;
|
||||
|
||||
// SetLocalValue
|
||||
// . We blindly tries to set all possible formatters to this value
|
||||
@@ -53,28 +57,31 @@ void EmitterState::SetNonContent() { m_hasNonContent = true; }
|
||||
|
||||
void EmitterState::SetLongKey() {
|
||||
assert(!m_groups.empty());
|
||||
if (m_groups.empty())
|
||||
if (m_groups.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_groups.top().type == GroupType::Map);
|
||||
m_groups.top().longKey = true;
|
||||
assert(m_groups.back()->type == GroupType::Map);
|
||||
m_groups.back()->longKey = true;
|
||||
}
|
||||
|
||||
void EmitterState::ForceFlow() {
|
||||
assert(!m_groups.empty());
|
||||
if (m_groups.empty())
|
||||
if (m_groups.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_groups.top().flowType = FlowType::Flow;
|
||||
m_groups.back()->flowType = FlowType::Flow;
|
||||
}
|
||||
|
||||
void EmitterState::StartedNode() {
|
||||
if (m_groups.empty()) {
|
||||
m_docCount++;
|
||||
} else {
|
||||
m_groups.top().childCount++;
|
||||
if (m_groups.top().childCount % 2 == 0)
|
||||
m_groups.top().longKey = false;
|
||||
m_groups.back()->childCount++;
|
||||
if (m_groups.back()->childCount % 2 == 0) {
|
||||
m_groups.back()->longKey = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hasAnchor = false;
|
||||
@@ -121,41 +128,50 @@ void EmitterState::StartedScalar() {
|
||||
void EmitterState::StartedGroup(GroupType::value type) {
|
||||
StartedNode();
|
||||
|
||||
const int lastGroupIndent = (m_groups.empty() ? 0 : m_groups.top().indent);
|
||||
const std::size_t lastGroupIndent =
|
||||
(m_groups.empty() ? 0 : m_groups.back()->indent);
|
||||
m_curIndent += lastGroupIndent;
|
||||
|
||||
std::auto_ptr<Group> pGroup(new Group(type));
|
||||
// TODO: Create move constructors for settings types to simplify transfer
|
||||
std::unique_ptr<Group> pGroup(new Group(type));
|
||||
|
||||
// transfer settings (which last until this group is done)
|
||||
pGroup->modifiedSettings = m_modifiedSettings;
|
||||
//
|
||||
// NB: if pGroup->modifiedSettings == m_modifiedSettings,
|
||||
// m_modifiedSettings is not changed!
|
||||
pGroup->modifiedSettings = std::move(m_modifiedSettings);
|
||||
|
||||
// set up group
|
||||
if (GetFlowType(type) == Block)
|
||||
if (GetFlowType(type) == Block) {
|
||||
pGroup->flowType = FlowType::Block;
|
||||
else
|
||||
} else {
|
||||
pGroup->flowType = FlowType::Flow;
|
||||
}
|
||||
pGroup->indent = GetIndent();
|
||||
|
||||
m_groups.push(pGroup);
|
||||
m_groups.push_back(std::move(pGroup));
|
||||
}
|
||||
|
||||
void EmitterState::EndedGroup(GroupType::value type) {
|
||||
if (m_groups.empty()) {
|
||||
if (type == GroupType::Seq)
|
||||
if (type == GroupType::Seq) {
|
||||
return SetError(ErrorMsg::UNEXPECTED_END_SEQ);
|
||||
else
|
||||
} else {
|
||||
return SetError(ErrorMsg::UNEXPECTED_END_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of the current group
|
||||
{
|
||||
std::auto_ptr<Group> pFinishedGroup = m_groups.pop();
|
||||
if (pFinishedGroup->type != type)
|
||||
std::unique_ptr<Group> pFinishedGroup = std::move(m_groups.back());
|
||||
m_groups.pop_back();
|
||||
if (pFinishedGroup->type != type) {
|
||||
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
// reset old settings
|
||||
std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.top().indent);
|
||||
std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.back()->indent);
|
||||
assert(m_curIndent >= lastIndent);
|
||||
m_curIndent -= lastIndent;
|
||||
|
||||
@@ -167,37 +183,39 @@ void EmitterState::EndedGroup(GroupType::value type) {
|
||||
}
|
||||
|
||||
EmitterNodeType::value EmitterState::CurGroupNodeType() const {
|
||||
if (m_groups.empty())
|
||||
if (m_groups.empty()) {
|
||||
return EmitterNodeType::NoType;
|
||||
}
|
||||
|
||||
return m_groups.top().NodeType();
|
||||
return m_groups.back()->NodeType();
|
||||
}
|
||||
|
||||
GroupType::value EmitterState::CurGroupType() const {
|
||||
return m_groups.empty() ? GroupType::NoType : m_groups.top().type;
|
||||
return m_groups.empty() ? GroupType::NoType : m_groups.back()->type;
|
||||
}
|
||||
|
||||
FlowType::value EmitterState::CurGroupFlowType() const {
|
||||
return m_groups.empty() ? FlowType::NoType : m_groups.top().flowType;
|
||||
return m_groups.empty() ? FlowType::NoType : m_groups.back()->flowType;
|
||||
}
|
||||
|
||||
int EmitterState::CurGroupIndent() const {
|
||||
return m_groups.empty() ? 0 : m_groups.top().indent;
|
||||
std::size_t EmitterState::CurGroupIndent() const {
|
||||
return m_groups.empty() ? 0 : m_groups.back()->indent;
|
||||
}
|
||||
|
||||
std::size_t EmitterState::CurGroupChildCount() const {
|
||||
return m_groups.empty() ? m_docCount : m_groups.top().childCount;
|
||||
return m_groups.empty() ? m_docCount : m_groups.back()->childCount;
|
||||
}
|
||||
|
||||
bool EmitterState::CurGroupLongKey() const {
|
||||
return m_groups.empty() ? false : m_groups.top().longKey;
|
||||
return m_groups.empty() ? false : m_groups.back()->longKey;
|
||||
}
|
||||
|
||||
int EmitterState::LastIndent() const {
|
||||
if (m_groups.size() <= 1)
|
||||
std::size_t EmitterState::LastIndent() const {
|
||||
if (m_groups.size() <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_curIndent - m_groups.top(-1).indent;
|
||||
return m_curIndent - m_groups[m_groups.size() - 2]->indent;
|
||||
}
|
||||
|
||||
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
|
||||
@@ -334,17 +352,18 @@ bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetFloatPrecision(int value, FmtScope::value scope) {
|
||||
if (value < 0 || value > std::numeric_limits<float>::digits10 + 1)
|
||||
bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) {
|
||||
if (value > std::numeric_limits<float>::max_digits10)
|
||||
return false;
|
||||
_Set(m_floatPrecision, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetDoublePrecision(int value, FmtScope::value scope) {
|
||||
if (value < 0 || value > std::numeric_limits<double>::digits10 + 1)
|
||||
bool EmitterState::SetDoublePrecision(std::size_t value,
|
||||
FmtScope::value scope) {
|
||||
if (value > std::numeric_limits<double>::max_digits10)
|
||||
return false;
|
||||
_Set(m_doublePrecision, value, scope);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -7,15 +7,15 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ptr_stack.h"
|
||||
#include "setting.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
struct FmtScope {
|
||||
@@ -58,12 +58,12 @@ class EmitterState {
|
||||
|
||||
GroupType::value CurGroupType() const;
|
||||
FlowType::value CurGroupFlowType() const;
|
||||
int CurGroupIndent() const;
|
||||
std::size_t CurGroupIndent() const;
|
||||
std::size_t CurGroupChildCount() const;
|
||||
bool CurGroupLongKey() const;
|
||||
|
||||
int LastIndent() const;
|
||||
int CurIndent() const { return m_curIndent; }
|
||||
std::size_t LastIndent() const;
|
||||
std::size_t CurIndent() const { return m_curIndent; }
|
||||
bool HasAnchor() const { return m_hasAnchor; }
|
||||
bool HasTag() const { return m_hasTag; }
|
||||
bool HasBegunNode() const {
|
||||
@@ -95,12 +95,12 @@ class EmitterState {
|
||||
EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); }
|
||||
|
||||
bool SetIndent(std::size_t value, FmtScope::value scope);
|
||||
int GetIndent() const { return m_indent.get(); }
|
||||
std::size_t GetIndent() const { return m_indent.get(); }
|
||||
|
||||
bool SetPreCommentIndent(std::size_t value, FmtScope::value scope);
|
||||
int GetPreCommentIndent() const { return m_preCommentIndent.get(); }
|
||||
std::size_t GetPreCommentIndent() const { return m_preCommentIndent.get(); }
|
||||
bool SetPostCommentIndent(std::size_t value, FmtScope::value scope);
|
||||
int GetPostCommentIndent() const { return m_postCommentIndent.get(); }
|
||||
std::size_t GetPostCommentIndent() const { return m_postCommentIndent.get(); }
|
||||
|
||||
bool SetFlowType(GroupType::value groupType, EMITTER_MANIP value,
|
||||
FmtScope::value scope);
|
||||
@@ -109,9 +109,9 @@ class EmitterState {
|
||||
bool SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); }
|
||||
|
||||
bool SetFloatPrecision(int value, FmtScope::value scope);
|
||||
bool SetFloatPrecision(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetFloatPrecision() const { return m_floatPrecision.get(); }
|
||||
bool SetDoublePrecision(int value, FmtScope::value scope);
|
||||
bool SetDoublePrecision(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetDoublePrecision() const { return m_doublePrecision.get(); }
|
||||
|
||||
private:
|
||||
@@ -137,19 +137,24 @@ class EmitterState {
|
||||
Setting<EMITTER_MANIP> m_seqFmt;
|
||||
Setting<EMITTER_MANIP> m_mapFmt;
|
||||
Setting<EMITTER_MANIP> m_mapKeyFmt;
|
||||
Setting<int> m_floatPrecision;
|
||||
Setting<int> m_doublePrecision;
|
||||
Setting<std::size_t> m_floatPrecision;
|
||||
Setting<std::size_t> m_doublePrecision;
|
||||
|
||||
SettingChanges m_modifiedSettings;
|
||||
SettingChanges m_globalModifiedSettings;
|
||||
|
||||
struct Group {
|
||||
explicit Group(GroupType::value type_)
|
||||
: type(type_), indent(0), childCount(0), longKey(false) {}
|
||||
: type(type_),
|
||||
flowType{},
|
||||
indent(0),
|
||||
childCount(0),
|
||||
longKey(false),
|
||||
modifiedSettings{} {}
|
||||
|
||||
GroupType::value type;
|
||||
FlowType::value flowType;
|
||||
int indent;
|
||||
std::size_t indent;
|
||||
std::size_t childCount;
|
||||
bool longKey;
|
||||
|
||||
@@ -174,7 +179,7 @@ class EmitterState {
|
||||
}
|
||||
};
|
||||
|
||||
ptr_stack<Group> m_groups;
|
||||
std::vector<std::unique_ptr<Group>> m_groups;
|
||||
std::size_t m_curIndent;
|
||||
bool m_hasAnchor;
|
||||
bool m_hasTag;
|
||||
@@ -198,6 +203,6 @@ void EmitterState::_Set(Setting<T>& fmt, T value, FmtScope::value scope) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "regeximpl.h"
|
||||
#include "stringsource.h"
|
||||
#include "yaml-cpp/binary.h" // IWYU pragma: keep
|
||||
#include "yaml-cpp/null.h"
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
|
||||
namespace YAML {
|
||||
@@ -133,12 +134,12 @@ void WriteCodePoint(ostream_wrapper& out, int codePoint) {
|
||||
if (codePoint < 0 || codePoint > 0x10FFFF) {
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
}
|
||||
if (codePoint < 0x7F) {
|
||||
if (codePoint <= 0x7F) {
|
||||
out << static_cast<char>(codePoint);
|
||||
} else if (codePoint < 0x7FF) {
|
||||
} else if (codePoint <= 0x7FF) {
|
||||
out << static_cast<char>(0xC0 | (codePoint >> 6))
|
||||
<< static_cast<char>(0x80 | (codePoint & 0x3F));
|
||||
} else if (codePoint < 0xFFFF) {
|
||||
} else if (codePoint <= 0xFFFF) {
|
||||
out << static_cast<char>(0xE0 | (codePoint >> 12))
|
||||
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
|
||||
<< static_cast<char>(0x80 | (codePoint & 0x3F));
|
||||
@@ -152,12 +153,8 @@ void WriteCodePoint(ostream_wrapper& out, int codePoint) {
|
||||
|
||||
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
bool allowOnlyAscii) {
|
||||
if (str.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check against null
|
||||
if (str == "null") {
|
||||
if (IsNullString(str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -176,12 +173,12 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
|
||||
// then check until something is disallowed
|
||||
static const RegEx& disallowed_flow =
|
||||
Exp::EndScalarInFlow() || (Exp::BlankOrBreak() + Exp::Comment()) ||
|
||||
Exp::NotPrintable() || Exp::Utf8_ByteOrderMark() || Exp::Break() ||
|
||||
Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) |
|
||||
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
|
||||
Exp::Tab();
|
||||
static const RegEx& disallowed_block =
|
||||
Exp::EndScalar() || (Exp::BlankOrBreak() + Exp::Comment()) ||
|
||||
Exp::NotPrintable() || Exp::Utf8_ByteOrderMark() || Exp::Break() ||
|
||||
Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) |
|
||||
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
|
||||
Exp::Tab();
|
||||
const RegEx& disallowed =
|
||||
flowType == FlowType::Flow ? disallowed_flow : disallowed_block;
|
||||
@@ -202,11 +199,11 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
|
||||
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) {
|
||||
// TODO: check for non-printable characters?
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) {
|
||||
for (char ch : str) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch))) {
|
||||
return false;
|
||||
}
|
||||
if (str[i] == '\n') {
|
||||
if (ch == '\n') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -220,8 +217,8 @@ bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType,
|
||||
}
|
||||
|
||||
// TODO: check for non-printable characters?
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) {
|
||||
for (char ch : str) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -261,7 +258,7 @@ bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
EMITTER_MANIP strFormat,
|
||||
@@ -357,7 +354,7 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
}
|
||||
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
int indent) {
|
||||
std::size_t indent) {
|
||||
out << "|\n";
|
||||
out << IndentTo(indent);
|
||||
int codePoint;
|
||||
@@ -375,14 +372,18 @@ bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteChar(ostream_wrapper& out, char ch) {
|
||||
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
|
||||
out << ch;
|
||||
} else if ((0x20 <= ch && ch <= 0x7e) || ch == ' ') {
|
||||
out << "\"" << ch << "\"";
|
||||
} else if (ch == '\"') {
|
||||
out << "\"\\\"\"";
|
||||
} else if (ch == '\t') {
|
||||
out << "\"\\t\"";
|
||||
} else if (ch == '\n') {
|
||||
out << "\"\\n\"";
|
||||
} else if (ch == '\b') {
|
||||
out << "\"\\b\"";
|
||||
} else if (ch == '\\') {
|
||||
out << "\"\\\\\"";
|
||||
} else if (0x20 <= ch && ch <= 0x7e) {
|
||||
out << "\"" << ch << "\"";
|
||||
} else {
|
||||
out << "\"";
|
||||
WriteDoubleQuoteEscapeSequence(out, ch);
|
||||
@@ -392,7 +393,7 @@ bool WriteChar(ostream_wrapper& out, char ch) {
|
||||
}
|
||||
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
int postCommentIndent) {
|
||||
std::size_t postCommentIndent) {
|
||||
const std::size_t curIndent = out.col();
|
||||
out << "#" << Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
@@ -400,8 +401,8 @@ bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
if (codePoint == '\n') {
|
||||
out << "\n" << IndentTo(curIndent) << "#"
|
||||
<< Indentation(postCommentIndent);
|
||||
out << "\n"
|
||||
<< IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
@@ -478,5 +479,5 @@ bool WriteBinary(ostream_wrapper& out, const Binary& binary) {
|
||||
false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Utils
|
||||
} // namespace YAML
|
||||
|
@@ -34,10 +34,10 @@ bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
bool escapeNonAscii);
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
int indent);
|
||||
std::size_t indent);
|
||||
bool WriteChar(ostream_wrapper& out, char ch);
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
int postCommentIndent);
|
||||
std::size_t postCommentIndent);
|
||||
bool WriteAlias(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteAnchor(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim);
|
||||
|
20
src/exceptions.cpp
Normal file
20
src/exceptions.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "yaml-cpp/exceptions.h"
|
||||
#include "yaml-cpp/noexcept.h"
|
||||
|
||||
namespace YAML {
|
||||
|
||||
// These destructors are defined out-of-line so the vtable is only emitted once.
|
||||
Exception::~Exception() YAML_CPP_NOEXCEPT = default;
|
||||
ParserException::~ParserException() YAML_CPP_NOEXCEPT = default;
|
||||
RepresentationException::~RepresentationException() YAML_CPP_NOEXCEPT = default;
|
||||
InvalidScalar::~InvalidScalar() YAML_CPP_NOEXCEPT = default;
|
||||
KeyNotFound::~KeyNotFound() YAML_CPP_NOEXCEPT = default;
|
||||
InvalidNode::~InvalidNode() YAML_CPP_NOEXCEPT = default;
|
||||
BadConversion::~BadConversion() YAML_CPP_NOEXCEPT = default;
|
||||
BadDereference::~BadDereference() YAML_CPP_NOEXCEPT = default;
|
||||
BadSubscript::~BadSubscript() YAML_CPP_NOEXCEPT = default;
|
||||
BadPushback::~BadPushback() YAML_CPP_NOEXCEPT = default;
|
||||
BadInsert::~BadInsert() YAML_CPP_NOEXCEPT = default;
|
||||
EmitterException::~EmitterException() YAML_CPP_NOEXCEPT = default;
|
||||
BadFile::~BadFile() YAML_CPP_NOEXCEPT = default;
|
||||
}
|
@@ -12,8 +12,7 @@ namespace YAML {
|
||||
namespace Exp {
|
||||
unsigned ParseHex(const std::string& str, const Mark& mark) {
|
||||
unsigned value = 0;
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
char ch = str[i];
|
||||
for (char ch : str) {
|
||||
int digit = 0;
|
||||
if ('a' <= ch && ch <= 'f')
|
||||
digit = ch - 'a' + 10;
|
||||
@@ -132,5 +131,5 @@ std::string Escape(Stream& in) {
|
||||
std::stringstream msg;
|
||||
throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Exp
|
||||
} // namespace YAML
|
||||
|
75
src/exp.h
75
src/exp.h
@@ -20,6 +20,10 @@ namespace YAML {
|
||||
|
||||
namespace Exp {
|
||||
// misc
|
||||
inline const RegEx& Empty() {
|
||||
static const RegEx e;
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Space() {
|
||||
static const RegEx e = RegEx(' ');
|
||||
return e;
|
||||
@@ -29,15 +33,15 @@ inline const RegEx& Tab() {
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Blank() {
|
||||
static const RegEx e = Space() || Tab();
|
||||
static const RegEx e = Space() | Tab();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Break() {
|
||||
static const RegEx e = RegEx('\n') || RegEx("\r\n");
|
||||
static const RegEx e = RegEx('\n') | RegEx("\r\n");
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& BlankOrBreak() {
|
||||
static const RegEx e = Blank() || Break();
|
||||
static const RegEx e = Blank() | Break();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Digit() {
|
||||
@@ -45,29 +49,29 @@ inline const RegEx& Digit() {
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Alpha() {
|
||||
static const RegEx e = RegEx('a', 'z') || RegEx('A', 'Z');
|
||||
static const RegEx e = RegEx('a', 'z') | RegEx('A', 'Z');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& AlphaNumeric() {
|
||||
static const RegEx e = Alpha() || Digit();
|
||||
static const RegEx e = Alpha() | Digit();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Word() {
|
||||
static const RegEx e = AlphaNumeric() || RegEx('-');
|
||||
static const RegEx e = AlphaNumeric() | RegEx('-');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Hex() {
|
||||
static const RegEx e = Digit() || RegEx('A', 'F') || RegEx('a', 'f');
|
||||
static const RegEx e = Digit() | RegEx('A', 'F') | RegEx('a', 'f');
|
||||
return e;
|
||||
}
|
||||
// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec.
|
||||
// 5.1)
|
||||
inline const RegEx& NotPrintable() {
|
||||
static const RegEx e =
|
||||
RegEx(0) ||
|
||||
RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) ||
|
||||
RegEx(0x0E, 0x1F) ||
|
||||
(RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F')));
|
||||
RegEx(0) |
|
||||
RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) |
|
||||
RegEx(0x0E, 0x1F) |
|
||||
(RegEx('\xC2') + (RegEx('\x80', '\x84') | RegEx('\x86', '\x9F')));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Utf8_ByteOrderMark() {
|
||||
@@ -78,19 +82,19 @@ inline const RegEx& Utf8_ByteOrderMark() {
|
||||
// actual tags
|
||||
|
||||
inline const RegEx& DocStart() {
|
||||
static const RegEx e = RegEx("---") + (BlankOrBreak() || RegEx());
|
||||
static const RegEx e = RegEx("---") + (BlankOrBreak() | RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& DocEnd() {
|
||||
static const RegEx e = RegEx("...") + (BlankOrBreak() || RegEx());
|
||||
static const RegEx e = RegEx("...") + (BlankOrBreak() | RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& DocIndicator() {
|
||||
static const RegEx e = DocStart() || DocEnd();
|
||||
static const RegEx e = DocStart() | DocEnd();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& BlockEntry() {
|
||||
static const RegEx e = RegEx('-') + (BlankOrBreak() || RegEx());
|
||||
static const RegEx e = RegEx('-') + (BlankOrBreak() | RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Key() {
|
||||
@@ -102,11 +106,11 @@ inline const RegEx& KeyInFlow() {
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Value() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& ValueInFlow() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx(",}", REGEX_OR));
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx(",}", REGEX_OR));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& ValueInJSONFlow() {
|
||||
@@ -118,20 +122,20 @@ inline const RegEx Comment() {
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Anchor() {
|
||||
static const RegEx e = !(RegEx("[]{},", REGEX_OR) || BlankOrBreak());
|
||||
static const RegEx e = !(RegEx("[]{},", REGEX_OR) | BlankOrBreak());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& AnchorEnd() {
|
||||
static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak();
|
||||
static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) | BlankOrBreak();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& URI() {
|
||||
static const RegEx e = Word() || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) ||
|
||||
static const RegEx e = Word() | RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) |
|
||||
(RegEx('%') + Hex() + Hex());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Tag() {
|
||||
static const RegEx e = Word() || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) ||
|
||||
static const RegEx e = Word() | RegEx("#;/?:@&=+$_.~*'()", REGEX_OR) |
|
||||
(RegEx('%') + Hex() + Hex());
|
||||
return e;
|
||||
}
|
||||
@@ -144,27 +148,36 @@ inline const RegEx& Tag() {
|
||||
// space.
|
||||
inline const RegEx& PlainScalar() {
|
||||
static const RegEx e =
|
||||
!(BlankOrBreak() || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) ||
|
||||
(RegEx("-?:", REGEX_OR) + (BlankOrBreak() || RegEx())));
|
||||
!(BlankOrBreak() | RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) |
|
||||
(RegEx("-?:", REGEX_OR) + (BlankOrBreak() | RegEx())));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& PlainScalarInFlow() {
|
||||
static const RegEx e =
|
||||
!(BlankOrBreak() || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) ||
|
||||
!(BlankOrBreak() | RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) |
|
||||
(RegEx("-:", REGEX_OR) + Blank()));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EndScalar() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EndScalarInFlow() {
|
||||
static const RegEx e =
|
||||
(RegEx(':') + (BlankOrBreak() || RegEx() || RegEx(",]}", REGEX_OR))) ||
|
||||
(RegEx(':') + (BlankOrBreak() | RegEx() | RegEx(",]}", REGEX_OR))) |
|
||||
RegEx(",?[]{}", REGEX_OR);
|
||||
return e;
|
||||
}
|
||||
|
||||
inline const RegEx& ScanScalarEndInFlow() {
|
||||
static const RegEx e = (EndScalarInFlow() | (BlankOrBreak() + Comment()));
|
||||
return e;
|
||||
}
|
||||
|
||||
inline const RegEx& ScanScalarEnd() {
|
||||
static const RegEx e = EndScalar() | (BlankOrBreak() + Comment());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EscSingleQuote() {
|
||||
static const RegEx e = RegEx("\'\'");
|
||||
return e;
|
||||
@@ -179,15 +192,15 @@ inline const RegEx& ChompIndicator() {
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Chomp() {
|
||||
static const RegEx e = (ChompIndicator() + Digit()) ||
|
||||
(Digit() + ChompIndicator()) || ChompIndicator() ||
|
||||
static const RegEx e = (ChompIndicator() + Digit()) |
|
||||
(Digit() + ChompIndicator()) | ChompIndicator() |
|
||||
Digit();
|
||||
return e;
|
||||
}
|
||||
|
||||
// and some functions
|
||||
std::string Escape(Stream& in);
|
||||
}
|
||||
} // namespace Exp
|
||||
|
||||
namespace Keys {
|
||||
const char Directive = '%';
|
||||
@@ -203,7 +216,7 @@ const char LiteralScalar = '|';
|
||||
const char FoldedScalar = '>';
|
||||
const char VerbatimTagStart = '<';
|
||||
const char VerbatimTagEnd = '>';
|
||||
}
|
||||
}
|
||||
} // namespace Keys
|
||||
} // namespace YAML
|
||||
|
||||
#endif // EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include <assert.h>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include "yaml-cpp/exceptions.h"
|
||||
@@ -12,14 +12,24 @@
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
std::atomic<size_t> node::m_amount{0};
|
||||
|
||||
std::string node_data::empty_scalar;
|
||||
const std::string& node_data::empty_scalar() {
|
||||
static const std::string svalue;
|
||||
return svalue;
|
||||
}
|
||||
|
||||
node_data::node_data()
|
||||
: m_isDefined(false),
|
||||
m_mark(Mark::null_mark()),
|
||||
m_type(NodeType::Null),
|
||||
m_tag{},
|
||||
m_style(EmitterStyle::Default),
|
||||
m_seqSize(0) {}
|
||||
m_scalar{},
|
||||
m_sequence{},
|
||||
m_seqSize(0),
|
||||
m_map{},
|
||||
m_undefinedPairs{} {}
|
||||
|
||||
void node_data::mark_defined() {
|
||||
if (m_type == NodeType::Undefined)
|
||||
@@ -27,6 +37,8 @@ void node_data::mark_defined() {
|
||||
m_isDefined = true;
|
||||
}
|
||||
|
||||
void node_data::set_mark(const Mark& mark) { m_mark = mark; }
|
||||
|
||||
void node_data::set_type(NodeType::value type) {
|
||||
if (type == NodeType::Undefined) {
|
||||
m_type = type;
|
||||
@@ -99,7 +111,7 @@ void node_data::compute_seq_size() const {
|
||||
void node_data::compute_map_size() const {
|
||||
kv_pairs::iterator it = m_undefinedPairs.begin();
|
||||
while (it != m_undefinedPairs.end()) {
|
||||
kv_pairs::iterator jt = boost::next(it);
|
||||
kv_pairs::iterator jt = std::next(it);
|
||||
if (it->first->is_defined() && it->second->is_defined())
|
||||
m_undefinedPairs.erase(it);
|
||||
it = jt;
|
||||
@@ -185,7 +197,7 @@ void node_data::insert(node& key, node& value, shared_memory_holder pMemory) {
|
||||
convert_to_map(pMemory);
|
||||
break;
|
||||
case NodeType::Scalar:
|
||||
throw BadSubscript();
|
||||
throw BadSubscript(m_mark, key);
|
||||
}
|
||||
|
||||
insert_map_pair(key, value);
|
||||
@@ -194,7 +206,7 @@ void node_data::insert(node& key, node& value, shared_memory_holder pMemory) {
|
||||
// indexing
|
||||
node* node_data::get(node& key, shared_memory_holder /* pMemory */) const {
|
||||
if (m_type != NodeType::Map) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
@@ -202,7 +214,7 @@ node* node_data::get(node& key, shared_memory_holder /* pMemory */) const {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
node& node_data::get(node& key, shared_memory_holder pMemory) {
|
||||
@@ -215,7 +227,7 @@ node& node_data::get(node& 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) {
|
||||
@@ -232,6 +244,14 @@ bool node_data::remove(node& 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->is(key))
|
||||
m_undefinedPairs.erase(it);
|
||||
it = jt;
|
||||
}
|
||||
|
||||
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
if (it->first->is(key)) {
|
||||
m_map.erase(it);
|
||||
@@ -253,9 +273,10 @@ void node_data::reset_map() {
|
||||
}
|
||||
|
||||
void node_data::insert_map_pair(node& key, node& value) {
|
||||
m_map[&key] = &value;
|
||||
m_map.emplace_back(&key, &value);
|
||||
|
||||
if (!key.is_defined() || !value.is_defined())
|
||||
m_undefinedPairs.push_back(kv_pair(&key, &value));
|
||||
m_undefinedPairs.emplace_back(&key, &value);
|
||||
}
|
||||
|
||||
void node_data::convert_to_map(shared_memory_holder pMemory) {
|
||||
@@ -292,5 +313,5 @@ void node_data::convert_sequence_to_map(shared_memory_holder pMemory) {
|
||||
reset_sequence();
|
||||
m_type = NodeType::Map;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "nodebuilder.h"
|
||||
@@ -11,11 +10,16 @@ namespace YAML {
|
||||
struct Mark;
|
||||
|
||||
NodeBuilder::NodeBuilder()
|
||||
: m_pMemory(new detail::memory_holder), m_pRoot(0), m_mapDepth(0) {
|
||||
m_anchors.push_back(0); // since the anchors start at 1
|
||||
: m_pMemory(new detail::memory_holder),
|
||||
m_pRoot(nullptr),
|
||||
m_stack{},
|
||||
m_anchors{},
|
||||
m_keys{},
|
||||
m_mapDepth(0) {
|
||||
m_anchors.push_back(nullptr); // since the anchors start at 1
|
||||
}
|
||||
|
||||
NodeBuilder::~NodeBuilder() {}
|
||||
NodeBuilder::~NodeBuilder() = default;
|
||||
|
||||
Node NodeBuilder::Root() {
|
||||
if (!m_pRoot)
|
||||
@@ -28,8 +32,8 @@ void NodeBuilder::OnDocumentStart(const Mark&) {}
|
||||
|
||||
void NodeBuilder::OnDocumentEnd() {}
|
||||
|
||||
void NodeBuilder::OnNull(const Mark& /* mark */, anchor_t anchor) {
|
||||
detail::node& node = Push(anchor);
|
||||
void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) {
|
||||
detail::node& node = Push(mark, anchor);
|
||||
node.set_null();
|
||||
Pop();
|
||||
}
|
||||
@@ -40,18 +44,17 @@ void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
|
||||
Pop();
|
||||
}
|
||||
|
||||
void NodeBuilder::OnScalar(const Mark& /* mark */, const std::string& tag,
|
||||
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, const std::string& value) {
|
||||
detail::node& node = Push(anchor);
|
||||
detail::node& node = Push(mark, anchor);
|
||||
node.set_scalar(value);
|
||||
node.set_tag(tag);
|
||||
Pop();
|
||||
}
|
||||
|
||||
void NodeBuilder::OnSequenceStart(const Mark& /* mark */,
|
||||
const std::string& tag, anchor_t anchor,
|
||||
EmitterStyle::value style) {
|
||||
detail::node& node = Push(anchor);
|
||||
void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style) {
|
||||
detail::node& node = Push(mark, anchor);
|
||||
node.set_tag(tag);
|
||||
node.set_type(NodeType::Sequence);
|
||||
node.set_style(style);
|
||||
@@ -59,9 +62,9 @@ void NodeBuilder::OnSequenceStart(const Mark& /* mark */,
|
||||
|
||||
void NodeBuilder::OnSequenceEnd() { Pop(); }
|
||||
|
||||
void NodeBuilder::OnMapStart(const Mark& /* mark */, const std::string& tag,
|
||||
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style) {
|
||||
detail::node& node = Push(anchor);
|
||||
detail::node& node = Push(mark, anchor);
|
||||
node.set_type(NodeType::Map);
|
||||
node.set_tag(tag);
|
||||
node.set_style(style);
|
||||
@@ -74,8 +77,9 @@ void NodeBuilder::OnMapEnd() {
|
||||
Pop();
|
||||
}
|
||||
|
||||
detail::node& NodeBuilder::Push(anchor_t anchor) {
|
||||
detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) {
|
||||
detail::node& node = m_pMemory->create_node();
|
||||
node.set_mark(mark);
|
||||
RegisterAnchor(anchor, node);
|
||||
Push(node);
|
||||
return node;
|
||||
@@ -127,4 +131,4 @@ void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node& node) {
|
||||
m_anchors.push_back(&node);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -27,28 +27,32 @@ class Node;
|
||||
class NodeBuilder : public EventHandler {
|
||||
public:
|
||||
NodeBuilder();
|
||||
virtual ~NodeBuilder();
|
||||
NodeBuilder(const NodeBuilder&) = delete;
|
||||
NodeBuilder(NodeBuilder&&) = delete;
|
||||
NodeBuilder& operator=(const NodeBuilder&) = delete;
|
||||
NodeBuilder& operator=(NodeBuilder&&) = delete;
|
||||
~NodeBuilder() override;
|
||||
|
||||
Node Root();
|
||||
|
||||
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:
|
||||
detail::node& Push(anchor_t anchor);
|
||||
detail::node& Push(const Mark& mark, anchor_t anchor);
|
||||
void Push(detail::node& node);
|
||||
void Pop();
|
||||
void RegisterAnchor(anchor_t anchor, detail::node& node);
|
||||
@@ -57,14 +61,14 @@ class NodeBuilder : public EventHandler {
|
||||
detail::shared_memory_holder m_pMemory;
|
||||
detail::node* m_pRoot;
|
||||
|
||||
typedef std::vector<detail::node*> Nodes;
|
||||
using Nodes = std::vector<detail::node *>;
|
||||
Nodes m_stack;
|
||||
Nodes m_anchors;
|
||||
|
||||
typedef std::pair<detail::node*, bool> PushedKey;
|
||||
using PushedKey = std::pair<detail::node*, bool>;
|
||||
std::vector<PushedKey> m_keys;
|
||||
std::size_t m_mapDepth;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -20,7 +20,7 @@ anchor_t NodeEvents::AliasManager::LookupAnchor(
|
||||
}
|
||||
|
||||
NodeEvents::NodeEvents(const Node& node)
|
||||
: m_pMemory(node.m_pMemory), m_root(node.m_pNode) {
|
||||
: m_pMemory(node.m_pMemory), m_root(node.m_pNode), m_refCount{} {
|
||||
if (m_root)
|
||||
Setup(*m_root);
|
||||
}
|
||||
@@ -98,4 +98,4 @@ bool NodeEvents::IsAliased(const detail::node& node) const {
|
||||
RefCount::const_iterator it = m_refCount.find(node.ref());
|
||||
return it != m_refCount.end() && it->second > 1;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -26,13 +26,17 @@ class Node;
|
||||
class NodeEvents {
|
||||
public:
|
||||
explicit NodeEvents(const Node& node);
|
||||
NodeEvents(const NodeEvents&) = delete;
|
||||
NodeEvents(NodeEvents&&) = delete;
|
||||
NodeEvents& operator=(const NodeEvents&) = delete;
|
||||
NodeEvents& operator=(NodeEvents&&) = delete;
|
||||
|
||||
void Emit(EventHandler& handler);
|
||||
|
||||
private:
|
||||
class AliasManager {
|
||||
public:
|
||||
AliasManager() : m_curAnchor(0) {}
|
||||
AliasManager() : m_anchorByIdentity{}, m_curAnchor(0) {}
|
||||
|
||||
void RegisterReference(const detail::node& node);
|
||||
anchor_t LookupAnchor(const detail::node& node) const;
|
||||
@@ -41,7 +45,7 @@ class NodeEvents {
|
||||
anchor_t _CreateNewAnchor() { return ++m_curAnchor; }
|
||||
|
||||
private:
|
||||
typedef std::map<const detail::node_ref*, anchor_t> AnchorByIdentity;
|
||||
using AnchorByIdentity = std::map<const detail::node_ref*, anchor_t>;
|
||||
AnchorByIdentity m_anchorByIdentity;
|
||||
|
||||
anchor_t m_curAnchor;
|
||||
@@ -56,9 +60,9 @@ class NodeEvents {
|
||||
detail::shared_memory_holder m_pMemory;
|
||||
detail::node* m_root;
|
||||
|
||||
typedef std::map<const detail::node_ref*, int> RefCount;
|
||||
using RefCount = std::map<const detail::node_ref*, int>;
|
||||
RefCount m_refCount;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -2,4 +2,9 @@
|
||||
|
||||
namespace YAML {
|
||||
_Null Null;
|
||||
|
||||
bool IsNullString(const std::string& str) {
|
||||
return str.empty() || str == "~" || str == "null" || str == "Null" ||
|
||||
str == "NULL";
|
||||
}
|
||||
}
|
||||
|
@@ -7,16 +7,21 @@
|
||||
namespace YAML {
|
||||
ostream_wrapper::ostream_wrapper()
|
||||
: m_buffer(1, '\0'),
|
||||
m_pStream(0),
|
||||
m_pStream(nullptr),
|
||||
m_pos(0),
|
||||
m_row(0),
|
||||
m_col(0),
|
||||
m_comment(false) {}
|
||||
|
||||
ostream_wrapper::ostream_wrapper(std::ostream& stream)
|
||||
: m_pStream(&stream), m_pos(0), m_row(0), m_col(0), m_comment(false) {}
|
||||
: m_buffer{},
|
||||
m_pStream(&stream),
|
||||
m_pos(0),
|
||||
m_row(0),
|
||||
m_col(0),
|
||||
m_comment(false) {}
|
||||
|
||||
ostream_wrapper::~ostream_wrapper() {}
|
||||
ostream_wrapper::~ostream_wrapper() = default;
|
||||
|
||||
void ostream_wrapper::write(const std::string& str) {
|
||||
if (m_pStream) {
|
||||
@@ -26,8 +31,8 @@ void ostream_wrapper::write(const std::string& str) {
|
||||
std::copy(str.begin(), str.end(), m_buffer.begin() + m_pos);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
update_pos(str[i]);
|
||||
for (char ch : str) {
|
||||
update_pos(ch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +59,4 @@ void ostream_wrapper::update_pos(char ch) {
|
||||
m_comment = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -22,16 +22,18 @@ Node Load(const char* input) {
|
||||
Node Load(std::istream& input) {
|
||||
Parser parser(input);
|
||||
NodeBuilder builder;
|
||||
if (!parser.HandleNextDocument(builder))
|
||||
if (!parser.HandleNextDocument(builder)) {
|
||||
return Node();
|
||||
}
|
||||
|
||||
return builder.Root();
|
||||
}
|
||||
|
||||
Node LoadFile(const std::string& filename) {
|
||||
std::ifstream fin(filename.c_str());
|
||||
if (!fin)
|
||||
if (!fin) {
|
||||
throw BadFile();
|
||||
}
|
||||
return Load(fin);
|
||||
}
|
||||
|
||||
@@ -51,8 +53,9 @@ std::vector<Node> LoadAll(std::istream& input) {
|
||||
Parser parser(input);
|
||||
while (1) {
|
||||
NodeBuilder builder;
|
||||
if (!parser.HandleNextDocument(builder))
|
||||
if (!parser.HandleNextDocument(builder)) {
|
||||
break;
|
||||
}
|
||||
docs.push_back(builder.Root());
|
||||
}
|
||||
|
||||
@@ -61,8 +64,9 @@ std::vector<Node> LoadAll(std::istream& input) {
|
||||
|
||||
std::vector<Node> LoadAllFromFile(const std::string& filename) {
|
||||
std::ifstream fin(filename.c_str());
|
||||
if (!fin)
|
||||
if (!fin) {
|
||||
throw BadFile();
|
||||
}
|
||||
return LoadAll(fin);
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -11,14 +11,14 @@
|
||||
namespace YAML {
|
||||
class EventHandler;
|
||||
|
||||
Parser::Parser() {}
|
||||
Parser::Parser() : m_pScanner{}, m_pDirectives{} {}
|
||||
|
||||
Parser::Parser(std::istream& in) { Load(in); }
|
||||
Parser::Parser(std::istream& in) : Parser() { Load(in); }
|
||||
|
||||
Parser::~Parser() {}
|
||||
Parser::~Parser() = default;
|
||||
|
||||
Parser::operator bool() const {
|
||||
return m_pScanner.get() && !m_pScanner->empty();
|
||||
return m_pScanner && !m_pScanner->empty();
|
||||
}
|
||||
|
||||
void Parser::Load(std::istream& in) {
|
||||
@@ -26,40 +26,34 @@ void Parser::Load(std::istream& in) {
|
||||
m_pDirectives.reset(new Directives);
|
||||
}
|
||||
|
||||
// HandleNextDocument
|
||||
// . Handles the next document
|
||||
// . Throws a ParserException on error.
|
||||
// . Returns false if there are no more documents
|
||||
bool Parser::HandleNextDocument(EventHandler& eventHandler) {
|
||||
if (!m_pScanner.get())
|
||||
if (!m_pScanner)
|
||||
return false;
|
||||
|
||||
ParseDirectives();
|
||||
if (m_pScanner->empty())
|
||||
if (m_pScanner->empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SingleDocParser sdp(*m_pScanner, *m_pDirectives);
|
||||
sdp.HandleDocument(eventHandler);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ParseDirectives
|
||||
// . Reads any directives that are next in the queue.
|
||||
void Parser::ParseDirectives() {
|
||||
bool readDirective = false;
|
||||
|
||||
while (1) {
|
||||
if (m_pScanner->empty())
|
||||
break;
|
||||
|
||||
while (!m_pScanner->empty()) {
|
||||
Token& token = m_pScanner->peek();
|
||||
if (token.type != Token::DIRECTIVE)
|
||||
if (token.type != Token::DIRECTIVE) {
|
||||
break;
|
||||
}
|
||||
|
||||
// we keep the directives from the last document if none are specified;
|
||||
// but if any directives are specific, then we reset them
|
||||
if (!readDirective)
|
||||
if (!readDirective) {
|
||||
m_pDirectives.reset(new Directives);
|
||||
}
|
||||
|
||||
readDirective = true;
|
||||
HandleDirective(token);
|
||||
@@ -68,61 +62,60 @@ void Parser::ParseDirectives() {
|
||||
}
|
||||
|
||||
void Parser::HandleDirective(const Token& token) {
|
||||
if (token.value == "YAML")
|
||||
if (token.value == "YAML") {
|
||||
HandleYamlDirective(token);
|
||||
else if (token.value == "TAG")
|
||||
} else if (token.value == "TAG") {
|
||||
HandleTagDirective(token);
|
||||
}
|
||||
}
|
||||
|
||||
// HandleYamlDirective
|
||||
// . Should be of the form 'major.minor' (like a version number)
|
||||
void Parser::HandleYamlDirective(const Token& token) {
|
||||
if (token.params.size() != 1)
|
||||
if (token.params.size() != 1) {
|
||||
throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
|
||||
}
|
||||
|
||||
if (!m_pDirectives->version.isDefault)
|
||||
if (!m_pDirectives->version.isDefault) {
|
||||
throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
|
||||
}
|
||||
|
||||
std::stringstream str(token.params[0]);
|
||||
str >> m_pDirectives->version.major;
|
||||
str.get();
|
||||
str >> m_pDirectives->version.minor;
|
||||
if (!str || str.peek() != EOF)
|
||||
if (!str || str.peek() != EOF) {
|
||||
throw ParserException(
|
||||
token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]);
|
||||
}
|
||||
|
||||
if (m_pDirectives->version.major > 1)
|
||||
if (m_pDirectives->version.major > 1) {
|
||||
throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
|
||||
}
|
||||
|
||||
m_pDirectives->version.isDefault = false;
|
||||
// TODO: warning on major == 1, minor > 2?
|
||||
}
|
||||
|
||||
// HandleTagDirective
|
||||
// . Should be of the form 'handle prefix', where 'handle' is converted to
|
||||
// 'prefix' in the file.
|
||||
void Parser::HandleTagDirective(const Token& token) {
|
||||
if (token.params.size() != 2)
|
||||
throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
|
||||
|
||||
const std::string& handle = token.params[0];
|
||||
const std::string& prefix = token.params[1];
|
||||
if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end())
|
||||
if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) {
|
||||
throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
|
||||
}
|
||||
|
||||
m_pDirectives->tags[handle] = prefix;
|
||||
}
|
||||
|
||||
void Parser::PrintTokens(std::ostream& out) {
|
||||
if (!m_pScanner.get())
|
||||
if (!m_pScanner) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (m_pScanner->empty())
|
||||
break;
|
||||
|
||||
while (!m_pScanner->empty()) {
|
||||
out << m_pScanner->peek() << "\n";
|
||||
m_pScanner->pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -1,53 +0,0 @@
|
||||
#ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define PTR_STACK_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 <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
template <typename T>
|
||||
class ptr_stack : private YAML::noncopyable {
|
||||
public:
|
||||
ptr_stack() {}
|
||||
~ptr_stack() { clear(); }
|
||||
|
||||
void clear() {
|
||||
for (std::size_t i = 0; i < m_data.size(); i++)
|
||||
delete m_data[i];
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
std::size_t size() const { return m_data.size(); }
|
||||
bool empty() const { return m_data.empty(); }
|
||||
|
||||
void push(std::auto_ptr<T> t) {
|
||||
m_data.push_back(NULL);
|
||||
m_data.back() = t.release();
|
||||
}
|
||||
std::auto_ptr<T> pop() {
|
||||
std::auto_ptr<T> t(m_data.back());
|
||||
m_data.pop_back();
|
||||
return t;
|
||||
}
|
||||
T& top() { return *m_data.back(); }
|
||||
const T& top() const { return *m_data.back(); }
|
||||
|
||||
T& top(std::ptrdiff_t diff) { return **(m_data.end() - 1 + diff); }
|
||||
const T& top(std::ptrdiff_t diff) const {
|
||||
return **(m_data.end() - 1 + diff);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T*> m_data;
|
||||
};
|
||||
|
||||
#endif // PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
@@ -12,38 +12,34 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
namespace YAML {
|
||||
|
||||
// TODO: This class is no longer needed
|
||||
template <typename T>
|
||||
class ptr_vector : private YAML::noncopyable {
|
||||
class ptr_vector {
|
||||
public:
|
||||
ptr_vector() {}
|
||||
~ptr_vector() { clear(); }
|
||||
ptr_vector() : m_data{} {}
|
||||
ptr_vector(const ptr_vector&) = delete;
|
||||
ptr_vector(ptr_vector&&) = default;
|
||||
ptr_vector& operator=(const ptr_vector&) = delete;
|
||||
ptr_vector& operator=(ptr_vector&&) = default;
|
||||
|
||||
void clear() {
|
||||
for (std::size_t i = 0; i < m_data.size(); i++)
|
||||
delete m_data[i];
|
||||
m_data.clear();
|
||||
}
|
||||
void clear() { m_data.clear(); }
|
||||
|
||||
std::size_t size() const { return m_data.size(); }
|
||||
bool empty() const { return m_data.empty(); }
|
||||
|
||||
void push_back(std::auto_ptr<T> t) {
|
||||
m_data.push_back(NULL);
|
||||
m_data.back() = t.release();
|
||||
}
|
||||
void push_back(std::unique_ptr<T>&& t) { m_data.push_back(std::move(t)); }
|
||||
T& operator[](std::size_t i) { return *m_data[i]; }
|
||||
const T& operator[](std::size_t i) const { return *m_data[i]; }
|
||||
|
||||
T& back() { return *m_data.back(); }
|
||||
const T& back() const { return *m_data.back(); }
|
||||
T& back() { return *(m_data.back().get()); }
|
||||
|
||||
const T& back() const { return *(m_data.back().get()); }
|
||||
|
||||
private:
|
||||
std::vector<T*> m_data;
|
||||
std::vector<std::unique_ptr<T>> m_data;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -2,18 +2,16 @@
|
||||
|
||||
namespace YAML {
|
||||
// constructors
|
||||
RegEx::RegEx() : m_op(REGEX_EMPTY) {}
|
||||
|
||||
RegEx::RegEx(REGEX_OP op) : m_op(op) {}
|
||||
RegEx::RegEx(REGEX_OP op) : m_op(op), m_a(0), m_z(0), m_params{} {}
|
||||
RegEx::RegEx() : RegEx(REGEX_EMPTY) {}
|
||||
|
||||
RegEx::RegEx(char ch) : m_op(REGEX_MATCH), m_a(ch) {}
|
||||
RegEx::RegEx(char ch) : m_op(REGEX_MATCH), m_a(ch), m_z(0), m_params{} {}
|
||||
|
||||
RegEx::RegEx(char a, char z) : m_op(REGEX_RANGE), m_a(a), m_z(z) {}
|
||||
RegEx::RegEx(char a, char z) : m_op(REGEX_RANGE), m_a(a), m_z(z), m_params{} {}
|
||||
|
||||
RegEx::RegEx(const std::string& str, REGEX_OP op) : m_op(op) {
|
||||
for (std::size_t i = 0; i < str.size(); i++)
|
||||
m_params.push_back(RegEx(str[i]));
|
||||
}
|
||||
RegEx::RegEx(const std::string& str, REGEX_OP op)
|
||||
: m_op(op), m_a(0), m_z(0), m_params(str.begin(), str.end()) {}
|
||||
|
||||
// combination constructors
|
||||
RegEx operator!(const RegEx& ex) {
|
||||
@@ -22,14 +20,14 @@ RegEx operator!(const RegEx& ex) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
RegEx operator||(const RegEx& ex1, const RegEx& ex2) {
|
||||
RegEx operator|(const RegEx& ex1, const RegEx& ex2) {
|
||||
RegEx ret(REGEX_OR);
|
||||
ret.m_params.push_back(ex1);
|
||||
ret.m_params.push_back(ex2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
RegEx operator&&(const RegEx& ex1, const RegEx& ex2) {
|
||||
RegEx operator&(const RegEx& ex1, const RegEx& ex2) {
|
||||
RegEx ret(REGEX_AND);
|
||||
ret.m_params.push_back(ex1);
|
||||
ret.m_params.push_back(ex2);
|
||||
@@ -42,4 +40,4 @@ RegEx operator+(const RegEx& ex1, const RegEx& ex2) {
|
||||
ret.m_params.push_back(ex2);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -10,6 +10,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
class Stream;
|
||||
|
||||
@@ -26,18 +28,18 @@ enum REGEX_OP {
|
||||
// simplified regular expressions
|
||||
// . Only straightforward matches (no repeated characters)
|
||||
// . Only matches from start of string
|
||||
class RegEx {
|
||||
class YAML_CPP_API RegEx {
|
||||
public:
|
||||
RegEx();
|
||||
RegEx(char ch);
|
||||
explicit RegEx(char ch);
|
||||
RegEx(char a, char z);
|
||||
RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ);
|
||||
~RegEx() {}
|
||||
~RegEx() = default;
|
||||
|
||||
friend RegEx operator!(const RegEx& ex);
|
||||
friend RegEx operator||(const RegEx& ex1, const RegEx& ex2);
|
||||
friend RegEx operator&&(const RegEx& ex1, const RegEx& ex2);
|
||||
friend RegEx operator+(const RegEx& ex1, const RegEx& ex2);
|
||||
friend YAML_CPP_API RegEx operator!(const RegEx& ex);
|
||||
friend YAML_CPP_API RegEx operator|(const RegEx& ex1, const RegEx& ex2);
|
||||
friend YAML_CPP_API RegEx operator&(const RegEx& ex1, const RegEx& ex2);
|
||||
friend YAML_CPP_API RegEx operator+(const RegEx& ex1, const RegEx& ex2);
|
||||
|
||||
bool Matches(char ch) const;
|
||||
bool Matches(const std::string& str) const;
|
||||
@@ -51,7 +53,7 @@ class RegEx {
|
||||
int Match(const Source& source) const;
|
||||
|
||||
private:
|
||||
RegEx(REGEX_OP op);
|
||||
explicit RegEx(REGEX_OP op);
|
||||
|
||||
template <typename Source>
|
||||
bool IsValidSource(const Source& source) const;
|
||||
@@ -75,10 +77,11 @@ class RegEx {
|
||||
|
||||
private:
|
||||
REGEX_OP m_op;
|
||||
char m_a, m_z;
|
||||
char m_a{};
|
||||
char m_z{};
|
||||
std::vector<RegEx> m_params;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#include "regeximpl.h"
|
||||
|
||||
|
@@ -8,8 +8,8 @@
|
||||
#endif
|
||||
|
||||
#include "stream.h"
|
||||
#include "stringsource.h"
|
||||
#include "streamcharsource.h"
|
||||
#include "stringsource.h"
|
||||
|
||||
namespace YAML {
|
||||
// query matches
|
||||
@@ -106,9 +106,8 @@ inline int RegEx::MatchOpEmpty(const Source& source) const {
|
||||
template <>
|
||||
inline int RegEx::MatchOpEmpty<StringCharSource>(
|
||||
const StringCharSource& source) const {
|
||||
return !source
|
||||
? 0
|
||||
: -1; // the empty regex only is successful on the empty string
|
||||
return !source ? 0 : -1; // the empty regex only is successful on the empty
|
||||
// string
|
||||
}
|
||||
|
||||
// MatchOperator
|
||||
@@ -130,8 +129,8 @@ inline int RegEx::MatchOpRange(const Source& source) const {
|
||||
// OrOperator
|
||||
template <typename Source>
|
||||
inline int RegEx::MatchOpOr(const Source& source) const {
|
||||
for (std::size_t i = 0; i < m_params.size(); i++) {
|
||||
int n = m_params[i].MatchUnchecked(source);
|
||||
for (const RegEx& param : m_params) {
|
||||
int n = param.MatchUnchecked(source);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
}
|
||||
@@ -169,11 +168,11 @@ inline int RegEx::MatchOpNot(const Source& source) const {
|
||||
template <typename Source>
|
||||
inline int RegEx::MatchOpSeq(const Source& source) const {
|
||||
int offset = 0;
|
||||
for (std::size_t i = 0; i < m_params.size(); i++) {
|
||||
int n = m_params[i].Match(source + offset); // note Match, not
|
||||
// MatchUnchecked because we
|
||||
// need to check validity after
|
||||
// the offset
|
||||
for (const RegEx& param : m_params) {
|
||||
int n = param.Match(source + offset); // note Match, not
|
||||
// MatchUnchecked because we
|
||||
// need to check validity after
|
||||
// the offset
|
||||
if (n == -1)
|
||||
return -1;
|
||||
offset += n;
|
||||
@@ -181,6 +180,6 @@ inline int RegEx::MatchOpSeq(const Source& source) const {
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
185
src/scanner.cpp
185
src/scanner.cpp
@@ -9,30 +9,29 @@
|
||||
namespace YAML {
|
||||
Scanner::Scanner(std::istream& in)
|
||||
: INPUT(in),
|
||||
m_tokens{},
|
||||
m_startedStream(false),
|
||||
m_endedStream(false),
|
||||
m_simpleKeyAllowed(false),
|
||||
m_canBeJSONFlow(false) {}
|
||||
m_canBeJSONFlow(false),
|
||||
m_simpleKeys{},
|
||||
m_indents{},
|
||||
m_indentRefs{},
|
||||
m_flows{} {}
|
||||
|
||||
Scanner::~Scanner() {}
|
||||
Scanner::~Scanner() = default;
|
||||
|
||||
// empty
|
||||
// . Returns true if there are no more tokens to be read
|
||||
bool Scanner::empty() {
|
||||
EnsureTokensInQueue();
|
||||
return m_tokens.empty();
|
||||
}
|
||||
|
||||
// pop
|
||||
// . Simply removes the next token on the queue.
|
||||
void Scanner::pop() {
|
||||
EnsureTokensInQueue();
|
||||
if (!m_tokens.empty())
|
||||
m_tokens.pop();
|
||||
}
|
||||
|
||||
// peek
|
||||
// . Returns (but does not remove) the next token on the queue.
|
||||
Token& Scanner::peek() {
|
||||
EnsureTokensInQueue();
|
||||
assert(!m_tokens.empty()); // should we be asserting here? I mean, we really
|
||||
@@ -49,21 +48,17 @@ Token& Scanner::peek() {
|
||||
return m_tokens.front();
|
||||
}
|
||||
|
||||
// mark
|
||||
// . Returns the current mark in the stream
|
||||
Mark Scanner::mark() const { return INPUT.mark(); }
|
||||
|
||||
// EnsureTokensInQueue
|
||||
// . Scan until there's a valid token at the front of the queue,
|
||||
// or we're sure the queue is empty.
|
||||
void Scanner::EnsureTokensInQueue() {
|
||||
while (1) {
|
||||
if (!m_tokens.empty()) {
|
||||
Token& token = m_tokens.front();
|
||||
|
||||
// if this guy's valid, then we're done
|
||||
if (token.status == Token::VALID)
|
||||
if (token.status == Token::VALID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// here's where we clean up the impossible tokens
|
||||
if (token.status == Token::INVALID) {
|
||||
@@ -75,23 +70,23 @@ void Scanner::EnsureTokensInQueue() {
|
||||
}
|
||||
|
||||
// no token? maybe we've actually finished
|
||||
if (m_endedStream)
|
||||
if (m_endedStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
// no? then scan...
|
||||
ScanNextToken();
|
||||
}
|
||||
}
|
||||
|
||||
// ScanNextToken
|
||||
// . The main scanning function; here we branch out and
|
||||
// scan whatever the next token should be.
|
||||
void Scanner::ScanNextToken() {
|
||||
if (m_endedStream)
|
||||
if (m_endedStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_startedStream)
|
||||
if (!m_startedStream) {
|
||||
return StartStream();
|
||||
}
|
||||
|
||||
// get rid of whitespace, etc. (in between tokens it should be irrelevent)
|
||||
ScanToNextToken();
|
||||
@@ -104,85 +99,102 @@ void Scanner::ScanNextToken() {
|
||||
// *****
|
||||
|
||||
// end of stream
|
||||
if (!INPUT)
|
||||
if (!INPUT) {
|
||||
return EndStream();
|
||||
}
|
||||
|
||||
if (INPUT.column() == 0 && INPUT.peek() == Keys::Directive)
|
||||
if (INPUT.column() == 0 && INPUT.peek() == Keys::Directive) {
|
||||
return ScanDirective();
|
||||
}
|
||||
|
||||
// document token
|
||||
if (INPUT.column() == 0 && Exp::DocStart().Matches(INPUT))
|
||||
if (INPUT.column() == 0 && Exp::DocStart().Matches(INPUT)) {
|
||||
return ScanDocStart();
|
||||
}
|
||||
|
||||
if (INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT))
|
||||
if (INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT)) {
|
||||
return ScanDocEnd();
|
||||
}
|
||||
|
||||
// flow start/end/entry
|
||||
if (INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart)
|
||||
if (INPUT.peek() == Keys::FlowSeqStart ||
|
||||
INPUT.peek() == Keys::FlowMapStart) {
|
||||
return ScanFlowStart();
|
||||
}
|
||||
|
||||
if (INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd)
|
||||
if (INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) {
|
||||
return ScanFlowEnd();
|
||||
}
|
||||
|
||||
if (INPUT.peek() == Keys::FlowEntry)
|
||||
if (INPUT.peek() == Keys::FlowEntry) {
|
||||
return ScanFlowEntry();
|
||||
}
|
||||
|
||||
// block/map stuff
|
||||
if (Exp::BlockEntry().Matches(INPUT))
|
||||
if (Exp::BlockEntry().Matches(INPUT)) {
|
||||
return ScanBlockEntry();
|
||||
}
|
||||
|
||||
if ((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT))
|
||||
if ((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT)) {
|
||||
return ScanKey();
|
||||
}
|
||||
|
||||
if (GetValueRegex().Matches(INPUT))
|
||||
if (GetValueRegex().Matches(INPUT)) {
|
||||
return ScanValue();
|
||||
}
|
||||
|
||||
// alias/anchor
|
||||
if (INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor)
|
||||
if (INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) {
|
||||
return ScanAnchorOrAlias();
|
||||
}
|
||||
|
||||
// tag
|
||||
if (INPUT.peek() == Keys::Tag)
|
||||
if (INPUT.peek() == Keys::Tag) {
|
||||
return ScanTag();
|
||||
}
|
||||
|
||||
// special scalars
|
||||
if (InBlockContext() && (INPUT.peek() == Keys::LiteralScalar ||
|
||||
INPUT.peek() == Keys::FoldedScalar))
|
||||
INPUT.peek() == Keys::FoldedScalar)) {
|
||||
return ScanBlockScalar();
|
||||
}
|
||||
|
||||
if (INPUT.peek() == '\'' || INPUT.peek() == '\"')
|
||||
if (INPUT.peek() == '\'' || INPUT.peek() == '\"') {
|
||||
return ScanQuotedScalar();
|
||||
}
|
||||
|
||||
// plain scalars
|
||||
if ((InBlockContext() ? Exp::PlainScalar() : Exp::PlainScalarInFlow())
|
||||
.Matches(INPUT))
|
||||
.Matches(INPUT)) {
|
||||
return ScanPlainScalar();
|
||||
}
|
||||
|
||||
// don't know what it is!
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::UNKNOWN_TOKEN);
|
||||
}
|
||||
|
||||
// ScanToNextToken
|
||||
// . Eats input until we reach the next token-like thing.
|
||||
void Scanner::ScanToNextToken() {
|
||||
while (1) {
|
||||
// first eat whitespace
|
||||
while (INPUT && IsWhitespaceToBeEaten(INPUT.peek())) {
|
||||
if (InBlockContext() && Exp::Tab().Matches(INPUT))
|
||||
if (InBlockContext() && Exp::Tab().Matches(INPUT)) {
|
||||
m_simpleKeyAllowed = false;
|
||||
}
|
||||
INPUT.eat(1);
|
||||
}
|
||||
|
||||
// then eat a comment
|
||||
if (Exp::Comment().Matches(INPUT)) {
|
||||
// eat until line break
|
||||
while (INPUT && !Exp::Break().Matches(INPUT))
|
||||
while (INPUT && !Exp::Break().Matches(INPUT)) {
|
||||
INPUT.eat(1);
|
||||
}
|
||||
}
|
||||
|
||||
// if it's NOT a line break, then we're done!
|
||||
if (!Exp::Break().Matches(INPUT))
|
||||
if (!Exp::Break().Matches(INPUT)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise, let's eat the line break and keep going
|
||||
int n = Exp::Break().Match(INPUT);
|
||||
@@ -192,8 +204,9 @@ void Scanner::ScanToNextToken() {
|
||||
InvalidateSimpleKey();
|
||||
|
||||
// new line - we may be able to accept a simple key now
|
||||
if (InBlockContext())
|
||||
if (InBlockContext()) {
|
||||
m_simpleKeyAllowed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,40 +223,39 @@ void Scanner::ScanToNextToken() {
|
||||
// that they can't contribute to indentation, so once you've seen a tab in a
|
||||
// line, you can't start a simple key
|
||||
bool Scanner::IsWhitespaceToBeEaten(char ch) {
|
||||
if (ch == ' ')
|
||||
if (ch == ' ') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ch == '\t')
|
||||
if (ch == '\t') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetValueRegex
|
||||
// . Get the appropriate regex to check if it's a value token
|
||||
const RegEx& Scanner::GetValueRegex() const {
|
||||
if (InBlockContext())
|
||||
if (InBlockContext()) {
|
||||
return Exp::Value();
|
||||
}
|
||||
|
||||
return m_canBeJSONFlow ? Exp::ValueInJSONFlow() : Exp::ValueInFlow();
|
||||
}
|
||||
|
||||
// StartStream
|
||||
// . Set the initial conditions for starting a stream.
|
||||
void Scanner::StartStream() {
|
||||
m_startedStream = true;
|
||||
m_simpleKeyAllowed = true;
|
||||
std::auto_ptr<IndentMarker> pIndent(new IndentMarker(-1, IndentMarker::NONE));
|
||||
m_indentRefs.push_back(pIndent);
|
||||
std::unique_ptr<IndentMarker> pIndent(
|
||||
new IndentMarker(-1, IndentMarker::NONE));
|
||||
m_indentRefs.push_back(std::move(pIndent));
|
||||
m_indents.push(&m_indentRefs.back());
|
||||
}
|
||||
|
||||
// EndStream
|
||||
// . Close out the stream, finish up, etc.
|
||||
void Scanner::EndStream() {
|
||||
// force newline
|
||||
if (INPUT.column() > 0)
|
||||
if (INPUT.column() > 0) {
|
||||
INPUT.ResetColumn();
|
||||
}
|
||||
|
||||
PopAllIndents();
|
||||
PopAllSimpleKeys();
|
||||
@@ -271,84 +283,80 @@ Token::TYPE Scanner::GetStartTokenFor(IndentMarker::INDENT_TYPE type) const {
|
||||
throw std::runtime_error("yaml-cpp: internal error, invalid indent type");
|
||||
}
|
||||
|
||||
// PushIndentTo
|
||||
// . Pushes an indentation onto the stack, and enqueues the
|
||||
// proper token (sequence start or mapping start).
|
||||
// . Returns the indent marker it generates (if any).
|
||||
Scanner::IndentMarker* Scanner::PushIndentTo(int column,
|
||||
IndentMarker::INDENT_TYPE type) {
|
||||
// are we in flow?
|
||||
if (InFlowContext())
|
||||
return 0;
|
||||
if (InFlowContext()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::auto_ptr<IndentMarker> pIndent(new IndentMarker(column, type));
|
||||
std::unique_ptr<IndentMarker> pIndent(new IndentMarker(column, type));
|
||||
IndentMarker& indent = *pIndent;
|
||||
const IndentMarker& lastIndent = *m_indents.top();
|
||||
|
||||
// is this actually an indentation?
|
||||
if (indent.column < lastIndent.column)
|
||||
return 0;
|
||||
if (indent.column < lastIndent.column) {
|
||||
return nullptr;
|
||||
}
|
||||
if (indent.column == lastIndent.column &&
|
||||
!(indent.type == IndentMarker::SEQ &&
|
||||
lastIndent.type == IndentMarker::MAP))
|
||||
return 0;
|
||||
lastIndent.type == IndentMarker::MAP)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// push a start token
|
||||
indent.pStartToken = PushToken(GetStartTokenFor(type));
|
||||
|
||||
// and then the indent
|
||||
m_indents.push(&indent);
|
||||
m_indentRefs.push_back(pIndent);
|
||||
m_indentRefs.push_back(std::move(pIndent));
|
||||
return &m_indentRefs.back();
|
||||
}
|
||||
|
||||
// PopIndentToHere
|
||||
// . Pops indentations off the stack until we reach the current indentation
|
||||
// level,
|
||||
// and enqueues the proper token each time.
|
||||
// . Then pops all invalid indentations off.
|
||||
void Scanner::PopIndentToHere() {
|
||||
// are we in flow?
|
||||
if (InFlowContext())
|
||||
if (InFlowContext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// now pop away
|
||||
while (!m_indents.empty()) {
|
||||
const IndentMarker& indent = *m_indents.top();
|
||||
if (indent.column < INPUT.column())
|
||||
if (indent.column < INPUT.column()) {
|
||||
break;
|
||||
}
|
||||
if (indent.column == INPUT.column() &&
|
||||
!(indent.type == IndentMarker::SEQ &&
|
||||
!Exp::BlockEntry().Matches(INPUT)))
|
||||
!Exp::BlockEntry().Matches(INPUT))) {
|
||||
break;
|
||||
}
|
||||
|
||||
PopIndent();
|
||||
}
|
||||
|
||||
while (!m_indents.empty() && m_indents.top()->status == IndentMarker::INVALID)
|
||||
while (!m_indents.empty() &&
|
||||
m_indents.top()->status == IndentMarker::INVALID) {
|
||||
PopIndent();
|
||||
}
|
||||
}
|
||||
|
||||
// PopAllIndents
|
||||
// . Pops all indentations (except for the base empty one) off the stack,
|
||||
// and enqueues the proper token each time.
|
||||
void Scanner::PopAllIndents() {
|
||||
// are we in flow?
|
||||
if (InFlowContext())
|
||||
if (InFlowContext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// now pop away
|
||||
while (!m_indents.empty()) {
|
||||
const IndentMarker& indent = *m_indents.top();
|
||||
if (indent.type == IndentMarker::NONE)
|
||||
if (indent.type == IndentMarker::NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
PopIndent();
|
||||
}
|
||||
}
|
||||
|
||||
// PopIndent
|
||||
// . Pops a single indent, pushing the proper token
|
||||
void Scanner::PopIndent() {
|
||||
const IndentMarker& indent = *m_indents.top();
|
||||
m_indents.pop();
|
||||
@@ -358,23 +366,20 @@ void Scanner::PopIndent() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (indent.type == IndentMarker::SEQ)
|
||||
if (indent.type == IndentMarker::SEQ) {
|
||||
m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark()));
|
||||
else if (indent.type == IndentMarker::MAP)
|
||||
} else if (indent.type == IndentMarker::MAP) {
|
||||
m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark()));
|
||||
}
|
||||
}
|
||||
|
||||
// GetTopIndent
|
||||
int Scanner::GetTopIndent() const {
|
||||
if (m_indents.empty())
|
||||
if (m_indents.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_indents.top()->column;
|
||||
}
|
||||
|
||||
// ThrowParserException
|
||||
// . Throws a ParserException with the current token location
|
||||
// (if available).
|
||||
// . Does not parse any more tokens.
|
||||
void Scanner::ThrowParserException(const std::string& msg) const {
|
||||
Mark mark = Mark::null_mark();
|
||||
if (!m_tokens.empty()) {
|
||||
@@ -383,4 +388,4 @@ void Scanner::ThrowParserException(const std::string& msg) const {
|
||||
}
|
||||
throw ParserException(mark, msg);
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -24,15 +24,24 @@ namespace YAML {
|
||||
class Node;
|
||||
class RegEx;
|
||||
|
||||
/**
|
||||
* A scanner transforms a stream of characters into a stream of tokens.
|
||||
*/
|
||||
class Scanner {
|
||||
public:
|
||||
Scanner(std::istream &in);
|
||||
explicit Scanner(std::istream &in);
|
||||
~Scanner();
|
||||
|
||||
// token queue management (hopefully this looks kinda stl-ish)
|
||||
/** Returns true if there are no more tokens to be read. */
|
||||
bool empty();
|
||||
|
||||
/** Removes the next token in the queue. */
|
||||
void pop();
|
||||
|
||||
/** Returns, but does not remove, the next token in the queue. */
|
||||
Token &peek();
|
||||
|
||||
/** Returns the current mark in the input stream. */
|
||||
Mark mark() const;
|
||||
|
||||
private:
|
||||
@@ -40,7 +49,7 @@ class Scanner {
|
||||
enum INDENT_TYPE { MAP, SEQ, NONE };
|
||||
enum STATUS { VALID, INVALID, UNKNOWN };
|
||||
IndentMarker(int column_, INDENT_TYPE type_)
|
||||
: column(column_), type(type_), status(VALID), pStartToken(0) {}
|
||||
: column(column_), type(type_), status(VALID), pStartToken(nullptr) {}
|
||||
|
||||
int column;
|
||||
INDENT_TYPE type;
|
||||
@@ -52,11 +61,29 @@ class Scanner {
|
||||
|
||||
private:
|
||||
// scanning
|
||||
|
||||
/**
|
||||
* Scans until there's a valid token at the front of the queue, or the queue
|
||||
* is empty. The state can be checked by {@link #empty}, and the next token
|
||||
* retrieved by {@link #peek}.
|
||||
*/
|
||||
void EnsureTokensInQueue();
|
||||
|
||||
/**
|
||||
* The main scanning function; this method branches out to scan whatever the
|
||||
* next token should be.
|
||||
*/
|
||||
void ScanNextToken();
|
||||
|
||||
/** Eats the input stream until it reaches the next token-like thing. */
|
||||
void ScanToNextToken();
|
||||
|
||||
/** Sets the initial conditions for starting a stream. */
|
||||
void StartStream();
|
||||
|
||||
/** Closes out the stream, finish up, etc. */
|
||||
void EndStream();
|
||||
|
||||
Token *PushToken(Token::TYPE type);
|
||||
|
||||
bool InFlowContext() const { return !m_flows.empty(); }
|
||||
@@ -64,9 +91,29 @@ class Scanner {
|
||||
std::size_t GetFlowLevel() const { return m_flows.size(); }
|
||||
|
||||
Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const;
|
||||
|
||||
/**
|
||||
* Pushes an indentation onto the stack, and enqueues the proper token
|
||||
* (sequence start or mapping start).
|
||||
*
|
||||
* @return the indent marker it generates (if any).
|
||||
*/
|
||||
IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type);
|
||||
|
||||
/**
|
||||
* Pops indentations off the stack until it reaches the current indentation
|
||||
* level, and enqueues the proper token each time. Then pops all invalid
|
||||
* indentations off.
|
||||
*/
|
||||
void PopIndentToHere();
|
||||
|
||||
/**
|
||||
* Pops all indentations (except for the base empty one) off the stack, and
|
||||
* enqueues the proper token each time.
|
||||
*/
|
||||
void PopAllIndents();
|
||||
|
||||
/** Pops a single indent, pushing the proper token. */
|
||||
void PopIndent();
|
||||
int GetTopIndent() const;
|
||||
|
||||
@@ -78,9 +125,17 @@ class Scanner {
|
||||
bool VerifySimpleKey();
|
||||
void PopAllSimpleKeys();
|
||||
|
||||
/**
|
||||
* Throws a ParserException with the current token location (if available),
|
||||
* and does not parse any more tokens.
|
||||
*/
|
||||
void ThrowParserException(const std::string &msg) const;
|
||||
|
||||
bool IsWhitespaceToBeEaten(char ch);
|
||||
|
||||
/**
|
||||
* Returns the appropriate regex to check if the next token is a value token.
|
||||
*/
|
||||
const RegEx &GetValueRegex() const;
|
||||
|
||||
struct SimpleKey {
|
||||
|
@@ -28,22 +28,28 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
|
||||
std::string scalar;
|
||||
params.leadingSpaces = false;
|
||||
|
||||
if (!params.end) {
|
||||
params.end = &Exp::Empty();
|
||||
}
|
||||
|
||||
while (INPUT) {
|
||||
// ********************************
|
||||
// Phase #1: scan until line ending
|
||||
|
||||
std::size_t lastNonWhitespaceChar = scalar.size();
|
||||
bool escapedNewline = false;
|
||||
while (!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
|
||||
if (!INPUT)
|
||||
while (!params.end->Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
|
||||
if (!INPUT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// document indicator?
|
||||
if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
|
||||
if (params.onDocIndicator == BREAK)
|
||||
if (params.onDocIndicator == BREAK) {
|
||||
break;
|
||||
else if (params.onDocIndicator == THROW)
|
||||
} else if (params.onDocIndicator == THROW) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
|
||||
}
|
||||
}
|
||||
|
||||
foundNonEmptyLine = true;
|
||||
@@ -70,27 +76,31 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
|
||||
// otherwise, just add the damn character
|
||||
char ch = INPUT.get();
|
||||
scalar += ch;
|
||||
if (ch != ' ' && ch != '\t')
|
||||
if (ch != ' ' && ch != '\t') {
|
||||
lastNonWhitespaceChar = scalar.size();
|
||||
}
|
||||
}
|
||||
|
||||
// eof? if we're looking to eat something, then we throw
|
||||
if (!INPUT) {
|
||||
if (params.eatEnd)
|
||||
if (params.eatEnd) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// doc indicator?
|
||||
if (params.onDocIndicator == BREAK && INPUT.column() == 0 &&
|
||||
Exp::DocIndicator().Matches(INPUT))
|
||||
Exp::DocIndicator().Matches(INPUT)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// are we done via character match?
|
||||
int n = params.end.Match(INPUT);
|
||||
int n = params.end->Match(INPUT);
|
||||
if (n >= 0) {
|
||||
if (params.eatEnd)
|
||||
if (params.eatEnd) {
|
||||
INPUT.eat(n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -107,23 +117,33 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
|
||||
// Phase #3: scan initial spaces
|
||||
|
||||
// first the required indentation
|
||||
while (INPUT.peek() == ' ' && (INPUT.column() < params.indent ||
|
||||
(params.detectIndent && !foundNonEmptyLine)))
|
||||
while (INPUT.peek() == ' ' &&
|
||||
(INPUT.column() < params.indent ||
|
||||
(params.detectIndent && !foundNonEmptyLine)) &&
|
||||
!params.end->Matches(INPUT)) {
|
||||
INPUT.eat(1);
|
||||
}
|
||||
|
||||
// update indent if we're auto-detecting
|
||||
if (params.detectIndent && !foundNonEmptyLine)
|
||||
if (params.detectIndent && !foundNonEmptyLine) {
|
||||
params.indent = std::max(params.indent, INPUT.column());
|
||||
}
|
||||
|
||||
// and then the rest of the whitespace
|
||||
while (Exp::Blank().Matches(INPUT)) {
|
||||
// we check for tabs that masquerade as indentation
|
||||
if (INPUT.peek() == '\t' && INPUT.column() < params.indent &&
|
||||
params.onTabInIndentation == THROW)
|
||||
params.onTabInIndentation == THROW) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
|
||||
}
|
||||
|
||||
if (!params.eatLeadingWhitespace)
|
||||
if (!params.eatLeadingWhitespace) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (params.end->Matches(INPUT)) {
|
||||
break;
|
||||
}
|
||||
|
||||
INPUT.eat(1);
|
||||
}
|
||||
@@ -143,26 +163,29 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
|
||||
break;
|
||||
case FOLD_BLOCK:
|
||||
if (!emptyLine && !nextEmptyLine && !moreIndented &&
|
||||
!nextMoreIndented && INPUT.column() >= params.indent)
|
||||
!nextMoreIndented && INPUT.column() >= params.indent) {
|
||||
scalar += " ";
|
||||
else if (nextEmptyLine)
|
||||
} else if (nextEmptyLine) {
|
||||
foldedNewlineCount++;
|
||||
else
|
||||
} else {
|
||||
scalar += "\n";
|
||||
}
|
||||
|
||||
if (!nextEmptyLine && foldedNewlineCount > 0) {
|
||||
scalar += std::string(foldedNewlineCount - 1, '\n');
|
||||
if (foldedNewlineStartedMoreIndented ||
|
||||
nextMoreIndented | !foundNonEmptyLine)
|
||||
nextMoreIndented | !foundNonEmptyLine) {
|
||||
scalar += "\n";
|
||||
}
|
||||
foldedNewlineCount = 0;
|
||||
}
|
||||
break;
|
||||
case FOLD_FLOW:
|
||||
if (nextEmptyLine)
|
||||
if (nextEmptyLine) {
|
||||
scalar += "\n";
|
||||
else if (!emptyLine && !nextEmptyLine && !escapedNewline)
|
||||
} else if (!emptyLine && !escapedNewline) {
|
||||
scalar += " ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -182,35 +205,41 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
|
||||
if (params.trimTrailingSpaces) {
|
||||
std::size_t pos = scalar.find_last_not_of(' ');
|
||||
if (lastEscapedChar != std::string::npos) {
|
||||
if (pos < lastEscapedChar || pos == std::string::npos)
|
||||
if (pos < lastEscapedChar || pos == std::string::npos) {
|
||||
pos = lastEscapedChar;
|
||||
}
|
||||
}
|
||||
if (pos < scalar.size())
|
||||
if (pos < scalar.size()) {
|
||||
scalar.erase(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
switch (params.chomp) {
|
||||
case CLIP: {
|
||||
std::size_t pos = scalar.find_last_not_of('\n');
|
||||
if (lastEscapedChar != std::string::npos) {
|
||||
if (pos < lastEscapedChar || pos == std::string::npos)
|
||||
if (pos < lastEscapedChar || pos == std::string::npos) {
|
||||
pos = lastEscapedChar;
|
||||
}
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
if (pos == std::string::npos) {
|
||||
scalar.erase();
|
||||
else if (pos + 1 < scalar.size())
|
||||
} else if (pos + 1 < scalar.size()) {
|
||||
scalar.erase(pos + 2);
|
||||
}
|
||||
} break;
|
||||
case STRIP: {
|
||||
std::size_t pos = scalar.find_last_not_of('\n');
|
||||
if (lastEscapedChar != std::string::npos) {
|
||||
if (pos < lastEscapedChar || pos == std::string::npos)
|
||||
if (pos < lastEscapedChar || pos == std::string::npos) {
|
||||
pos = lastEscapedChar;
|
||||
}
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
if (pos == std::string::npos) {
|
||||
scalar.erase();
|
||||
else if (pos < scalar.size())
|
||||
} else if (pos < scalar.size()) {
|
||||
scalar.erase(pos + 1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
|
@@ -19,7 +19,8 @@ enum FOLD { DONT_FOLD, FOLD_BLOCK, FOLD_FLOW };
|
||||
|
||||
struct ScanScalarParams {
|
||||
ScanScalarParams()
|
||||
: eatEnd(false),
|
||||
: end(nullptr),
|
||||
eatEnd(false),
|
||||
indent(0),
|
||||
detectIndent(false),
|
||||
eatLeadingWhitespace(0),
|
||||
@@ -32,7 +33,8 @@ struct ScanScalarParams {
|
||||
leadingSpaces(false) {}
|
||||
|
||||
// input:
|
||||
RegEx end; // what condition ends this scalar?
|
||||
const RegEx* end; // what condition ends this scalar?
|
||||
// unowned.
|
||||
bool eatEnd; // should we eat that condition when we see it?
|
||||
int indent; // what level of indentation should be eaten and ignored?
|
||||
bool detectIndent; // should we try to autodetect the indent?
|
||||
|
@@ -297,8 +297,8 @@ void Scanner::ScanPlainScalar() {
|
||||
|
||||
// set up the scanning parameters
|
||||
ScanScalarParams params;
|
||||
params.end = (InFlowContext() ? Exp::EndScalarInFlow() : Exp::EndScalar()) ||
|
||||
(Exp::BlankOrBreak() + Exp::Comment());
|
||||
params.end =
|
||||
(InFlowContext() ? &Exp::ScanScalarEndInFlow() : &Exp::ScanScalarEnd());
|
||||
params.eatEnd = false;
|
||||
params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1);
|
||||
params.fold = FOLD_FLOW;
|
||||
@@ -338,7 +338,8 @@ void Scanner::ScanQuotedScalar() {
|
||||
|
||||
// setup the scanning parameters
|
||||
ScanScalarParams params;
|
||||
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote() : RegEx(quote));
|
||||
RegEx end = (single ? RegEx(quote) & !Exp::EscSingleQuote() : RegEx(quote));
|
||||
params.end = &end;
|
||||
params.eatEnd = true;
|
||||
params.escape = (single ? '\'' : '\\');
|
||||
params.indent = 0;
|
||||
@@ -433,4 +434,4 @@ void Scanner::ScanBlockScalar() {
|
||||
token.value = scalar;
|
||||
m_tokens.push(token);
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -7,41 +7,46 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/noexcept.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
namespace YAML {
|
||||
class SettingChangeBase;
|
||||
|
||||
class SettingChangeBase {
|
||||
public:
|
||||
virtual ~SettingChangeBase() = default;
|
||||
virtual void pop() = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Setting {
|
||||
public:
|
||||
Setting() : m_value() {}
|
||||
Setting(const T& value) : m_value() { set(value); }
|
||||
|
||||
const T get() const { return m_value; }
|
||||
std::auto_ptr<SettingChangeBase> set(const T& value);
|
||||
std::unique_ptr<SettingChangeBase> set(const T& value);
|
||||
void restore(const Setting<T>& oldSetting) { m_value = oldSetting.get(); }
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
class SettingChangeBase {
|
||||
public:
|
||||
virtual ~SettingChangeBase() {}
|
||||
virtual void pop() = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SettingChange : public SettingChangeBase {
|
||||
public:
|
||||
SettingChange(Setting<T>* pSetting) : m_pCurSetting(pSetting) {
|
||||
// copy old setting to save its state
|
||||
m_oldSetting = *pSetting;
|
||||
}
|
||||
SettingChange(Setting<T>* pSetting)
|
||||
: m_pCurSetting(pSetting),
|
||||
m_oldSetting(*pSetting) // copy old setting to save its state
|
||||
{}
|
||||
SettingChange(const SettingChange&) = delete;
|
||||
SettingChange(SettingChange&&) = delete;
|
||||
SettingChange& operator=(const SettingChange&) = delete;
|
||||
SettingChange& operator=(SettingChange&&) = delete;
|
||||
|
||||
virtual void pop() { m_pCurSetting->restore(m_oldSetting); }
|
||||
void pop() override { m_pCurSetting->restore(m_oldSetting); }
|
||||
|
||||
private:
|
||||
Setting<T>* m_pCurSetting;
|
||||
@@ -49,51 +54,48 @@ class SettingChange : public SettingChangeBase {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline std::auto_ptr<SettingChangeBase> Setting<T>::set(const T& value) {
|
||||
std::auto_ptr<SettingChangeBase> pChange(new SettingChange<T>(this));
|
||||
inline std::unique_ptr<SettingChangeBase> Setting<T>::set(const T& value) {
|
||||
std::unique_ptr<SettingChangeBase> pChange(new SettingChange<T>(this));
|
||||
m_value = value;
|
||||
return pChange;
|
||||
}
|
||||
|
||||
class SettingChanges : private noncopyable {
|
||||
class SettingChanges {
|
||||
public:
|
||||
SettingChanges() {}
|
||||
SettingChanges() : m_settingChanges{} {}
|
||||
SettingChanges(const SettingChanges&) = delete;
|
||||
SettingChanges(SettingChanges&&) YAML_CPP_NOEXCEPT = default;
|
||||
SettingChanges& operator=(const SettingChanges&) = delete;
|
||||
SettingChanges& operator=(SettingChanges&& rhs) YAML_CPP_NOEXCEPT {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
clear();
|
||||
std::swap(m_settingChanges, rhs.m_settingChanges);
|
||||
|
||||
return *this;
|
||||
}
|
||||
~SettingChanges() { clear(); }
|
||||
|
||||
void clear() {
|
||||
void clear() YAML_CPP_NOEXCEPT {
|
||||
restore();
|
||||
|
||||
for (setting_changes::const_iterator it = m_settingChanges.begin();
|
||||
it != m_settingChanges.end(); ++it)
|
||||
delete *it;
|
||||
m_settingChanges.clear();
|
||||
}
|
||||
|
||||
void restore() {
|
||||
void restore() YAML_CPP_NOEXCEPT {
|
||||
for (setting_changes::const_iterator it = m_settingChanges.begin();
|
||||
it != m_settingChanges.end(); ++it)
|
||||
(*it)->pop();
|
||||
}
|
||||
|
||||
void push(std::auto_ptr<SettingChangeBase> pSettingChange) {
|
||||
m_settingChanges.push_back(pSettingChange.release());
|
||||
}
|
||||
|
||||
// like std::auto_ptr - assignment is transfer of ownership
|
||||
SettingChanges& operator=(SettingChanges& rhs) {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
clear();
|
||||
m_settingChanges = rhs.m_settingChanges;
|
||||
rhs.m_settingChanges.clear();
|
||||
return *this;
|
||||
void push(std::unique_ptr<SettingChangeBase> pSettingChange) {
|
||||
m_settingChanges.push_back(std::move(pSettingChange));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<SettingChangeBase*> setting_changes;
|
||||
using setting_changes = std::vector<std::unique_ptr<SettingChangeBase>>;
|
||||
setting_changes m_settingChanges;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -5,7 +5,7 @@ namespace YAML {
|
||||
struct Mark;
|
||||
|
||||
Scanner::SimpleKey::SimpleKey(const Mark& mark_, std::size_t flowLevel_)
|
||||
: mark(mark_), flowLevel(flowLevel_), pIndent(0), pMapStart(0), pKey(0) {}
|
||||
: mark(mark_), flowLevel(flowLevel_), pIndent(nullptr), pMapStart(nullptr), pKey(nullptr) {}
|
||||
|
||||
void Scanner::SimpleKey::Validate() {
|
||||
// Note: pIndent will *not* be garbage here;
|
||||
|
@@ -11,15 +11,17 @@
|
||||
#include "yaml-cpp/eventhandler.h"
|
||||
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
|
||||
namespace YAML {
|
||||
SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives)
|
||||
: m_scanner(scanner),
|
||||
m_directives(directives),
|
||||
m_pCollectionStack(new CollectionStack),
|
||||
m_anchors{},
|
||||
m_curAnchor(0) {}
|
||||
|
||||
SingleDocParser::~SingleDocParser() {}
|
||||
SingleDocParser::~SingleDocParser() = default;
|
||||
|
||||
// HandleDocument
|
||||
// . Handles the next document
|
||||
@@ -70,12 +72,22 @@ void SingleDocParser::HandleNode(EventHandler& eventHandler) {
|
||||
}
|
||||
|
||||
std::string tag;
|
||||
std::string anchor_name;
|
||||
anchor_t anchor;
|
||||
ParseProperties(tag, anchor);
|
||||
ParseProperties(tag, anchor, anchor_name);
|
||||
|
||||
if (!anchor_name.empty())
|
||||
eventHandler.OnAnchor(mark, anchor_name);
|
||||
|
||||
// after parsing properties, an empty node is again a possibility
|
||||
if (m_scanner.empty()) {
|
||||
eventHandler.OnNull(mark, anchor);
|
||||
return;
|
||||
}
|
||||
|
||||
const Token& token = m_scanner.peek();
|
||||
|
||||
if (token.type == Token::PLAIN_SCALAR && token.value == "null") {
|
||||
if (token.type == Token::PLAIN_SCALAR && IsNullString(token.value)) {
|
||||
eventHandler.OnNull(mark, anchor);
|
||||
m_scanner.pop();
|
||||
return;
|
||||
@@ -165,10 +177,10 @@ void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler) {
|
||||
|
||||
// check for null
|
||||
if (!m_scanner.empty()) {
|
||||
const Token& token = m_scanner.peek();
|
||||
if (token.type == Token::BLOCK_ENTRY ||
|
||||
token.type == Token::BLOCK_SEQ_END) {
|
||||
eventHandler.OnNull(token.mark, NullAnchor);
|
||||
const Token& nextToken = m_scanner.peek();
|
||||
if (nextToken.type == Token::BLOCK_ENTRY ||
|
||||
nextToken.type == Token::BLOCK_SEQ_END) {
|
||||
eventHandler.OnNull(nextToken.mark, NullAnchor);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -355,8 +367,10 @@ void SingleDocParser::HandleCompactMapWithNoKey(EventHandler& eventHandler) {
|
||||
|
||||
// ParseProperties
|
||||
// . Grabs any tag or anchor tokens and deals with them.
|
||||
void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor) {
|
||||
void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor,
|
||||
std::string& anchor_name) {
|
||||
tag.clear();
|
||||
anchor_name.clear();
|
||||
anchor = NullAnchor;
|
||||
|
||||
while (1) {
|
||||
@@ -368,7 +382,7 @@ void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor) {
|
||||
ParseTag(tag);
|
||||
break;
|
||||
case Token::ANCHOR:
|
||||
ParseAnchor(anchor);
|
||||
ParseAnchor(anchor, anchor_name);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -386,11 +400,12 @@ void SingleDocParser::ParseTag(std::string& tag) {
|
||||
m_scanner.pop();
|
||||
}
|
||||
|
||||
void SingleDocParser::ParseAnchor(anchor_t& anchor) {
|
||||
void SingleDocParser::ParseAnchor(anchor_t& anchor, std::string& anchor_name) {
|
||||
Token& token = m_scanner.peek();
|
||||
if (anchor)
|
||||
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
|
||||
|
||||
anchor_name = token.value;
|
||||
anchor = RegisterAnchor(token.value);
|
||||
m_scanner.pop();
|
||||
}
|
||||
@@ -410,4 +425,4 @@ anchor_t SingleDocParser::LookupAnchor(const Mark& mark,
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "yaml-cpp/anchor.h"
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
namespace YAML {
|
||||
class CollectionStack;
|
||||
@@ -23,9 +22,13 @@ struct Directives;
|
||||
struct Mark;
|
||||
struct Token;
|
||||
|
||||
class SingleDocParser : private noncopyable {
|
||||
class SingleDocParser {
|
||||
public:
|
||||
SingleDocParser(Scanner& scanner, const Directives& directives);
|
||||
SingleDocParser(const SingleDocParser&) = delete;
|
||||
SingleDocParser(SingleDocParser&&) = delete;
|
||||
SingleDocParser& operator=(const SingleDocParser&) = delete;
|
||||
SingleDocParser& operator=(SingleDocParser&&) = delete;
|
||||
~SingleDocParser();
|
||||
|
||||
void HandleDocument(EventHandler& eventHandler);
|
||||
@@ -43,9 +46,10 @@ class SingleDocParser : private noncopyable {
|
||||
void HandleCompactMap(EventHandler& eventHandler);
|
||||
void HandleCompactMapWithNoKey(EventHandler& eventHandler);
|
||||
|
||||
void ParseProperties(std::string& tag, anchor_t& anchor);
|
||||
void ParseProperties(std::string& tag, anchor_t& anchor,
|
||||
std::string& anchor_name);
|
||||
void ParseTag(std::string& tag);
|
||||
void ParseAnchor(anchor_t& anchor);
|
||||
void ParseAnchor(anchor_t& anchor, std::string& anchor_name);
|
||||
|
||||
anchor_t RegisterAnchor(const std::string& name);
|
||||
anchor_t LookupAnchor(const Mark& mark, const std::string& name) const;
|
||||
@@ -53,13 +57,13 @@ class SingleDocParser : private noncopyable {
|
||||
private:
|
||||
Scanner& m_scanner;
|
||||
const Directives& m_directives;
|
||||
std::auto_ptr<CollectionStack> m_pCollectionStack;
|
||||
std::unique_ptr<CollectionStack> m_pCollectionStack;
|
||||
|
||||
typedef std::map<std::string, anchor_t> Anchors;
|
||||
using Anchors = std::map<std::string, anchor_t>;
|
||||
Anchors m_anchors;
|
||||
|
||||
anchor_t m_curAnchor;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -111,24 +111,15 @@ static UtfIntroState s_introTransitions[][uictMax] = {
|
||||
|
||||
static char s_introUngetCount[][uictMax] = {
|
||||
// uict00, uictBB, uictBF, uictEF, uictFE, uictFF, uictAscii, uictOther
|
||||
{0, 1, 1, 0, 0, 0, 0, 1},
|
||||
{0, 2, 2, 2, 2, 2, 2, 2},
|
||||
{3, 3, 3, 3, 0, 3, 3, 3},
|
||||
{4, 4, 4, 4, 4, 0, 4, 4},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{2, 2, 2, 2, 2, 0, 2, 2},
|
||||
{2, 2, 2, 2, 0, 2, 2, 2},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 2, 2, 2, 2, 2, 2, 2},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 2, 2, 2, 2, 2, 2, 2},
|
||||
{0, 3, 3, 3, 3, 3, 3, 3},
|
||||
{4, 4, 4, 4, 4, 4, 4, 4},
|
||||
{2, 0, 2, 2, 2, 2, 2, 2},
|
||||
{3, 3, 0, 3, 3, 3, 3, 3},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 1, 1, 0, 0, 0, 0, 1}, {0, 2, 2, 2, 2, 2, 2, 2},
|
||||
{3, 3, 3, 3, 0, 3, 3, 3}, {4, 4, 4, 4, 4, 0, 4, 4},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{2, 2, 2, 2, 2, 0, 2, 2}, {2, 2, 2, 2, 0, 2, 2, 2},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1}, {0, 2, 2, 2, 2, 2, 2, 2},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 2, 2, 2, 2, 2, 2, 2}, {0, 3, 3, 3, 3, 3, 3, 3},
|
||||
{4, 4, 4, 4, 4, 4, 4, 4}, {2, 0, 2, 2, 2, 2, 2, 2},
|
||||
{3, 3, 0, 3, 3, 3, 3, 3}, {1, 1, 1, 1, 1, 1, 1, 1},
|
||||
};
|
||||
|
||||
inline UtfIntroCharType IntroCharTypeOf(std::istream::int_type ch) {
|
||||
@@ -160,7 +151,7 @@ inline UtfIntroCharType IntroCharTypeOf(std::istream::int_type ch) {
|
||||
|
||||
inline char Utf8Adjust(unsigned long ch, unsigned char lead_bits,
|
||||
unsigned char rshift) {
|
||||
const unsigned char header = ((1 << lead_bits) - 1) << (8 - lead_bits);
|
||||
const unsigned char header = static_cast<unsigned char>(((1 << lead_bits) - 1) << (8 - lead_bits));
|
||||
const unsigned char mask = (0xFF >> (lead_bits + 1));
|
||||
return static_cast<char>(
|
||||
static_cast<unsigned char>(header | ((ch >> rshift) & mask)));
|
||||
@@ -192,17 +183,20 @@ inline void QueueUnicodeCodepoint(std::deque<char>& q, unsigned long ch) {
|
||||
|
||||
Stream::Stream(std::istream& input)
|
||||
: m_input(input),
|
||||
m_mark{},
|
||||
m_charSet{},
|
||||
m_readahead{},
|
||||
m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]),
|
||||
m_nPrefetchedAvailable(0),
|
||||
m_nPrefetchedUsed(0) {
|
||||
typedef std::istream::traits_type char_traits;
|
||||
using char_traits = std::istream::traits_type;
|
||||
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
// Determine (or guess) the character-set by reading the BOM, if any. See
|
||||
// the YAML specification for the determination algorithm.
|
||||
char_traits::int_type intro[4];
|
||||
char_traits::int_type intro[4]{};
|
||||
int nIntroUsed = 0;
|
||||
UtfIntroState state = uis_start;
|
||||
for (; !s_introFinalState[state];) {
|
||||
@@ -279,9 +273,11 @@ char Stream::get() {
|
||||
// . Extracts 'n' characters from the stream and updates our position
|
||||
std::string Stream::get(int n) {
|
||||
std::string ret;
|
||||
ret.reserve(n);
|
||||
for (int i = 0; i < n; i++)
|
||||
ret += get();
|
||||
if(n > 0) {
|
||||
ret.reserve(static_cast<std::string::size_type>(n));
|
||||
for (int i = 0; i < n; i++)
|
||||
ret += get();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -332,7 +328,7 @@ bool Stream::_ReadAheadTo(size_t i) const {
|
||||
void Stream::StreamInUtf8() const {
|
||||
unsigned char b = GetNextByte();
|
||||
if (m_input.good()) {
|
||||
m_readahead.push_back(b);
|
||||
m_readahead.push_back(static_cast<char>(b));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,4 +441,4 @@ void Stream::StreamInUtf32() const {
|
||||
|
||||
QueueUnicodeCodepoint(m_readahead, ch);
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
12
src/stream.h
12
src/stream.h
@@ -7,7 +7,6 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
@@ -17,11 +16,18 @@
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
class Stream : private noncopyable {
|
||||
|
||||
class StreamCharSource;
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
friend class StreamCharSource;
|
||||
|
||||
Stream(std::istream& input);
|
||||
Stream(const Stream&) = delete;
|
||||
Stream(Stream&&) = delete;
|
||||
Stream& operator=(const Stream&) = delete;
|
||||
Stream& operator=(Stream&&) = delete;
|
||||
~Stream();
|
||||
|
||||
operator bool() const;
|
||||
@@ -71,6 +77,6 @@ inline bool Stream::ReadAheadTo(size_t i) const {
|
||||
return true;
|
||||
return _ReadAheadTo(i);
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -7,16 +7,20 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
#include "yaml-cpp/noexcept.h"
|
||||
#include "stream.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace YAML {
|
||||
|
||||
class StreamCharSource {
|
||||
public:
|
||||
StreamCharSource(const Stream& stream) : m_offset(0), m_stream(stream) {}
|
||||
StreamCharSource(const StreamCharSource& source)
|
||||
: m_offset(source.m_offset), m_stream(source.m_stream) {}
|
||||
~StreamCharSource() {}
|
||||
StreamCharSource(const StreamCharSource& source) = default;
|
||||
StreamCharSource(StreamCharSource&&) YAML_CPP_NOEXCEPT = default;
|
||||
StreamCharSource& operator=(const StreamCharSource&) = delete;
|
||||
StreamCharSource& operator=(StreamCharSource&&) = delete;
|
||||
~StreamCharSource() = default;
|
||||
|
||||
operator bool() const;
|
||||
char operator[](std::size_t i) const { return m_stream.CharAt(m_offset + i); }
|
||||
@@ -27,8 +31,6 @@ class StreamCharSource {
|
||||
private:
|
||||
std::size_t m_offset;
|
||||
const Stream& m_stream;
|
||||
|
||||
StreamCharSource& operator=(const StreamCharSource&); // non-assignable
|
||||
};
|
||||
|
||||
inline StreamCharSource::operator bool() const {
|
||||
@@ -38,11 +40,11 @@ inline StreamCharSource::operator bool() const {
|
||||
inline const StreamCharSource StreamCharSource::operator+(int i) const {
|
||||
StreamCharSource source(*this);
|
||||
if (static_cast<int>(source.m_offset) + i >= 0)
|
||||
source.m_offset += i;
|
||||
source.m_offset += static_cast<std::size_t>(i);
|
||||
else
|
||||
source.m_offset = 0;
|
||||
return source;
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -6,7 +6,8 @@
|
||||
#include "token.h"
|
||||
|
||||
namespace YAML {
|
||||
Tag::Tag(const Token& token) : type(static_cast<TYPE>(token.data)) {
|
||||
Tag::Tag(const Token& token)
|
||||
: type(static_cast<TYPE>(token.data)), handle{}, value{} {
|
||||
switch (type) {
|
||||
case VERBATIM:
|
||||
value = token.value;
|
||||
@@ -46,4 +47,4 @@ const std::string Tag::Translate(const Directives& directives) {
|
||||
}
|
||||
throw std::runtime_error("yaml-cpp: internal error, bad tag type");
|
||||
}
|
||||
}
|
||||
} // namespace YAML
|
||||
|
17
src/token.h
17
src/token.h
@@ -14,10 +14,11 @@
|
||||
|
||||
namespace YAML {
|
||||
const std::string TokenNames[] = {
|
||||
"DIRECTIVE", "DOC_START", "DOC_END", "BLOCK_SEQ_START", "BLOCK_MAP_START",
|
||||
"BLOCK_SEQ_END", "BLOCK_MAP_END", "BLOCK_ENTRY", "FLOW_SEQ_START",
|
||||
"FLOW_MAP_START", "FLOW_SEQ_END", "FLOW_MAP_END", "FLOW_MAP_COMPACT",
|
||||
"FLOW_ENTRY", "KEY", "VALUE", "ANCHOR", "ALIAS", "TAG", "SCALAR"};
|
||||
"DIRECTIVE", "DOC_START", "DOC_END", "BLOCK_SEQ_START",
|
||||
"BLOCK_MAP_START", "BLOCK_SEQ_END", "BLOCK_MAP_END", "BLOCK_ENTRY",
|
||||
"FLOW_SEQ_START", "FLOW_MAP_START", "FLOW_SEQ_END", "FLOW_MAP_END",
|
||||
"FLOW_MAP_COMPACT", "FLOW_ENTRY", "KEY", "VALUE",
|
||||
"ANCHOR", "ALIAS", "TAG", "SCALAR"};
|
||||
|
||||
struct Token {
|
||||
// enums
|
||||
@@ -48,12 +49,12 @@ struct Token {
|
||||
|
||||
// data
|
||||
Token(TYPE type_, const Mark& mark_)
|
||||
: status(VALID), type(type_), mark(mark_), data(0) {}
|
||||
: status(VALID), type(type_), mark(mark_), value{}, params{}, data(0) {}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const Token& token) {
|
||||
out << TokenNames[token.type] << std::string(": ") << token.value;
|
||||
for (std::size_t i = 0; i < token.params.size(); i++)
|
||||
out << std::string(" ") << token.params[i];
|
||||
for (const std::string& param : token.params)
|
||||
out << std::string(" ") << param;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -64,6 +65,6 @@ struct Token {
|
||||
std::vector<std::string> params;
|
||||
int data;
|
||||
};
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
14
test/BUILD.bazel
Normal file
14
test/BUILD.bazel
Normal file
@@ -0,0 +1,14 @@
|
||||
cc_test(
|
||||
name = "test",
|
||||
srcs = glob([
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"integrations/*.cpp",
|
||||
"node/*.cpp",
|
||||
]),
|
||||
deps = [
|
||||
"//:yaml-cpp",
|
||||
"//:yaml-cpp_internal",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
@@ -1,34 +1,49 @@
|
||||
set(gtest_force_shared_crt ${MSVC_SHARED_RT} CACHE BOOL
|
||||
"Use shared (DLL) run-time lib even when Google Test built as a static lib.")
|
||||
add_subdirectory(gmock-1.7.0)
|
||||
include_directories(SYSTEM gmock-1.7.0/gtest/include)
|
||||
include_directories(SYSTEM gmock-1.7.0/include)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
add_definitions("-DGTEST_LINKED_AS_SHARED_LIBRARY")
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(BUILD_MOCK ON CACHE BOOL "" FORCE)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
|
||||
|
||||
add_subdirectory(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.10.0"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/prefix")
|
||||
|
||||
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.10.0/googletest/include")
|
||||
|
||||
set(test-new-api-pattern "new-api/*.cpp")
|
||||
set(test-source-pattern "*.cpp" "integration/*.cpp" "node/*.cpp")
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.11)
|
||||
list(INSERT test-new-api-pattern 0 CONFIGURE_DEPENDS)
|
||||
list(INSERT test-source-pattern 0 CONFIGURE_DEPENDS)
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR
|
||||
"${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(yaml_test_flags "-Wno-c99-extensions -Wno-variadic-macros -Wno-sign-compare")
|
||||
file(GLOB test-new-api-sources ${test-new-api-pattern})
|
||||
file(GLOB test-sources ${test-source-pattern})
|
||||
|
||||
add_executable(yaml-cpp-tests "")
|
||||
target_sources(yaml-cpp-tests
|
||||
PRIVATE
|
||||
${test-new-api-sources}
|
||||
${test-sources})
|
||||
target_include_directories(yaml-cpp-tests
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/integration
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/src)
|
||||
target_compile_options(yaml-cpp-tests
|
||||
PRIVATE
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-c99-extensions -Wno-variadic-macros -Wno-sign-compare>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wno-variadic-macros -Wno-sign-compare>)
|
||||
target_link_libraries(yaml-cpp-tests
|
||||
PRIVATE
|
||||
Threads::Threads
|
||||
yaml-cpp
|
||||
gmock)
|
||||
|
||||
set_property(TARGET yaml-cpp-tests PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set_target_properties(yaml-cpp-tests PROPERTIES CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
file(GLOB test_headers [a-z_]*.h)
|
||||
file(GLOB test_sources [a-z_]*.cpp integration/[a-z_]*.cpp node/[a-z_]*.cpp)
|
||||
file(GLOB test_new_api_sources new-api/[a-z]*.cpp)
|
||||
|
||||
list(APPEND test_sources ${test_new_api_sources})
|
||||
add_sources(${test_sources} ${test_headers})
|
||||
|
||||
include_directories(${YAML_CPP_SOURCE_DIR}/test)
|
||||
|
||||
add_executable(run-tests
|
||||
${test_sources}
|
||||
${test_headers}
|
||||
)
|
||||
set_target_properties(run-tests PROPERTIES
|
||||
COMPILE_FLAGS "${yaml_c_flags} ${yaml_cxx_flags} ${yaml_test_flags}"
|
||||
)
|
||||
target_link_libraries(run-tests yaml-cpp gmock)
|
||||
|
||||
add_test(yaml-test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/run-tests)
|
||||
add_test(yaml-cpp::test yaml-cpp-tests)
|
||||
|
@@ -35,10 +35,12 @@ def doc_end(implicit=False):
|
||||
|
||||
def scalar(value, tag='', anchor='', anchor_id=0):
|
||||
emit = []
|
||||
handle = []
|
||||
if tag:
|
||||
emit += ['VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['Anchor("%s")' % encode(anchor)]
|
||||
handle += ['OnAnchor(_, "%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
@@ -47,39 +49,46 @@ def scalar(value, tag='', anchor='', anchor_id=0):
|
||||
else:
|
||||
out_tag = '!'
|
||||
emit += ['"%s"' % encode(value)]
|
||||
return {'emit': emit, 'handle': 'OnScalar(_, "%s", %s, "%s")' % (out_tag, anchor_id, encode(value))}
|
||||
handle += ['OnScalar(_, "%s", %s, "%s")' % (out_tag, anchor_id, encode(value))]
|
||||
return {'emit': emit, 'handle': handle}
|
||||
|
||||
def comment(value):
|
||||
return {'emit': 'Comment("%s")' % value, 'handle': ''}
|
||||
|
||||
def seq_start(tag='', anchor='', anchor_id=0, style='_'):
|
||||
emit = []
|
||||
handle = []
|
||||
if tag:
|
||||
emit += ['VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['Anchor("%s")' % encode(anchor)]
|
||||
handle += ['OnAnchor(_, "%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
out_tag = '?'
|
||||
emit += ['BeginSeq']
|
||||
return {'emit': emit, 'handle': 'OnSequenceStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)}
|
||||
handle += ['OnSequenceStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)]
|
||||
return {'emit': emit, 'handle': handle}
|
||||
|
||||
def seq_end():
|
||||
return {'emit': 'EndSeq', 'handle': 'OnSequenceEnd()'}
|
||||
|
||||
def map_start(tag='', anchor='', anchor_id=0, style='_'):
|
||||
emit = []
|
||||
handle = []
|
||||
if tag:
|
||||
emit += ['VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['Anchor("%s")' % encode(anchor)]
|
||||
handle += ['OnAnchor(_, "%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
out_tag = '?'
|
||||
emit += ['BeginMap']
|
||||
return {'emit': emit, 'handle': 'OnMapStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)}
|
||||
handle += ['OnMapStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)]
|
||||
return {'emit': emit, 'handle': handle}
|
||||
|
||||
def map_end():
|
||||
return {'emit': 'EndMap', 'handle': 'OnMapEnd()'}
|
||||
@@ -202,7 +211,10 @@ def create_emitter_tests(out):
|
||||
out.writeln('')
|
||||
for event in test['events']:
|
||||
handle = event['handle']
|
||||
if handle:
|
||||
if isinstance(handle, list):
|
||||
for e in handle:
|
||||
out.writeln('EXPECT_CALL(handler, %s);' % e)
|
||||
elif handle:
|
||||
out.writeln('EXPECT_CALL(handler, %s);' % handle)
|
||||
out.writeln('Parse(out.c_str());')
|
||||
out.writeln('')
|
||||
|
@@ -1,126 +0,0 @@
|
||||
Changes for 1.7.0:
|
||||
|
||||
* All new improvements in Google Test 1.7.0.
|
||||
* New feature: matchers DoubleNear(), FloatNear(),
|
||||
NanSensitiveDoubleNear(), NanSensitiveFloatNear(),
|
||||
UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(),
|
||||
WhenSortedBy(), IsEmpty(), and SizeIs().
|
||||
* Improvement: Google Mock can now be built as a DLL.
|
||||
* Improvement: when compiled by a C++11 compiler, matchers AllOf()
|
||||
and AnyOf() can accept an arbitrary number of matchers.
|
||||
* Improvement: when compiled by a C++11 compiler, matchers
|
||||
ElementsAreArray() can accept an initializer list.
|
||||
* Improvement: when exceptions are enabled, a mock method with no
|
||||
default action now throws instead crashing the test.
|
||||
* Improvement: added class testing::StringMatchResultListener to aid
|
||||
definition of composite matchers.
|
||||
* Improvement: function return types used in MOCK_METHOD*() macros can
|
||||
now contain unprotected commas.
|
||||
* Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT()
|
||||
are now more strict in ensuring that the value type and the matcher
|
||||
type are compatible, catching potential bugs in tests.
|
||||
* Improvement: Pointee() now works on an optional<T>.
|
||||
* Improvement: the ElementsAreArray() matcher can now take a vector or
|
||||
iterator range as input, and makes a copy of its input elements
|
||||
before the conversion to a Matcher.
|
||||
* Improvement: the Google Mock Generator can now generate mocks for
|
||||
some class templates.
|
||||
* Bug fix: mock object destruction triggerred by another mock object's
|
||||
destruction no longer hangs.
|
||||
* Improvement: Google Mock Doctor works better with newer Clang and
|
||||
GCC now.
|
||||
* Compatibility fixes.
|
||||
* Bug/warning fixes.
|
||||
|
||||
Changes for 1.6.0:
|
||||
|
||||
* Compilation is much faster and uses much less memory, especially
|
||||
when the constructor and destructor of a mock class are moved out of
|
||||
the class body.
|
||||
* New matchers: Pointwise(), Each().
|
||||
* New actions: ReturnPointee() and ReturnRefOfCopy().
|
||||
* CMake support.
|
||||
* Project files for Visual Studio 2010.
|
||||
* AllOf() and AnyOf() can handle up-to 10 arguments now.
|
||||
* Google Mock doctor understands Clang error messages now.
|
||||
* SetArgPointee<> now accepts string literals.
|
||||
* gmock_gen.py handles storage specifier macros and template return
|
||||
types now.
|
||||
* Compatibility fixes.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
* Potentially incompatible changes: disables the harmful 'make install'
|
||||
command in autotools.
|
||||
|
||||
Potentially breaking changes:
|
||||
|
||||
* The description string for MATCHER*() changes from Python-style
|
||||
interpolation to an ordinary C++ string expression.
|
||||
* SetArgumentPointee is deprecated in favor of SetArgPointee.
|
||||
* Some non-essential project files for Visual Studio 2005 are removed.
|
||||
|
||||
Changes for 1.5.0:
|
||||
|
||||
* New feature: Google Mock can be safely used in multi-threaded tests
|
||||
on platforms having pthreads.
|
||||
* New feature: function for printing a value of arbitrary type.
|
||||
* New feature: function ExplainMatchResult() for easy definition of
|
||||
composite matchers.
|
||||
* The new matcher API lets user-defined matchers generate custom
|
||||
explanations more directly and efficiently.
|
||||
* Better failure messages all around.
|
||||
* NotNull() and IsNull() now work with smart pointers.
|
||||
* Field() and Property() now work when the matcher argument is a pointer
|
||||
passed by reference.
|
||||
* Regular expression matchers on all platforms.
|
||||
* Added GCC 4.0 support for Google Mock Doctor.
|
||||
* Added gmock_all_test.cc for compiling most Google Mock tests
|
||||
in a single file.
|
||||
* Significantly cleaned up compiler warnings.
|
||||
* Bug fixes, better test coverage, and implementation clean-ups.
|
||||
|
||||
Potentially breaking changes:
|
||||
|
||||
* Custom matchers defined using MatcherInterface or MakePolymorphicMatcher()
|
||||
need to be updated after upgrading to Google Mock 1.5.0; matchers defined
|
||||
using MATCHER or MATCHER_P* aren't affected.
|
||||
* Dropped support for 'make install'.
|
||||
|
||||
Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of
|
||||
Google Test):
|
||||
|
||||
* Works in more environments: Symbian and minGW, Visual C++ 7.1.
|
||||
* Lighter weight: comes with our own implementation of TR1 tuple (no
|
||||
more dependency on Boost!).
|
||||
* New feature: --gmock_catch_leaked_mocks for detecting leaked mocks.
|
||||
* New feature: ACTION_TEMPLATE for defining templatized actions.
|
||||
* New feature: the .After() clause for specifying expectation order.
|
||||
* New feature: the .With() clause for for specifying inter-argument
|
||||
constraints.
|
||||
* New feature: actions ReturnArg<k>(), ReturnNew<T>(...), and
|
||||
DeleteArg<k>().
|
||||
* New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(),
|
||||
and Contains().
|
||||
* New feature: utility class MockFunction<F>, useful for checkpoints, etc.
|
||||
* New feature: functions Value(x, m) and SafeMatcherCast<T>(m).
|
||||
* New feature: copying a mock object is rejected at compile time.
|
||||
* New feature: a script for fusing all Google Mock and Google Test
|
||||
source files for easy deployment.
|
||||
* Improved the Google Mock doctor to diagnose more diseases.
|
||||
* Improved the Google Mock generator script.
|
||||
* Compatibility fixes for Mac OS X and gcc.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.1.0:
|
||||
|
||||
* New feature: ability to use Google Mock with any testing framework.
|
||||
* New feature: macros for easily defining new matchers
|
||||
* New feature: macros for easily defining new actions.
|
||||
* New feature: more container matchers.
|
||||
* New feature: actions for accessing function arguments and throwing
|
||||
exceptions.
|
||||
* Improved the Google Mock doctor script for diagnosing compiler errors.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.0.0:
|
||||
|
||||
* Initial Open Source release of Google Mock
|
@@ -1,216 +0,0 @@
|
||||
# Automake file
|
||||
|
||||
# Nonstandard package files for distribution.
|
||||
EXTRA_DIST = LICENSE
|
||||
|
||||
# We may need to build our internally packaged gtest. If so, it will be
|
||||
# included in the 'subdirs' variable.
|
||||
SUBDIRS = $(subdirs)
|
||||
|
||||
# This is generated by the configure script, so clean it for distribution.
|
||||
DISTCLEANFILES = scripts/gmock-config
|
||||
|
||||
# We define the global AM_CPPFLAGS as everything we compile includes from these
|
||||
# directories.
|
||||
AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include
|
||||
|
||||
# Modifies compiler and linker flags for pthreads compatibility.
|
||||
if HAVE_PTHREADS
|
||||
AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
|
||||
AM_LIBS = @PTHREAD_LIBS@
|
||||
endif
|
||||
|
||||
# Build rules for libraries.
|
||||
lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la
|
||||
|
||||
lib_libgmock_la_SOURCES = src/gmock-all.cc
|
||||
|
||||
pkginclude_HEADERS = \
|
||||
include/gmock/gmock-actions.h \
|
||||
include/gmock/gmock-cardinalities.h \
|
||||
include/gmock/gmock-generated-actions.h \
|
||||
include/gmock/gmock-generated-function-mockers.h \
|
||||
include/gmock/gmock-generated-matchers.h \
|
||||
include/gmock/gmock-generated-nice-strict.h \
|
||||
include/gmock/gmock-matchers.h \
|
||||
include/gmock/gmock-more-actions.h \
|
||||
include/gmock/gmock-more-matchers.h \
|
||||
include/gmock/gmock-spec-builders.h \
|
||||
include/gmock/gmock.h
|
||||
|
||||
pkginclude_internaldir = $(pkgincludedir)/internal
|
||||
pkginclude_internal_HEADERS = \
|
||||
include/gmock/internal/gmock-generated-internal-utils.h \
|
||||
include/gmock/internal/gmock-internal-utils.h \
|
||||
include/gmock/internal/gmock-port.h
|
||||
|
||||
lib_libgmock_main_la_SOURCES = src/gmock_main.cc
|
||||
lib_libgmock_main_la_LIBADD = lib/libgmock.la
|
||||
|
||||
# Build rules for tests. Automake's naming for some of these variables isn't
|
||||
# terribly obvious, so this is a brief reference:
|
||||
#
|
||||
# TESTS -- Programs run automatically by "make check"
|
||||
# check_PROGRAMS -- Programs built by "make check" but not necessarily run
|
||||
|
||||
TESTS=
|
||||
check_PROGRAMS=
|
||||
AM_LDFLAGS = $(GTEST_LDFLAGS)
|
||||
|
||||
# This exercises all major components of Google Mock. It also
|
||||
# verifies that libgmock works.
|
||||
TESTS += test/gmock-spec-builders_test
|
||||
check_PROGRAMS += test/gmock-spec-builders_test
|
||||
test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc
|
||||
test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la
|
||||
|
||||
# This tests using Google Mock in multiple translation units. It also
|
||||
# verifies that libgmock_main and libgmock work.
|
||||
TESTS += test/gmock_link_test
|
||||
check_PROGRAMS += test/gmock_link_test
|
||||
test_gmock_link_test_SOURCES = \
|
||||
test/gmock_link2_test.cc \
|
||||
test/gmock_link_test.cc \
|
||||
test/gmock_link_test.h
|
||||
test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la
|
||||
|
||||
if HAVE_PYTHON
|
||||
# Tests that fused gmock files compile and work.
|
||||
TESTS += test/gmock_fused_test
|
||||
check_PROGRAMS += test/gmock_fused_test
|
||||
test_gmock_fused_test_SOURCES = \
|
||||
fused-src/gmock-gtest-all.cc \
|
||||
fused-src/gmock/gmock.h \
|
||||
fused-src/gmock_main.cc \
|
||||
fused-src/gtest/gtest.h \
|
||||
test/gmock_test.cc
|
||||
test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src"
|
||||
endif
|
||||
|
||||
# Google Mock source files that we don't compile directly.
|
||||
GMOCK_SOURCE_INGLUDES = \
|
||||
src/gmock-cardinalities.cc \
|
||||
src/gmock-internal-utils.cc \
|
||||
src/gmock-matchers.cc \
|
||||
src/gmock-spec-builders.cc \
|
||||
src/gmock.cc
|
||||
|
||||
EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES)
|
||||
|
||||
# C++ tests that we don't compile using autotools.
|
||||
EXTRA_DIST += \
|
||||
test/gmock-actions_test.cc \
|
||||
test/gmock_all_test.cc \
|
||||
test/gmock-cardinalities_test.cc \
|
||||
test/gmock_ex_test.cc \
|
||||
test/gmock-generated-actions_test.cc \
|
||||
test/gmock-generated-function-mockers_test.cc \
|
||||
test/gmock-generated-internal-utils_test.cc \
|
||||
test/gmock-generated-matchers_test.cc \
|
||||
test/gmock-internal-utils_test.cc \
|
||||
test/gmock-matchers_test.cc \
|
||||
test/gmock-more-actions_test.cc \
|
||||
test/gmock-nice-strict_test.cc \
|
||||
test/gmock-port_test.cc \
|
||||
test/gmock_stress_test.cc
|
||||
|
||||
# Python tests, which we don't run using autotools.
|
||||
EXTRA_DIST += \
|
||||
test/gmock_leak_test.py \
|
||||
test/gmock_leak_test_.cc \
|
||||
test/gmock_output_test.py \
|
||||
test/gmock_output_test_.cc \
|
||||
test/gmock_output_test_golden.txt \
|
||||
test/gmock_test_utils.py
|
||||
|
||||
# Nonstandard package files for distribution.
|
||||
EXTRA_DIST += \
|
||||
CHANGES \
|
||||
CONTRIBUTORS \
|
||||
make/Makefile
|
||||
|
||||
# Pump scripts for generating Google Mock headers.
|
||||
# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
|
||||
EXTRA_DIST += \
|
||||
include/gmock/gmock-generated-actions.h.pump \
|
||||
include/gmock/gmock-generated-function-mockers.h.pump \
|
||||
include/gmock/gmock-generated-matchers.h.pump \
|
||||
include/gmock/gmock-generated-nice-strict.h.pump \
|
||||
include/gmock/internal/gmock-generated-internal-utils.h.pump
|
||||
|
||||
# Script for fusing Google Mock and Google Test source files.
|
||||
EXTRA_DIST += scripts/fuse_gmock_files.py
|
||||
|
||||
# The Google Mock Generator tool from the cppclean project.
|
||||
EXTRA_DIST += \
|
||||
scripts/generator/LICENSE \
|
||||
scripts/generator/README \
|
||||
scripts/generator/README.cppclean \
|
||||
scripts/generator/cpp/__init__.py \
|
||||
scripts/generator/cpp/ast.py \
|
||||
scripts/generator/cpp/gmock_class.py \
|
||||
scripts/generator/cpp/keywords.py \
|
||||
scripts/generator/cpp/tokenize.py \
|
||||
scripts/generator/cpp/utils.py \
|
||||
scripts/generator/gmock_gen.py
|
||||
|
||||
# CMake scripts.
|
||||
EXTRA_DIST += \
|
||||
CMakeLists.txt
|
||||
|
||||
# Microsoft Visual Studio 2005 projects.
|
||||
EXTRA_DIST += \
|
||||
msvc/2005/gmock.sln \
|
||||
msvc/2005/gmock.vcproj \
|
||||
msvc/2005/gmock_config.vsprops \
|
||||
msvc/2005/gmock_main.vcproj \
|
||||
msvc/2005/gmock_test.vcproj
|
||||
|
||||
# Microsoft Visual Studio 2010 projects.
|
||||
EXTRA_DIST += \
|
||||
msvc/2010/gmock.sln \
|
||||
msvc/2010/gmock.vcxproj \
|
||||
msvc/2010/gmock_config.props \
|
||||
msvc/2010/gmock_main.vcxproj \
|
||||
msvc/2010/gmock_test.vcxproj
|
||||
|
||||
if HAVE_PYTHON
|
||||
# gmock_test.cc does not really depend on files generated by the
|
||||
# fused-gmock-internal rule. However, gmock_test.o does, and it is
|
||||
# important to include test/gmock_test.cc as part of this rule in order to
|
||||
# prevent compiling gmock_test.o until all dependent files have been
|
||||
# generated.
|
||||
$(test_gmock_fused_test_SOURCES): fused-gmock-internal
|
||||
|
||||
# TODO(vladl@google.com): Find a way to add Google Tests's sources here.
|
||||
fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
|
||||
$(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \
|
||||
$(lib_libgmock_main_la_SOURCES) \
|
||||
scripts/fuse_gmock_files.py
|
||||
mkdir -p "$(srcdir)/fused-src"
|
||||
chmod -R u+w "$(srcdir)/fused-src"
|
||||
rm -f "$(srcdir)/fused-src/gtest/gtest.h"
|
||||
rm -f "$(srcdir)/fused-src/gmock/gmock.h"
|
||||
rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc"
|
||||
"$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src"
|
||||
cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src"
|
||||
|
||||
maintainer-clean-local:
|
||||
rm -rf "$(srcdir)/fused-src"
|
||||
endif
|
||||
|
||||
# Death tests may produce core dumps in the build directory. In case
|
||||
# this happens, clean them to keep distcleancheck happy.
|
||||
CLEANFILES = core
|
||||
|
||||
# Disables 'make install' as installing a compiled version of Google
|
||||
# Mock can lead to undefined behavior due to violation of the
|
||||
# One-Definition Rule.
|
||||
|
||||
install-exec-local:
|
||||
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system."
|
||||
false
|
||||
|
||||
install-data-local:
|
||||
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system."
|
||||
false
|
File diff suppressed because it is too large
Load Diff
@@ -1,369 +0,0 @@
|
||||
Google C++ Mocking Framework
|
||||
============================
|
||||
|
||||
http://code.google.com/p/googlemock/
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Google's framework for writing and using C++ mock classes on a variety
|
||||
of platforms (Linux, Mac OS X, Windows, Windows CE, Symbian, etc).
|
||||
Inspired by jMock, EasyMock, and Hamcrest, and designed with C++'s
|
||||
specifics in mind, it can help you derive better designs of your
|
||||
system and write better tests.
|
||||
|
||||
Google Mock:
|
||||
|
||||
- provides a declarative syntax for defining mocks,
|
||||
- can easily define partial (hybrid) mocks, which are a cross of real
|
||||
and mock objects,
|
||||
- handles functions of arbitrary types and overloaded functions,
|
||||
- comes with a rich set of matchers for validating function arguments,
|
||||
- uses an intuitive syntax for controlling the behavior of a mock,
|
||||
- does automatic verification of expectations (no record-and-replay
|
||||
needed),
|
||||
- allows arbitrary (partial) ordering constraints on
|
||||
function calls to be expressed,
|
||||
- lets a user extend it by defining new matchers and actions.
|
||||
- does not use exceptions, and
|
||||
- is easy to learn and use.
|
||||
|
||||
Please see the project page above for more information as well as the
|
||||
mailing list for questions, discussions, and development. There is
|
||||
also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
|
||||
join us!
|
||||
|
||||
Please note that code under scripts/generator/ is from the cppclean
|
||||
project (http://code.google.com/p/cppclean/) and under the Apache
|
||||
License, which is different from Google Mock's license.
|
||||
|
||||
Requirements for End Users
|
||||
--------------------------
|
||||
|
||||
Google Mock is implemented on top of the Google Test C++ testing
|
||||
framework (http://code.google.com/p/googletest/), and includes the
|
||||
latter as part of the SVN repositary and distribution package. You
|
||||
must use the bundled version of Google Test when using Google Mock, or
|
||||
you may get compiler/linker errors.
|
||||
|
||||
You can also easily configure Google Mock to work with another testing
|
||||
framework of your choice; although it will still need Google Test as
|
||||
an internal dependency. Please read
|
||||
http://code.google.com/p/googlemock/wiki/ForDummies#Using_Google_Mock_with_Any_Testing_Framework
|
||||
for how to do it.
|
||||
|
||||
Google Mock depends on advanced C++ features and thus requires a more
|
||||
modern compiler. The following are needed to use Google Mock:
|
||||
|
||||
### Linux Requirements ###
|
||||
|
||||
These are the base requirements to build and use Google Mock from a source
|
||||
package (as described below):
|
||||
|
||||
* GNU-compatible Make or "gmake"
|
||||
* POSIX-standard shell
|
||||
* POSIX(-2) Regular Expressions (regex.h)
|
||||
* C++98-standard-compliant compiler (e.g. GCC 3.4 or newer)
|
||||
|
||||
### Windows Requirements ###
|
||||
|
||||
* Microsoft Visual C++ 8.0 SP1 or newer
|
||||
|
||||
### Mac OS X Requirements ###
|
||||
|
||||
* Mac OS X 10.4 Tiger or newer
|
||||
* Developer Tools Installed
|
||||
|
||||
Requirements for Contributors
|
||||
-----------------------------
|
||||
|
||||
We welcome patches. If you plan to contribute a patch, you need to
|
||||
build Google Mock and its own tests from an SVN checkout (described
|
||||
below), which has further requirements:
|
||||
|
||||
* Automake version 1.9 or newer
|
||||
* Autoconf version 2.59 or newer
|
||||
* Libtool / Libtoolize
|
||||
* Python version 2.3 or newer (for running some of the tests and
|
||||
re-generating certain source files from templates)
|
||||
|
||||
Getting the Source
|
||||
------------------
|
||||
|
||||
There are two primary ways of getting Google Mock's source code: you
|
||||
can download a stable source release in your preferred archive format,
|
||||
or directly check out the source from our Subversion (SVN) repositary.
|
||||
The SVN checkout requires a few extra steps and some extra software
|
||||
packages on your system, but lets you track development and make
|
||||
patches much more easily, so we highly encourage it.
|
||||
|
||||
### Source Package ###
|
||||
|
||||
Google Mock is released in versioned source packages which can be
|
||||
downloaded from the download page [1]. Several different archive
|
||||
formats are provided, but the only difference is the tools needed to
|
||||
extract their contents, and the size of the resulting file. Download
|
||||
whichever you are most comfortable with.
|
||||
|
||||
[1] http://code.google.com/p/googlemock/downloads/list
|
||||
|
||||
Once downloaded expand the archive using whichever tools you prefer
|
||||
for that type. This will always result in a new directory with the
|
||||
name "gmock-X.Y.Z" which contains all of the source code. Here are
|
||||
some examples on Linux:
|
||||
|
||||
tar -xvzf gmock-X.Y.Z.tar.gz
|
||||
tar -xvjf gmock-X.Y.Z.tar.bz2
|
||||
unzip gmock-X.Y.Z.zip
|
||||
|
||||
### SVN Checkout ###
|
||||
|
||||
To check out the main branch (also known as the "trunk") of Google
|
||||
Mock, run the following Subversion command:
|
||||
|
||||
svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn
|
||||
|
||||
If you are using a *nix system and plan to use the GNU Autotools build
|
||||
system to build Google Mock (described below), you'll need to
|
||||
configure it now. Otherwise you are done with getting the source
|
||||
files.
|
||||
|
||||
To prepare the Autotools build system, enter the target directory of
|
||||
the checkout command you used ('gmock-svn') and proceed with the
|
||||
following command:
|
||||
|
||||
autoreconf -fvi
|
||||
|
||||
Once you have completed this step, you are ready to build the library.
|
||||
Note that you should only need to complete this step once. The
|
||||
subsequent 'make' invocations will automatically re-generate the bits
|
||||
of the build system that need to be changed.
|
||||
|
||||
If your system uses older versions of the autotools, the above command
|
||||
will fail. You may need to explicitly specify a version to use. For
|
||||
instance, if you have both GNU Automake 1.4 and 1.9 installed and
|
||||
'automake' would invoke the 1.4, use instead:
|
||||
|
||||
AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi
|
||||
|
||||
Make sure you're using the same version of automake and aclocal.
|
||||
|
||||
Setting up the Build
|
||||
--------------------
|
||||
|
||||
To build Google Mock and your tests that use it, you need to tell your
|
||||
build system where to find its headers and source files. The exact
|
||||
way to do it depends on which build system you use, and is usually
|
||||
straightforward.
|
||||
|
||||
### Generic Build Instructions ###
|
||||
|
||||
This section shows how you can integrate Google Mock into your
|
||||
existing build system.
|
||||
|
||||
Suppose you put Google Mock in directory ${GMOCK_DIR} and Google Test
|
||||
in ${GTEST_DIR} (the latter is ${GMOCK_DIR}/gtest by default). To
|
||||
build Google Mock, create a library build target (or a project as
|
||||
called by Visual Studio and Xcode) to compile
|
||||
|
||||
${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc
|
||||
|
||||
with
|
||||
|
||||
${GTEST_DIR}/include and ${GMOCK_DIR}/include
|
||||
|
||||
in the system header search path, and
|
||||
|
||||
${GTEST_DIR} and ${GMOCK_DIR}
|
||||
|
||||
in the normal header search path. Assuming a Linux-like system and gcc,
|
||||
something like the following will do:
|
||||
|
||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
||||
-isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
|
||||
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
||||
-isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
|
||||
-pthread -c ${GMOCK_DIR}/src/gmock-all.cc
|
||||
ar -rv libgmock.a gtest-all.o gmock-all.o
|
||||
|
||||
(We need -pthread as Google Test and Google Mock use threads.)
|
||||
|
||||
Next, you should compile your test source file with
|
||||
${GTEST_DIR}/include and ${GMOCK_DIR}/include in the header search
|
||||
path, and link it with gmock and any other necessary libraries:
|
||||
|
||||
g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \
|
||||
-pthread path/to/your_test.cc libgmock.a -o your_test
|
||||
|
||||
As an example, the make/ directory contains a Makefile that you can
|
||||
use to build Google Mock on systems where GNU make is available
|
||||
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
|
||||
Mock's own tests. Instead, it just builds the Google Mock library and
|
||||
a sample test. You can use it as a starting point for your own build
|
||||
script.
|
||||
|
||||
If the default settings are correct for your environment, the
|
||||
following commands should succeed:
|
||||
|
||||
cd ${GMOCK_DIR}/make
|
||||
make
|
||||
./gmock_test
|
||||
|
||||
If you see errors, try to tweak the contents of make/Makefile to make
|
||||
them go away. There are instructions in make/Makefile on how to do
|
||||
it.
|
||||
|
||||
### Windows ###
|
||||
|
||||
The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010
|
||||
directory contains VC++ 2010 projects for building Google Mock and
|
||||
selected tests.
|
||||
|
||||
Change to the appropriate directory and run "msbuild gmock.sln" to
|
||||
build the library and tests (or open the gmock.sln in the MSVC IDE).
|
||||
If you want to create your own project to use with Google Mock, you'll
|
||||
have to configure it to use the gmock_config propety sheet. For that:
|
||||
|
||||
* Open the Property Manager window (View | Other Windows | Property Manager)
|
||||
* Right-click on your project and select "Add Existing Property Sheet..."
|
||||
* Navigate to gmock_config.vsprops or gmock_config.props and select it.
|
||||
* In Project Properties | Configuration Properties | General | Additional
|
||||
Include Directories, type <path to Google Mock>/include.
|
||||
|
||||
Tweaking Google Mock
|
||||
--------------------
|
||||
|
||||
Google Mock can be used in diverse environments. The default
|
||||
configuration may not work (or may not work well) out of the box in
|
||||
some environments. However, you can easily tweak Google Mock by
|
||||
defining control macros on the compiler command line. Generally,
|
||||
these macros are named like GTEST_XYZ and you define them to either 1
|
||||
or 0 to enable or disable a certain feature.
|
||||
|
||||
We list the most frequently used macros below. For a complete list,
|
||||
see file ${GTEST_DIR}/include/gtest/internal/gtest-port.h.
|
||||
|
||||
### Choosing a TR1 Tuple Library ###
|
||||
|
||||
Google Mock uses the C++ Technical Report 1 (TR1) tuple library
|
||||
heavily. Unfortunately TR1 tuple is not yet widely available with all
|
||||
compilers. The good news is that Google Test 1.4.0+ implements a
|
||||
subset of TR1 tuple that's enough for Google Mock's need. Google Mock
|
||||
will automatically use that implementation when the compiler doesn't
|
||||
provide TR1 tuple.
|
||||
|
||||
Usually you don't need to care about which tuple library Google Test
|
||||
and Google Mock use. However, if your project already uses TR1 tuple,
|
||||
you need to tell Google Test and Google Mock to use the same TR1 tuple
|
||||
library the rest of your project uses, or the two tuple
|
||||
implementations will clash. To do that, add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=0
|
||||
|
||||
to the compiler flags while compiling Google Test, Google Mock, and
|
||||
your tests. If you want to force Google Test and Google Mock to use
|
||||
their own tuple library, just add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=1
|
||||
|
||||
to the compiler flags instead.
|
||||
|
||||
If you want to use Boost's TR1 tuple library with Google Mock, please
|
||||
refer to the Boost website (http://www.boost.org/) for how to obtain
|
||||
it and set it up.
|
||||
|
||||
### As a Shared Library (DLL) ###
|
||||
|
||||
Google Mock is compact, so most users can build and link it as a static
|
||||
library for the simplicity. Google Mock can be used as a DLL, but the
|
||||
same DLL must contain Google Test as well. See Google Test's README
|
||||
file for instructions on how to set up necessary compiler settings.
|
||||
|
||||
### Tweaking Google Mock ###
|
||||
|
||||
Most of Google Test's control macros apply to Google Mock as well.
|
||||
Please see file ${GTEST_DIR}/README for how to tweak them.
|
||||
|
||||
Upgrading from an Earlier Version
|
||||
---------------------------------
|
||||
|
||||
We strive to keep Google Mock releases backward compatible.
|
||||
Sometimes, though, we have to make some breaking changes for the
|
||||
users' long-term benefits. This section describes what you'll need to
|
||||
do if you are upgrading from an earlier version of Google Mock.
|
||||
|
||||
### Upgrading from 1.1.0 or Earlier ###
|
||||
|
||||
You may need to explicitly enable or disable Google Test's own TR1
|
||||
tuple library. See the instructions in section "Choosing a TR1 Tuple
|
||||
Library".
|
||||
|
||||
### Upgrading from 1.4.0 or Earlier ###
|
||||
|
||||
On platforms where the pthread library is available, Google Test and
|
||||
Google Mock use it in order to be thread-safe. For this to work, you
|
||||
may need to tweak your compiler and/or linker flags. Please see the
|
||||
"Multi-threaded Tests" section in file ${GTEST_DIR}/README for what
|
||||
you may need to do.
|
||||
|
||||
If you have custom matchers defined using MatcherInterface or
|
||||
MakePolymorphicMatcher(), you'll need to update their definitions to
|
||||
use the new matcher API [2]. Matchers defined using MATCHER() or
|
||||
MATCHER_P*() aren't affected.
|
||||
|
||||
[2] http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers,
|
||||
http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers
|
||||
|
||||
Developing Google Mock
|
||||
----------------------
|
||||
|
||||
This section discusses how to make your own changes to Google Mock.
|
||||
|
||||
### Testing Google Mock Itself ###
|
||||
|
||||
To make sure your changes work as intended and don't break existing
|
||||
functionality, you'll want to compile and run Google Test's own tests.
|
||||
For that you'll need Autotools. First, make sure you have followed
|
||||
the instructions in section "SVN Checkout" to configure Google Mock.
|
||||
Then, create a build output directory and enter it. Next,
|
||||
|
||||
${GMOCK_DIR}/configure # Standard GNU configure script, --help for more info
|
||||
|
||||
Once you have successfully configured Google Mock, the build steps are
|
||||
standard for GNU-style OSS packages.
|
||||
|
||||
make # Standard makefile following GNU conventions
|
||||
make check # Builds and runs all tests - all should pass.
|
||||
|
||||
Note that when building your project against Google Mock, you are building
|
||||
against Google Test as well. There is no need to configure Google Test
|
||||
separately.
|
||||
|
||||
### Regenerating Source Files ###
|
||||
|
||||
Some of Google Mock's source files are generated from templates (not
|
||||
in the C++ sense) using a script. A template file is named FOO.pump,
|
||||
where FOO is the name of the file it will generate. For example, the
|
||||
file include/gmock/gmock-generated-actions.h.pump is used to generate
|
||||
gmock-generated-actions.h in the same directory.
|
||||
|
||||
Normally you don't need to worry about regenerating the source files,
|
||||
unless you need to modify them. In that case, you should modify the
|
||||
corresponding .pump files instead and run the 'pump' script (for Pump
|
||||
is Useful for Meta Programming) to regenerate them. You can find
|
||||
pump.py in the ${GTEST_DIR}/scripts/ directory. Read the Pump manual
|
||||
[3] for how to use it.
|
||||
|
||||
[3] http://code.google.com/p/googletest/wiki/PumpManual.
|
||||
|
||||
### Contributing a Patch ###
|
||||
|
||||
We welcome patches. Please read the Google Mock developer's guide [4]
|
||||
for how you can contribute. In particular, make sure you have signed
|
||||
the Contributor License Agreement, or we won't be able to accept the
|
||||
patch.
|
||||
|
||||
[4] http://code.google.com/p/googlemock/wiki/DevGuide
|
||||
|
||||
Happy testing!
|
9799
test/gmock-1.7.0/aclocal.m4
vendored
9799
test/gmock-1.7.0/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user