Compare commits

..

218 Commits

Author SHA1 Message Date
dependabot[bot]
1599d55a3d Bump actions/checkout from 4 to 5 in the github-actions group
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 4 to 5
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 04:21:47 +00:00
Christoph Grüninger
2f86d13775 Update googletest to 1.13
Fix issue with CMake 4.0
2025-04-29 16:53:58 -05:00
Christoph Grüninger
c9371de783 [cmake] Require minimum CMake version 3.5
Soon CMake 4.0 will be released. It requires that projects
set a minimum required CMake version of 3.5. There is a
workaround with an additional flag, but it would is better
to increase the minimum required version.
2025-04-29 16:53:58 -05:00
Salim B
28f93bdec6 docs: Fix link in README 2025-03-13 14:45:33 -05:00
Patrick Diehl
39f737443b Update README.md
Bump the release note to the latest version
2025-01-24 16:01:30 -06:00
Jeremy Nimmer
73ef0060aa Avoid including <iostream> in library code
Including iostream means introducing the static (global) constructors
and destructors for std::cin, std::cerr, and std::cout. That extra
init and fini code is undesirable when those streams are not actually
used.

Instead, we'll use the narrower includes for exactly what's needed,
i.e., <istream> or <ostream>.
2024-12-30 11:27:02 -06:00
Daniel Levin
7470c2d871 emitter: Support std::string_view
Accept Emitter::operator<<(std::string_view).

ABI remains C++11 compatible by exposing new method
Emitter::Write(const char*, size_t).

All affected calls optimized to pass std::string values as pointer + size
tuple into appropriate routines.
2024-12-22 16:22:38 -06:00
Jesse Beder
8a9a7b74ef Update CONTRIBUTING.md
Add some details about testing.
2024-12-22 16:16:07 -06:00
Jesse Beder
d45c4fba3e Update README.md 2024-12-18 11:43:01 -06:00
Jesse Beder
61db89741d Exclude ubuntu/C++ 11/googletest system from the test matrix since it doesn't compile. 2024-12-17 15:59:47 -06:00
Jesse Beder
7def2046ff Fix bazel build, and commit module lock file.
Including:
- Remove WORKSPACE and upgrade to MODULE.bazel.
- The integration tests were not included since the directory was misspelled.
- Their header files were not accessible.
2024-12-17 14:49:17 -06:00
IMaloney
1da813f56a ensuring local tags are retained after loading a node + test 2024-12-17 09:20:46 -06:00
Phil Miller
f878043f12 Don't install embedded copy of GTest
Goole Test itself documents the `INSTALL_GTEST` option as something that projects embedding it should set to `OFF`. Leaving it on means that projects downstream from libraries that embed it are likely to encounter conflicting copies. This is particularly annoying because GTest does not maintain anything like a stable API, and so causes builds to fail if include paths pick up an inappropriately installed copy ahead of the one that the code wanted.

Fixes #488
2024-12-17 09:12:49 -06:00
Simon Gene Gottlieb
9ce5a25188 fix: spell fix 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
ebfbf27115 patch: added more defensive programming techniques 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
06ffaf3104 remove reduntant license information 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
0b945415fd fix: add missing include 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
82f3c04081 fix: add YAML_CPP_API for windows-shared library builds 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
d8de96524c patch: move dragonbox.h from 'include' folder to 'src' folder 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
5d9e4b6251 patch: split fp_to_string.h into fptostring.h and fptostring.cpp 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
28c0a1bc25 doc: add a little more information to dragonbox file 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
72865f7d32 fix: remove trailing return types 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
f4bca79dc4 fix: fp_to_string uses now 2 spaces 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
d4e00bd473 fix: rename fp_to_string to FpToString to match coding style 2024-11-07 15:14:36 -06:00
Simon Gene Gottlieb
bd070a7b76 fix: prettier floating point numbers
Add dragonbox to compute the required precision to print floating point
numbers. This avoids uglification of floating point numbers that
happen by default via std::stringstream.

Numbers like 34.34 used to be converted to '34.340000000000003' as strings.
With this version they will be converted to the string '34.34'.

This fixes issue https://github.com/jbeder/yaml-cpp/issues/1289
2024-11-07 15:14:36 -06:00
Reini Urban
3d2888cc8a missing keys should throw InvalidNode, not BadConversion
Fixes GH #1274
2024-11-01 10:25:39 -05:00
Federico Di Pierro
c2bec4c755 chore(test): moved infiniteloop test to load_node_test suite.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-10-29 22:21:05 -05:00
Federico Di Pierro
29c59c01d4 new(test): added a test to avoid future issues with LoadAll().
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-10-29 22:21:05 -05:00
Federico Di Pierro
bc67157109 fix(src): avoid possible infinite loop in LoadAll().
Leave at first empty root.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-10-29 22:21:05 -05:00
Federico Di Pierro
da82fd982c chore(test/integration): refactor some test cases to their own test.
Plus, check that the content is what we actually expect.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-13 10:18:41 +02:00
Federico Di Pierro
1f2b841949 fix(src,include,test): fixed multiple cases where a bad yaml was accepted.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-09-13 10:18:41 +02:00
Orgad Shaneh
47cd2725d6 Remove build debug messages
They were commented out before 0733aeb45, but when that commit
was reverted in 2b65c65e1 they were recovered uncommented.
2024-08-27 12:23:42 -05:00
Orgad Shaneh
850ec4f39e Fix reference types in iterators
Amends 26faac387c.
2024-08-27 11:12:58 -05:00
Simon Gene Gottlieb
84459a7f98 fix: missing token enum name 2024-08-22 07:55:33 -05:00
Simon Gene Gottlieb
ee9c4d19be fix: parse files with '\r' symbols as line ending correctly 2024-08-22 07:53:52 -05:00
Cristian Le
b38ac5b55f Use FetchContent_MakeAvailable 2024-08-21 12:44:27 -05:00
Christopher Fore
7b469b4220 emitterutils: Explicitly include <cstdint>
GCC 15 will no longer include it by default, resulting in build
failures in projects that do not explicitly include it.

Error:
src/emitterutils.cpp:221:11: error: 'uint16_t' was not declared in this scope
  221 | std::pair<uint16_t, uint16_t> EncodeUTF16SurrogatePair(int codePoint) {
      |           ^~~~~~~~
src/emitterutils.cpp:13:1: note: 'uint16_t' is defined in header '<cstdint>';
this is probably fixable by adding '#include <cstdint>'
   12 | #include "yaml-cpp/null.h"
  +++ |+#include <cstdint>
   13 | #include "yaml-cpp/ostream_wrapper.h"

Tests pass.

Closes: #1307
See-also: https://gcc.gnu.org/pipermail/gcc-cvs/2024-August/407124.html
See-also: https://bugs.gentoo.org/937412
Signed-off-by: Christopher Fore <csfore@posteo.net>
2024-08-18 15:19:15 -05:00
Simon Gene Gottlieb
8fbf344aee doc, fix: invalid liquid '{{...}}' tags
jekyll/liquid got hung up on `{{"Daniel", 26}, {"Jesse", 24}}`.

The reason is that `{{...}}` are used as variables that are replaced by
there values. In this case we have a YAML object that looks the same.
This issue can be fixed by surrounding the block into `{% raw %}...{%
endraw %}` tags.
2024-08-06 10:40:52 -05:00
NameSirius
06c3d1db51 fix compile warning(Pull requests #1305)(Issues #1306) 2024-08-06 10:39:36 -05:00
Jesse Beder
04dddd6999 Revert "Fix compile warning with -Wshadow"
This reverts commit 1f5e971f77.

See #1306; the previous commit caused an error with -Wpedantic:

yaml-cpp/include/yaml-cpp/emitterstyle.h:13:2: error: extra ‘;’ [-Wpedantic]

Since the original commit was to resolve warnings, reverting and the OP can produce a new one that fixes this issue.
2024-08-05 15:50:36 -05:00
NameSirius
1f5e971f77 Fix compile warning with -Wshadow 2024-08-05 09:50:21 -05:00
Josiah VanderZee
b11eaf1631 Run format target from project root
The CMake format target does not use the correct .clang-format file in
out-of-source builds. This instructs CMake to use the project root as
the working directory for running the clang-format command so that it
finds the .clang-format file.
2024-08-02 07:20:10 -05:00
Josiah VanderZee
9f7babc3ff Use c-strings to constant initialize token array
Since `std::string` has to be dynamically constructed and destructed,
it could be accessed before initialization or after destruction in a
multithreaded context. By using constant c-strings instead, we guarantee
that the array will be valid for the whole lifetime of the program. The
use of `constexpr` also enforces this requirement.

I have run clang-format on the file to format my changes according to
CONTRIBUTING.md.
2024-08-01 22:54:57 -05:00
Simon Gene Gottlieb
b95aa146ec fix: use C locale by default 2024-07-17 13:39:30 -05:00
Frank Osterfeld
1d8ca1f35e Avoid static reference to temporary
These caused issues when used in a wasm project.
2024-05-02 09:29:05 -05:00
Humberto Dias
76dc671573 Add option YAML_ENABLE_PIC=ON 2024-02-22 12:12:48 -06:00
Humberto Dias
5c1bbbd276 Skip Position Independent Code for PSP/PS3 2024-02-22 12:12:48 -06:00
dependabot[bot]
4afd53b0d3 Bump the github-actions group with 1 update
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).

- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-28 15:49:18 -06:00
Jason Beach
96f5c887f3 assign fallback value 2024-01-26 13:28:55 -06:00
Alejandro-FA
c67d701ad8 Fix indentation of empty sequences and add test 2024-01-26 12:30:06 -06:00
Trompettesib
9eb1142900 Fix GIT_TAG field in cmake integration example 2024-01-04 09:40:42 -06:00
Alexandre TISSOT
c28295bda4 Add CMake integration example 2024-01-04 09:40:42 -06:00
Levi Armstrong
94710bb221 Add default destructor to EmitFromEvents 2023-12-28 10:44:52 -06:00
Diogo Teles Sant'Anna
c7639e81d5 ci: configure dependabot to montly update GHAs
Signed-off-by: Diogo Teles Sant'Anna <diogoteles@google.com>
2023-12-14 09:13:33 -06:00
Diogo Teles Sant'Anna
f30582fb09 ci: hash-pin sensitive workflow dependency
Signed-off-by: Diogo Teles Sant'Anna <diogoteles@google.com>
2023-12-14 09:13:33 -06:00
Alex Thiessen
eaf7205372 README.md: Describe building with debug libstdc++ mode 2023-11-27 14:29:13 -06:00
Alex Thiessen
1c5a38eef3 workflows/build.yml: Use debug std C++ library on Ubuntu
Protect from regressions due to use of undefined or
implementation-specific behavior when using `std::` containers and smart
pointers.

This only has effect on platforms with the GNU standard C++ library.

Refer to https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html.
2023-11-27 14:29:13 -06:00
Levi Armstrong
51adc5f739 Update yaml-cpp-config.cmake.in 2023-11-06 19:25:04 -06:00
Levi Armstrong
30e6933279 Fix yaml-cpp-config.cmake.in 2023-11-06 19:25:04 -06:00
Gianfranco Costamagna
db03655d58 Make sure CXX_STANDARD can be overridden from outside (#1239) 2023-10-23 07:20:22 -05:00
Gianfranco Costamagna
145eec5f3e Add CMake option YAML_USE_SYSTEM_GTEST to use system googletest if available. (#1035)
There is no need to use the embedded gtest code copy in Linux systems, if they already provide the googletest framework system-wide.
Search for it, and fallback to the embedded one if the system one is not detected.

This patch has been also contributed by Simon Quigley <tsimonq2@debian.org>
2023-10-22 00:06:39 -05:00
Ezekiel Warren
f791b955d8 remove unncessary continue-on-error (#1234) 2023-10-12 19:27:47 -04:00
Ezekiel Warren
4fc5ec36bc automatically create bzlmod archive for release (#1230) 2023-10-12 11:52:22 -04:00
Pete Lewis
8106fcf1e5 Resolve warnings about unreferenced parameter 'style' in NullEventHandlers (#1193) 2023-10-12 11:49:34 -04:00
Pierre Wendling
c26e047223 CMake: Fixes for generated config (#1212)
* CMake: Add option to set the package install dir.

* CMake: Fix generated config.

- `YAML_CPP_SHARED_LIBS_BUILT` should not be set with a `PATH_VAR` as it
would always evaluate to true.
- `YAML_CPP_LIBRARIES` should used the exported target name including
the namespace, but `check_required_components` shouldn't.
- Use `CMAKE_CURRENT_LIST_DIR` to find the target file, instead of a
`PATH_VAR`. Package managers such as vcpkg move CMake configs after
installing.

* CI: Test the generated CMake package.

* CMake: Create add a deprecated yaml-cpp target.

This target is meant to provide compatibility with versions prior to
0.8.0.

* CMake: mark the yaml-cpp target as IMPORTED.

---------

Co-authored-by: Jesse Beder <jbeder+github@gmail.com>
2023-10-12 11:48:16 -04:00
Megamouse
ac144ed46c Hide uninstall target unless YAML_CPP_INSTALL is set, and allow it to be disabled by YAML_CPP_DISABLE_UNINSTALL
add_custom_target uninstall causes a clash with the same target in rtmidi (https://github.com/thestk/rtmidi).
"add_custom_target cannot create target "uninstall" because another target with the same name already exists.  The existing target is a custom target created in source directory"

Adds new option YAML_CPP_DISABLE_UNINSTALL 

fixes #1151

---------

Co-authored-by: Megamouse <studienricky89@googlemail.de>
Co-authored-by: Jesse Beder <jbeder+github@gmail.com>
2023-10-11 00:02:33 -04:00
Alfi Maulana
4c061a5058 Disable format target when not building as the main project (#1231) 2023-10-10 23:40:09 -04:00
Paul Jurczak
37f1b8b8c9 Update How-To-Emit-YAML.md (#976) 2023-09-21 15:38:56 -05:00
FireWolf
d046eea331 node/convert: Enable the template specialization for std::string_view properly when the library is compiled by MSVC on Windows. (#1227) 2023-09-17 11:58:31 -04:00
Daniel Stonier
9f31491b0f bzlmodded (#1224) 2023-09-17 11:57:52 -04:00
Kefu Chai
016b2e7769 CI: test with supported C++ standards (#1226)
* CI: test with supported C++ standards

let's test with the supported standards for better coverage.
C++23 standard was just out, but the support on the toolchain is
not quite ready yet. so let's leave it for a future change.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>

* CI: drop redundant Build step

"Build Tests" is strictly a superset of "Build". in addition to
the library, the former builds the tests also. both these
steps share the same set of command line arguments. by removing
"Build" step, we don't lose anything regarding the test coverage
and information for further investigation if the build fails.

Signed-off-by: Kefu Chai <tchaikov@gmail.com>

---------

Signed-off-by: Kefu Chai <tchaikov@gmail.com>
2023-09-10 08:38:51 -04:00
Kefu Chai
2383e6d0f2 Revert "node/convert: relax the check for string_view (#1222)" (#1225)
This reverts commit 6262201182.

in 62622011, we wanted address the needs to use the `string_view`
converter in C++98, but that requirement was based on wrong
preconditions. `std::string_view` was introduced in C++17, and
popular standard libraries like libstdc++ and libc++ both provide
`std::string_view` when the source is built with C++17.

furthermore 62622011 is buggy. because it uses `<version>` to tell
the feature set provided by the standard library. but `<version>`
is a part of C++20. so this defeats the purpose of the change of
62622011.

Fixes #1223
2023-09-10 08:28:52 -04:00
Kefu Chai
6262201182 node/convert: relax the check for string_view (#1222) 2023-09-06 07:57:12 -05:00
Gianfranco Costamagna
fcbb8193b9 Fix testsuite with gcc-13 (#1216)
cd /<<PKGBUILDDIR>>/build-static/test && /usr/bin/c++ -DYAML_CPP_STATIC_DEFINE -I/<<PKGBUILDDIR>>/test/integration -I/<<PKGBUILDDIR>>/test -I/<<PKGBUILDDIR>>/src -I/<<PKGBUILDDIR>>/include -isystem /usr/src/googletest/googlemock/include -isystem /usr/src/googletest/googlemock -isystem /usr/src/googletest/googletest/include -isystem /usr/src/googletest/googletest -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fdebug-prefix-map=/<<PKGBUILDDIR>>=/usr/src/yaml-cpp-0.8.0+dfsg-1~build1 -Wdate-time -D_FORTIFY_SOURCE=2 -std=gnu++14 -Wno-variadic-macros -Wno-sign-compare -DGTEST_HAS_PTHREAD=1 -MD -MT test/CMakeFiles/yaml-cpp-tests.dir/binary_test.cpp.o -MF CMakeFiles/yaml-cpp-tests.dir/binary_test.cpp.o.d -o CMakeFiles/yaml-cpp-tests.dir/binary_test.cpp.o -c /<<PKGBUILDDIR>>/test/binary_test.cpp
/<<PKGBUILDDIR>>/test/binary_test.cpp: In member function ‘virtual void BinaryTest_DecodingNoCrashOnNegative_Test::TestBody()’:
/<<PKGBUILDDIR>>/test/binary_test.cpp:11:38: error: narrowing conversion of ‘-58’ from ‘int’ to ‘char’ [-Wnarrowing]
   11 |   std::string input{-58, -1, -99, 109};
      |                                      ^
2023-08-19 15:36:16 -04:00
Craig Scott
c268020048 Specify CMake policy range to avoid deprecation warning (#1211) 2023-08-16 17:54:05 -05:00
Jesse Beder
f732014112 Bump version to 0.8.0. 2023-08-10 14:27:56 -05:00
Diogo Teles Sant'Anna
f6c8b17c3a Create Security-Policy (#1189) 2023-08-10 15:02:27 -04:00
Kefu Chai
35b4498026 node/convert: support conversion for std::string_view (#1148) 2023-07-24 14:51:05 -05:00
Ryan
b8882652fc Add namespace for the exported targets (#1196)
This matches the name for the ALIAS targets, and fixes #1025.
2023-06-28 11:37:09 -05:00
Jesse Beder
0e6e28d1a3 Revert "Move CTest to test entry (#1181)" (#1182)
This reverts commit 74f63c1181.
2023-03-22 19:14:49 -05:00
Jelin
74f63c1181 Move CTest to test entry (#1181) 2023-03-21 11:24:19 -05:00
Matthijs van der Burgh
987a604256 Delete .travis.yml (#1177) 2023-03-04 16:18:51 -06:00
Matthijs van der Burgh
55a8037daa (appveyor) remove, because testing windows in GH actions (#1176) 2023-03-04 14:07:09 -06:00
Matthijs van der Burgh
3ff7ab07ac Make sure tests are run in CI (#1170)
* Test(CMake) set NAME and COMMAND in add_test

* (CMake) add enable_testing()

* (CMake) move cmake_dependent_option up, before using them

* (CMake) use YAML_CPP_MAIN_PROJECT in cmake_dependent_option

* (CMake) log values regarding tests

* (CMake) always find CTest, but don't enable tests

* (CMAKE)(temp) fix logging

* (actions) set YAML_CPP_BUILD_TESTS for tests

* (actions) provide YAML_CPP_BUILD_TESTS to ctest

* (actions) set -DYAML_CPP_BUILD_TESTS at build

* (actions) don't fail false

* (actions) build tests in Test step

* (actions) run tests verbose

* (CMake) remove temp logging

* (actions) split building from running tests

* (actions) ctest Debug

* (actions) ctest Debug

* Remove enable_testing
2023-03-04 14:06:01 -06:00
Diogo Teles Sant'Anna
d7f672d141 CI: define read-only permission for GitHub Workflow (#1175)
It secures the repo against erroneous or malicious actions from external jobs you call from your workflow. It's specially important for the case they get compromised, for example.
2023-03-03 23:33:51 -06:00
Matthijs van der Burgh
bdc5582b35 Add tests for iterator and const_iterator on sequence (#1169) 2023-03-01 19:27:51 -06:00
James Brown
1b50109f7b Include property nodes in the long key check (#1140) 2022-10-04 18:51:53 -05:00
sfalmo
4ae4cb7309 Support conversion for std::valarray (#956) 2022-09-20 00:31:51 -05:00
Derzsi Dániel
97ebcf035a Export library directory and shared libs to CMake config (#1113)
This pull request adds two new exported variables to the CMake config:

YAML_CPP_LIBRARY_DIR - points to the directory containing the built library files
YAML_CPP_SHARED_LIBS_BUILT - boolean value, lets users know whether shared libraries were built or not
2022-09-20 00:26:59 -05:00
stephematician
85ad599d79 Basic update to CMakeLists.txt to address #1116 (#1117)
Add definitions to static yaml-cpp target (fixes #1116)

Also updates CONTRIBUTING instructions for tests
2022-09-20 00:24:35 -05:00
Baruch
c86a9e424c Minimize warnings when not the top-level project (#1124)
Minimize warnings when not the top-level project

Should fix #970 and #764 when trying to add yaml-cpp to other project
2022-09-20 00:22:11 -05:00
Timo Gurr
255bf1f9bc Install pkgconfig and cmake files into arch-dependent locations (#1055) 2022-09-20 00:17:13 -05:00
rdzehtsiar
763b7d6c70 Fix compilation errors in build for Oracle Solaris OS (#1133)
On Oracle Solaris the following statement is declared in file /usr/include/sys/regset.h:
#define SS 18 /* only stored on a privilege transition */

Because of this template type name SS is substituted by numeric literal, which results in a compilation error:
error: expected nested-name-specifier before numeric constant

Fixed by renaming template type names.

Co-authored-by: Roman Degtyar <Roman.Degtyar@veeam.com>
2022-09-20 00:04:18 -05:00
Skywol
e87ed7e5b1 Add the "make uninstall" target (#1130) 2022-09-20 00:03:40 -05:00
Igor [hyperxor]
c73ee34704 Small perfomance optimization in Directives and Tag methods (#1112) 2022-05-31 18:05:22 -05:00
Igor [hyperxor]
190ad502b5 Remove redundant include (#1110) 2022-05-21 07:20:18 -05:00
Dr. Andre Vehreschild
420c982310 Improve bazel build for Windows. (#1100)
Windows builds need some defines being set to use the static linking.

Also add bazel builds and test to Github-CI.
2022-04-27 09:10:13 -05:00
Dr. Andre Vehreschild
13626af92a Fix escaping anchors in keys (#1101) 2022-04-21 08:19:51 -05:00
Dr. Andre Vehreschild
4c982d59dc Improve build and fix single cr on windows (#1099) 2022-04-19 12:39:55 -05:00
SpaceIm
7d06655611 Allow yaml-cpp to be installed from another project (#1007)
Changes YAML_CPP_INSTALL from a cmake_dependent_option to an option.

Fixes #756, #847, and #1011.
2022-04-03 16:57:28 -05:00
xiaozhuai, Weihang Ding
0e6e98e8fb Extend options that disable testing and formatting to looking for dependencies also. (#1039)
The option `YAML_CPP_BUILD_TESTS` currently enables or disables building of tests; but unconditionally the CMake file includes CTest; this PR makes that conditional on the option.

Also, there is no option for enabling formatting, but it does check whether it can find the `clang-format` executable; this PR adds an option (default to true) that skips even looking for the executable if disabled.
2022-03-31 22:36:43 -05:00
Felix Schwitzer
4aad2b1666 Fix CMake export files (#1077)
After configuring the file `yaml-cpp-config.cmake.in`, the result ends up with
empty variables.  (see also the discussion in #774).

Rework this file and the call to `configure_package_config_file` according the
cmake documentation
(https://cmake.org/cmake/help/v3.22/module/CMakePackageConfigHelpers.html?highlight=configure_package_config#command:configure_package_config_file)
to overcome this issue and allow a simple `find_package` after install.

As there was some discussion about the place where to install the
`yaml-cpp-config.cmake` file, e.g. #1055, factor out the install location into
an extra variable to make it easier changing this location in the future.

Also untabify CMakeLists.txt in some places to align with the other code parts in this file.
2022-03-31 22:26:47 -05:00
Dr. Andre Vehreschild
a6db7e32ac Fix single cr not recognized (#1094)
Complies with YAML Standard [5.4](https://yaml.org/spec/1.2.2/#54-line-break-characters) [25] instead of matching `\r` only in combination with `\n`.
2022-03-31 22:16:35 -05:00
Michael Martz
669af4eb55 Make YAML_MSVC_SHARED_RT depend on "CMAKE_SYSTEM_NAME MATCHES Windows" instead of "MSVC".
Fixes issue #1053.
2022-03-31 22:13:19 -05:00
Akash Patel
edadfecdc6 Update gtest to 1.11.0 (#1086)
Properly resolves #1083, #996.
2022-02-17 12:08:56 -06:00
Sam4uk
26e3b70407 Update old style cast from (T) to static_cast<T>. 2022-02-08 16:06:36 -06:00
Christian Rauch
cdf89fa352 set POSITION_INDEPENDENT_CODE if BUILD_SHARED_LIBS=OFF (#1076) 2022-01-27 17:03:10 -06:00
TheVice
f8e1a7be3b Add MinGW to build pipeline
Also refactor the build action to use a matrix.
2022-01-27 17:00:08 -06:00
Chen
bce601f2bf Support the conversion for std::unordered_map (#932) 2022-01-05 18:12:40 -06:00
TheVice
d8d9419092 Fix shared library tests for Windows (#1074)
Add copying of shared library to the output directory with a test binary.

[binary] removed using of non unsigned char as argument at
'std::isspace' function that was provokes undefined behavior.

[.github/workflows/build.yml] enabled run of test at the
'windows-latest' environment.
2021-12-15 13:38:09 -06:00
Jesse Beder
974349d015 Fix typo in README about building shared libraries. 2021-12-10 08:54:35 -06:00
Jesse Beder
5057a53293 Fix github actions badge. 2021-11-22 22:44:31 -06:00
Jesse Beder
634578e477 Add github actions badge to README
This replaces the old Travis CI badge that didn't mean anything.
2021-11-22 22:42:51 -06:00
Pavel Karelin
2b65c65e1b Partially revert commit 0733aeb4 to make dll.h a non-generated file (#1064)
Partial revert of "Revert "Revert "Hide most of non-public symbols by default (#984)" (#1038)" (#1045)"

This reverts commit 0733aeb451.
2021-11-22 22:40:08 -06:00
Ryan Burns
328d2d85e8 Fix .pc paths for absolute GNUInstallDirs (#1058)
GNUInstallDirs provided may be absolute paths, in which case appending
to the install prefix is not correct. We can instead use the provided
CMAKE_INSTALL_FULL_* variables, which are precomputed absolute paths.

https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html
2021-11-02 21:34:46 -05:00
PhilipDeegan
4564d9a131 github actions for mac/linux/windows (#1056) 2021-10-31 11:59:40 -05:00
Robert Sebastian Herlim
2f8997565b Use static_cast<unsigned char> on DecodeBase64 to prevent SEGV on negative values (#1051) 2021-10-20 10:18:08 -05:00
Michał Janiszewski
1713859b05 Remove unused code from parse util (#1048) 2021-10-13 15:56:11 -05:00
João Marcos Bezerra
393a02a225 README.md revision (#732) 2021-10-09 22:02:35 -05:00
Pino Toscano
0733aeb451 Revert "Revert "Hide most of non-public symbols by default (#984)" (#1038)" (#1045) 2021-10-09 21:48:05 -05:00
Jesse Beder
0d9dbcfe8c Revert "Hide most of non-public symbols by default (#984)" (#1038)
This reverts commit da1c8d360e. and fixes #1036.
2021-09-28 08:41:55 -05:00
Pino Toscano
da1c8d360e Hide most of non-public symbols by default (#984)
* Export YAML::detail::node::m_amount

The internal header node/detail/node.h is included by public headers;
YAML::detail::node is implemented in the header itself, and thus it gets
inlined... except for its static m_amount class member, which is
instantiated in the library only. Right now all the symbols of yaml-cpp
are exported (nothing is hidden), so the linker will find node::m_amount
in the yaml-cpp library.

As solution/workaround, explicitly export YAML::detail::node::m_amount.

* CMake: use GenerateExportHeader

Make use of the GenerateExportHeader CMake module to generate the dll.h
header with export macros.

While the produced dll.h is different, the result should be the same,
i.e. nothing changes for yaml-cpp or its users.

* CMake: hide all the symbols by default

Hide all the symbols that are not explicitly exported with YAML_CPP_API.
This way the ABI will be way smaller, and only actually exposing the
public classes/functions.
2021-09-25 12:10:58 -05:00
jwindgassen
6308112e54 Added UE-Wrapper link to Readme (#1024) 2021-08-30 06:11:08 -05:00
Snow Pettersen
db6deedcd3 Include name of anchor in invalid anchor error (#1015) 2021-07-23 14:52:21 -05:00
mjvankampen
79aa6d53e5 Add assert to enable compilation with libcxx + gcc (#947) 2021-07-15 16:09:05 -05:00
jbeach
ef0bba178d Bump minimum cmake versions in gtest to eliminate cmake deprecation warnings. (#1012) 2021-07-15 16:08:00 -05:00
JBPennington
b591d8ae2a Update node impl.h for GCC unused variable warning (#981)
Removed the variable name in the defaulted function to make GCC happy.
2021-07-10 11:07:12 -05:00
Jesse Beder
0579ae3d97 Update version to 0.7.0. 2021-07-10 10:53:22 -05:00
theamarin
9ee3928754 Prevent trailing spaces when emitting literal strings (#1005) 2021-07-04 22:30:04 -05:00
t.t
a6bbe0e50a fix warning of level 4: (#971)
convert.h line130 : warning C4244 conversation from int to T possible loss of data
2021-01-05 07:40:28 -06:00
Chen
98acc5a887 Emit the correct Alias on the key (#908) (#929) 2020-07-27 13:49:04 -05:00
Chen
1c9abc8fa4 fix issue743: handle the empty content of flow sep/map correctly during emitting. (#921)
* fix issue743: handle the empty content of flow sep/map correctly during emitting.

* handle the empty Tag/Anchor properly.

* delete comment
2020-07-24 07:28:40 -05:00
Chen
11917babc7 Add the AppVeyor configuration file (#927) 2020-07-23 23:04:02 -05:00
Chen
c2793a36d5 Fix runtime exceptions in Visual Studio environment. (#926) 2020-07-23 08:48:20 -05:00
Kajetan Świerk
bc9874c9ff Reduce std::string copies (#924)
- Don't eagerly convert key to std::string
- Make const char* keys streamable when exception is thrown
- Don't create a temporary string when comparing a const char* key
2020-07-23 08:47:21 -05:00
Kajetan Świerk
06b99f53db Default initialize node's member variable (#923) 2020-07-18 19:34:46 -05:00
Chen
c3df6d87d4 Properly allow a trailing tab character on a block scalar (#919)
Fixes #917
2020-07-16 10:08:09 -05:00
Chen
51ce663085 Handle a key with length over 1024 as a long key. (#916)
Fixes #501
2020-07-16 09:51:54 -05:00
Chen
33315286ab Add the support to parsing a null value as std::string.
Fixes #590.
2020-07-16 09:15:39 -05:00
Pavel Karelin
4571e8177a Fix compilation for Qt-projects (#918)
Not use 'emit' as variable name, in Qt Framework it reserved word
2020-07-14 07:44:08 -05:00
Oliver Hamlet
c82d3129dd Add support for JSON-compatible string escapes (#485)
For completeness I've implemented escaping for characters outside the
basic multilingual plane, but it doesn't get used (as there's no
EscapeAsAsciiJson emitter option implemented).
2020-07-13 21:16:34 -05:00
Tom Collins
370aceeaf8 Enable CMP0091 to use MSVC_RUNTIME_LIBRARY (#913)
Per https://cmake.org/cmake/help/latest/policy/CMP0091.html, we need to
enable policy CMP0091 if we want to make use of MSVC_RUNTIME_LIBRARY
and/or CMAKE_MSVC_RUNTIME_LIBRARY.  Fixes issue #912.
2020-07-07 20:38:10 -05:00
Chen
6d5cfab5fd fix bug from issue298:Emitter stylings settings overridden by node settings. (#915) 2020-07-06 08:16:38 -05:00
Chen
026a53fbe1 Parse colon in plain scalar correctly when in a flow collection
Fixes #740.
2020-07-02 14:08:14 -05:00
Raffaello Bertini
1c2e767347 Fix YAML::Newline in a sequence or map.
Inside of a sequence or map, `YAML::Newline` wouldn't reset the collection state, which would cause behavior like this:

```
nodeA:   
    k: [{i: 0},
 {i:1},
  ]NodeB:
    k: [{i: 0},
 {i:1},
  ]
```
2020-07-01 22:31:51 -05:00
Chen
3f381f13a0 remove the wrong swap file. (#907) 2020-06-29 08:19:35 -05:00
Chen
08aa252611 Support kinds of emitter format-setting for YAML::Null. (#906)
* Support kinds of emitter format-setting for YAML::Null.

* update the code and test cases

* add the comment //fallthrough
2020-06-28 23:31:53 -05:00
Dekken
27d8a0e302 Refactor to allow MSVC without #define NOMINMAX (#905) 2020-06-27 20:28:24 -05:00
Dekken
97d1ae547c rm unusued typedef (#901) 2020-06-21 07:58:16 -05:00
Chen
5a9ab177ba tag_null (#897) 2020-06-17 12:49:09 -05:00
Chen
72fe73a104 fix issue752: generate right long keys (#879)
* fix issue752: generate right long keys

* Improve the readability of test cases

* update to raw string literal
2020-06-17 00:57:28 -05:00
Rosen Penev
a7a7908dc5 [clang-tidy] use auto (#888)
Found with modernize-use-auto

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-16 10:22:14 -05:00
Rosen Penev
0b0bf35c48 [clang-tidy] convert several functions to use references (#894)
Found with performance-unnecessary-value-param

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 17:34:27 -05:00
Rosen Penev
dbb385bdf5 [clang-tidy] use empty method (#895)
Found with readability-container-size-empty

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 17:23:40 -05:00
Rosen Penev
b2cd008717 partially fix clang compilation (#893)
* partially fix clang compilation

Missing header and mistaken algorithm usage.

Also removed it name from range loops. It's not correct.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* run through clang's -Wrange-loop-analysis

Some range loops should not use references as they need to copy.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* manual range loop conversions

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 16:59:27 -05:00
Rosen Penev
6387cbc0ca [clang-tidy] use braced initialization list (#883)
Found with modernize-return-braced-init-list

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:41:14 -05:00
Rosen Penev
1bf9540a7d [clang-tidy] fix inconsistent declaration (#884)
Found with readability-inconsistent-declaration-parameter-name

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:39:04 -05:00
Rosen Penev
4c90f2962e [clang-tidy] use bool literals (#881)
Found with modernize-use-bool-literals

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:30:37 -05:00
Rosen Penev
4f6d0733c9 [clang-tidy] use raw strings for easier readability (#882)
Found with modernize-raw-string-literal

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:29:38 -05:00
Rosen Penev
f05947ae59 [clang-tidy] use emplace_back (#880)
Found with modernize-use-emplace

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:28:19 -05:00
Rosen Penev
66171449d4 [clang-tidy] replace typedef with using (#886)
Found with modernize-use-using

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:27:08 -05:00
Rosen Penev
33c9f6e062 [clang-tidy] use override (#885)
Found with modernize-use-override

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:20:22 -05:00
Rosen Penev
7e4f290ef9 [clang-tidy] use = default (#887)
Found with modernize-use-equals-default

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:19:21 -05:00
Rosen Penev
ae811c3d86 [clang-tidy] convert to range loops (#889)
Found with modernize-loop-convert

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:17:50 -05:00
Rosen Penev
41001d1bf9 manual algorithm conversions (#891)
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:10:09 -05:00
Rosen Penev
a808c1f44a [clang-tidy] do not use return after else (#892)
Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-06-15 15:09:29 -05:00
Chen
4dbfeb0bbc Support as<uint8_t>/as<int8_t>.
Fix issue 844/848.
2020-06-15 10:31:59 -05:00
Chen
33316d531b Add tests for some interfaces of emitter (#875) 2020-05-31 09:16:16 -05:00
Josh Soref
6701275f19 Spelling (#870)
* spelling: differently

* spelling: irrelevant

* spelling: specified
2020-05-25 09:30:55 -05:00
Hans-Peter Gygax
cb7bb9821d Change CMakeLists to honor option "MSVC shared Runtimes" (#867) 2020-05-24 12:55:52 -05:00
Raúl Gutiérrez Segalés
f05b2577ad Fix crash when parsing {x: (#865) 2020-05-23 12:17:20 -05:00
Chen
d9c35b6079 Throw an exception when trying to parse a negative number as an unsigned.
Fixing issue 859.
2020-05-19 11:48:22 -05:00
Chen
4b98aedc16 Supplement test cases for 2.19 ~ 2.22 schema tags. (#857)
Add test cases for the event handler for schema tags; does not include test cases for Node because specialized tag handling is not implemented yet.
2020-05-12 13:20:45 -05:00
Ted Lyngmo
a98b8af448 Add filename to the BadFile exception (#858)
The BadFile exception which is thrown when failing to open a file now
contains the filename.
2020-05-07 14:46:28 -05:00
Ian Taylor
9fb5153487 implement convert for standard library containers allowing for custom allocators (#855) 2020-04-29 18:29:33 -05:00
deflinhec
513ee81fbf Make debug postfix optional (#856)
Library debug postfix might not be suitable for cross platform project, and usually require extra work of link against prebuilt yaml-cpp.

Generally, Xcode project output library to these directories:
    Debug
    Release
    Debug-iphoneos
    Release-iphoneos
    Debug-iphonesimulator
    Release-iphonesimulator

Another Xcode project usually configured its build setting as follow, and expects library name to be same between Release and Debug
    LIBRARY_SEARCH_PATHS=$(CONFIGURATION)$(EFFECT_PLATFORM_NAME)
    OTHER_LDFLAGS= $(inherited) -lyaml-cpp
2020-04-29 09:58:05 -05:00
Ian Taylor
9f2781b527 Fix clang format (#854)
Fix invocation of clang-format in CMakeLists and apply clang-format.
2020-04-29 09:40:33 -05:00
Martin Delille
7083db28b3 Add Qt wrapper gist (#853)
Add Qt wrapper gist to README as a third party contribution
2020-04-26 16:53:02 -05:00
Jesse Beder
2f00649291 Set theme jekyll-theme-slate 2020-04-24 14:22:43 -05:00
Martin Delille
b35f2a86a6 Rename "Home" to "index" in the doc (#851)
This will allow hosting as Github Pages.
2020-04-24 14:21:17 -05:00
Martin Delille
99222fc938 Include wiki content into a doc folder (#850)
* Copied Tutorial from Google Code wiki.

* Initial Home page

* Copied How To Parse A Document from Google Code wiki

* Updated How To Parse A Document (markdown)

* Updated How To Parse A Document (markdown)

* Updated How To Parse A Document (Old API) (markdown)

* Copied How To Emit YAML from Google Code wiki

* Copied Breaking Changes from Google Code wiki

* Copied Strings from Google Code wiki

* Updated Strings (markdown)

* Updated Home (markdown)

* Fix typo.

* Updated Breaking Changes (markdown)

* Updated How To Parse A Document (Old API) (markdown)

* Updated Breaking Changes (markdown)

* Move wiki content to docs/

* Improve markdown and add colored code syntax

Co-authored-by: Jesse Beder <jbeder+github@gmail.com>
2020-04-23 15:08:27 -05:00
Alan Griffiths
4edff1fa5d Fix stack overflow (#807)
Fix stack overflow in HandleNode by explicitly limiting the depth of recursion.
2020-04-09 13:02:10 -05:00
Tindy X
70205f5d88 Fix 'comparison object must be invocable as const' (#846) 2020-04-09 09:38:02 -05:00
Jesse Beder
9b8f35093e Update travis config to use updated versions of OS and compilers. (#845)
This fixes the linux/gcc error building Google Test with gcc 4.7:

https://travis-ci.org/github/jbeder/yaml-cpp/jobs/668233706
2020-04-07 22:46:47 -05:00
Ted Lyngmo
1d8542ad32 Add NodeTest EqualRepresentationAfterMoveAssignment (#816)
Add check that a move assigned Node gets the same representation as the
moved-from Node had before the move.
2020-04-07 20:08:56 -05:00
Maxim Okhotskiy
6f7ead5171 Maintain order of nodes in sequences (#668) 2020-04-07 11:46:34 -05:00
Victor Mataré
cf93f4c57b Pass a mark to BadSubscript exception (#843)
It's clearly related to an existing node, so it can have a mark and give
an error location.
2020-04-07 11:33:16 -05:00
Romain Deterre
26faac387c Remove uses of std::iterator (deprecated in C++17) (#839) 2020-03-29 17:53:55 -05:00
Romain Deterre
120863ba5a Update Google Test to v1.10.0 (#840)
This commit updates the version of Google Test from 1.8 to 1.10.
2020-03-28 19:53:13 -05:00
Dekken
b2f89386d8 Split conversion call that uses std::signbit with unsupported parameters with enable_if (#824) 2020-03-11 08:59:16 -05:00
Néstor Subirón
1bfbd2be4c Allow including yaml-cpp as system headers (#829) 2020-02-29 22:27:16 -06:00
Anton Onishchenko
de8253fcb0 Fix storing inf and NaN (#817) 2020-02-14 18:03:21 -06:00
JeffWegher
29dcf92f87 Fix Node::size() after removing node from sequence (#820) 2020-02-14 14:38:58 -06:00
Ted Lyngmo
ce056acab7 Add IsNull() check in test after reassignment (#814) 2020-02-07 10:52:43 -06:00
Ted Lyngmo
9ab22ef493 Make SettingChange and StreamCharSourcemove constructors and assignment operators noexcept (#808)
The explicitly defaulted or implemented move constructors and assignment
operators are made "noexcept".

Bugfix:
* src/stream.cpp Stream::Stream() char_traits::int_type intro[4] is
  now aggregate-initialized (to zero) to avoid UB.

Minor changes:
* Using std::isinf() and std::signbit() instead of comparing for
  equality with infinity.
* src/streamcharsource.h: Added #include "stream.h".
* src/stream.h: Forward declaring "class StreamCharSource".
* Some implicit casting changed into static_cast's.

Signed-off-by: Ted Lyngmo <ted@lyncon.se>
2020-02-04 16:58:00 -06:00
Ted Lyngmo
1928bca4a4 Move the YAML_CPP_NOEXCEPT macro to include/yaml-cpp/noexcept.h (#813)
This is in preparation for other patches that will make use of the
macro. The patch also removes #undef:ing the macro after its been
used to not make the header inclusion order critical. Otherwise,
the new header would always have to be the last of the yaml-cpp
headers to be included.
2020-02-04 13:24:37 -06:00
Jesse Beder
c9460110e0 Fix reading empty token stack with a node with properties but no scalar.
E.g. `!2`.
2020-01-20 18:16:08 -06:00
Ted Lyngmo
3dca8668b1 Change NULL to nullptr (#805) 2020-01-20 17:14:55 -06:00
Carlos Gomes Martinho
587b24e2ee Use de-facto standard CMake namespace convention (#792)
Change the namespace from yaml::yaml to yaml-cpp::yaml-cpp.
2019-11-29 17:02:21 -06:00
Igor [hyperxor]
5b3e30bfe9 Small readability improvements in Parser
Also add a test for a parser with no data
2019-11-23 13:17:02 -06:00
Igor [hyperxor]
72f699f5ce Remove redundant checks and add more unit tests (#783) 2019-11-04 10:19:02 -06:00
Mike Egger
a8ba6a8dca Adapt label postfix to fix build with Visual Studio (#782) 2019-10-31 09:35:12 -05:00
Romain Geissler @ Amadeus
14c87258cd Fix -Wmisleading-indentation warning when using gcc >= 6. (#779)
This happens whenever in a macro you use some "if" block, and don't use curly braces {},
as the macro is expanded on a single line, not on several lines. So just add the missing
curly braces to please gcc.

In file included from /remote/users/mlamesch/CloneFromPlatinum/yamlcpp/osp/Yamlcpp/18-0-0-5/include/yaml-cpp/yaml.h:18,
                 from src/TestYaml.cpp:2:
/remote/users/mlamesch/CloneFromPlatinum/yamlcpp/osp/Yamlcpp/18-0-0-5/include/yaml-cpp/node/convert.h: In static member function static bool YAML::convert<int>::decode(const YAML::Node&, int&):
/remote/users/mlamesch/CloneFromPlatinum/yamlcpp/osp/Yamlcpp/18-0-0-5/include/yaml-cpp/node/convert.h:139:1: error: this if clause does not guard... [-Werror=misleading-indentation]
 YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int);
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-10-23 14:45:27 -05:00
carmeli-tamir
f531f8a8c3 Show test output on CI in Travis (#777)
* Showing test output only on failure

* Test commit to see the failed test

* Now making sure that the tests pass with no output
2019-10-16 09:44:33 -05:00
Isabella Muerte
52a1378e48 Default YAML_BUILD_SHARED_LIBS to BUILD_SHARED_LIBS
🐛 Fixes #748 (#770)
2019-10-13 15:50:40 -05:00
Rasmus
c9a0077024 Add documentation to readme (#768) 2019-10-11 08:12:48 -05:00
Andy Maloney
b650bc8287 Modernize: Use range-based for loops for readability (#762)
Also run clang-format on these files as requested
2019-10-05 14:20:17 -05:00
Fatih YAZICI
21d75fa4cd Fix CMake 3.10 and below compatibility (#763)
Add empty list of sources to add_library and add_executable.
2019-10-04 14:46:18 -05:00
Andy Maloney
848091124d Replace node's YAML_CPP_OPERATOR_BOOL macro with an explicit bool operator (#755) 2019-10-02 14:14:07 -05:00
Andy Maloney
6e87b37034 Modernize: Use "using" instead of "typedef" (#754) 2019-10-02 11:14:49 -05:00
Andy Maloney
0fddd1e5bd Modernization: Use "override" when overriding base class methods (#753) 2019-10-02 09:21:17 -05:00
Andy Maloney
99d95d8edc Pass std::string by const ref (#749) 2019-10-02 08:39:41 -05:00
Andy Maloney
a6ed66abca Modernize: Use "default" for destructors and copy constructors (#751) 2019-10-02 08:38:49 -05:00
Andy Maloney
e6b3a92e67 Use cassert instead of old assert.h (#750) 2019-10-02 08:37:38 -05:00
Andy Maloney
47d32aadf0 CMake: Remove unused option YAML_APPLE_UNIVERSAL_BIN (#744) 2019-09-27 12:26:35 -05:00
Isabella Muerte
9d7e556ed5 Fix DEBUG_POSTFIX property (#746)
The generator expressions here are actually unnecessary, now that I think about it.

This should fix #745
2019-09-27 12:25:27 -05:00
Ezekiel Warren
62ff351432 Add bazel Support (#724)
Example of how someone might consume yaml-cpp with bazel:

cc_binary(
    name = "example",
    srcs = ["example.cc"],
    deps = ["@com_github_jbeder_yaml_cpp//:yaml-cpp"],
)
2019-09-27 10:11:38 -05:00
Isabella Muerte
5e9cb0128d Refactor CMake to use more modern paradigms (#741)
Remove 2.6-isms
Remove 2.8-isms
Bump CMake minimum version to 3.4

Disable some options when used as a subdirectory

Use `CONFIGURE_DEPENDS` with `file(GLOB)` when possible

Backport CMake 3.15's MSVC_RUNTIME_LIBRARY setting.
Set all compile options as generator expressions.
Set all find-package files to be installed to the correct file.

Remove `export(PACKAGE)`, as this has been deprecated.
Remove fat binary support
Remove manual setting of iPhone settings. These should be set by parent
projects.
Remove use of ExternalProject for a local use
Conditionally remove format target unless clang-format is found
2019-09-27 09:59:53 -05:00
553 changed files with 78988 additions and 115270 deletions

1
.bazelignore Normal file
View File

@@ -0,0 +1 @@
test/googletest-1.13.0

View File

@@ -8,7 +8,7 @@ EXAMPLE_PATH =
# One or more directories and files to exclude from documentation generation. # One or more directories and files to exclude from documentation generation.
# Use relative paths with respect to the repository root directory. # Use relative paths with respect to the repository root directory.
EXCLUDE = test/gtest-1.8.0/ EXCLUDE = test/googletest-1.13.0/
# One or more wildcard patterns to exclude files and directories from document # One or more wildcard patterns to exclude files and directories from document
# generation. # generation.

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
groups:
github-actions:
patterns:
- "*"

141
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,141 @@
name: Github PR
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
permissions: read-all
defaults:
run:
shell: bash
jobs:
cmake-build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
cxx_standard: [11, 17, 20]
build: [static, shared]
googletest: [build, system]
generator: ["Default Generator", "MinGW Makefiles"]
exclude:
- os: ubuntu-latest
cxx_standard: 11
googletest: system
- os: macos-latest
build: shared
- os: macos-latest
generator: "MinGW Makefiles"
- os: ubuntu-latest
generator: "MinGW Makefiles"
- os: macos-latest
googletest: system
- os: windows-latest
googletest: system
env:
YAML_BUILD_SHARED_LIBS: ${{ matrix.build == 'shared' && 'ON' || 'OFF' }}
YAML_USE_SYSTEM_GTEST: ${{ matrix.googletest == 'system' && 'ON' || 'OFF' }}
CMAKE_GENERATOR: >-
${{format(matrix.generator != 'Default Generator' && '-G "{0}"' || '', matrix.generator)}}
CMAKE_INSTALL_PREFIX: "${{ github.workspace }}/install-prefix"
CMAKE_BUILD_TYPE: Debug
CMAKE_CXX_FLAGS_DEBUG: ${{ matrix.googletest == 'build' && '-g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC' || '-g' }}
runs-on: ${{ matrix.os }}
steps:
- uses: awalsh128/cache-apt-pkgs-action@latest
if: matrix.os == 'ubuntu-latest'
with:
packages: googletest libgmock-dev libgtest-dev
version: 1.0
- uses: actions/checkout@v5
- name: Configure
run: |
cmake \
${{ env.CMAKE_GENERATOR }} \
-S "${{ github.workspace }}" \
-B build \
-D CMAKE_CXX_STANDARD=${{ matrix.cxx_standard }} \
-D CMAKE_INSTALL_PREFIX="${{ env.CMAKE_INSTALL_PREFIX }}" \
-D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \
-D CMAKE_CXX_FLAGS_DEBUG="${{ env.CMAKE_CXX_FLAGS_DEBUG }}" \
-D YAML_BUILD_SHARED_LIBS=${{ env.YAML_BUILD_SHARED_LIBS }} \
-D YAML_USE_SYSTEM_GTEST=${{ env.YAML_USE_SYSTEM_GTEST }} \
-D YAML_CPP_BUILD_TESTS=ON
- name: Build
run: |
cmake \
--build build \
--config ${{ env.CMAKE_BUILD_TYPE }} \
--verbose \
--parallel
- name: Run Tests
shell: bash
run: |
ctest \
--test-dir build \
--build-config ${{ env.CMAKE_BUILD_TYPE }} \
--output-on-failure \
--verbose
- name: Install
run: cmake --install build --config ${{ env.CMAKE_BUILD_TYPE }}
- name: Configure CMake package test
run: |
cmake \
${{ env.CMAKE_GENERATOR }} \
-S "${{ github.workspace }}/test/cmake" \
-B consumer-build \
-D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \
-D CMAKE_PREFIX_PATH="${{ env.CMAKE_INSTALL_PREFIX }}"
- name: Build CMake package test
run: |
cmake \
--build consumer-build \
--config ${{ env.CMAKE_BUILD_TYPE }} \
--verbose
bazel-build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- name: Build
run: |
cd "${{ github.workspace }}"
bazel build :all
- name: Test
run: |
cd "${{ github.workspace }}"
bazel test test
bzlmod-build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- name: Build
shell: bash
run: |
cd "${{ github.workspace }}"
bazel build --enable_bzlmod :all
- name: Test
shell: bash
run: |
cd "${{ github.workspace }}"
bazel test --enable_bzlmod test

19
.github/workflows/bzlmod-archive.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Bazel Release
on:
release:
types: [published]
jobs:
# A release archive is required for bzlmod
# See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html
bazel-release-archive:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.1
- run: git archive $GITHUB_REF -o "yaml-cpp-${GITHUB_REF:10}.tar.gz"
- run: gh release upload ${GITHUB_REF:10} "yaml-cpp-${GITHUB_REF:10}.tar.gz"
env:
GH_TOKEN: ${{ github.token }}

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
build/ build/
/tags /tags
/bazel-*

View File

@@ -1,28 +0,0 @@
language: c++
os:
- linux
- osx
compiler:
- clang
- gcc
before_install:
- |
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y \
&& sudo apt-get update -qq \
&& if [ "$CXX" == "g++" ]; then
sudo apt-get install -qq g++-4.7 && export CXX="g++-4.7" CC="gcc-4.7"
fi
fi
before_script:
- mkdir build
- cd build
- cmake ..
script:
- make
- test/run-tests
matrix:
exclude:
- os: linux
compiler: clang

21
BUILD.bazel Normal file
View File

@@ -0,0 +1,21 @@
yaml_cpp_defines = select({
# On Windows, ensure static linking is used.
"@platforms//os:windows": ["YAML_CPP_STATIC_DEFINE", "YAML_CPP_NO_CONTRIB"],
"//conditions:default": [],
})
cc_library(
name = "yaml-cpp_internal",
visibility = ["//:__subpackages__"],
strip_include_prefix = "src",
hdrs = glob(["src/**/*.h"]),
)
cc_library(
name = "yaml-cpp",
visibility = ["//visibility:public"],
includes = ["include"],
hdrs = glob(["include/**/*.h"]),
srcs = glob(["src/**/*.cpp", "src/**/*.h"]),
defines = yaml_cpp_defines,
)

View File

@@ -1,367 +1,213 @@
### # 3.5 is actually available almost everywhere.
### CMake settings # 3.30 as the upper policy limit avoids CMake deprecation warnings.
### cmake_minimum_required(VERSION 3.5...3.30)
# see http://www.cmake.org/Wiki/CMake_Policies
cmake_minimum_required(VERSION 3.1)
# enable MSVC_RUNTIME_LIBRARY target property
# see https://cmake.org/cmake/help/latest/policy/CMP0091.html
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
project(YAML_CPP VERSION 0.8.0 LANGUAGES CXX)
set(YAML_CPP_MAIN_PROJECT OFF)
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(YAML_CPP_MAIN_PROJECT ON)
endif()
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
include(GNUInstallDirs)
include(CTest)
### option(YAML_CPP_BUILD_CONTRIB "Enable yaml-cpp contrib in library" ON)
### Project settings
###
project(YAML_CPP VERSION 0.6.3)
###
### Project options
###
## Project stuff
option(YAML_CPP_BUILD_TESTS "Enable testing" ON)
option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON) option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON)
option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) option(YAML_BUILD_SHARED_LIBS "Build yaml-cpp shared library" ${BUILD_SHARED_LIBS})
option(YAML_CPP_INSTALL "Enable generation of install target" ON) option(YAML_CPP_INSTALL "Enable generation of yaml-cpp install targets" ${YAML_CPP_MAIN_PROJECT})
option(YAML_CPP_FORMAT_SOURCE "Format source" ${YAML_CPP_MAIN_PROJECT})
option(YAML_CPP_DISABLE_UNINSTALL "Disable uninstallation of yaml-cpp" OFF)
option(YAML_USE_SYSTEM_GTEST "Use system googletest if found" OFF)
option(YAML_ENABLE_PIC "Use Position-Independent Code " ON)
## Build options cmake_dependent_option(YAML_CPP_BUILD_TESTS
# --> General "Enable yaml-cpp tests" OFF
# see http://www.cmake.org/cmake/help/cmake2.6docs.html#variable:BUILD_SHARED_LIBS "BUILD_TESTING;YAML_CPP_MAIN_PROJECT" OFF)
# http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_library cmake_dependent_option(YAML_MSVC_SHARED_RT
option(YAML_BUILD_SHARED_LIBS "Build Shared Libraries" OFF) "MSVC: Build yaml-cpp with shared runtime libs (/MD)" ON
"CMAKE_SYSTEM_NAME MATCHES Windows" OFF)
set(YAML_CPP_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/yaml-cpp"
CACHE STRING "Path to install the CMake package to")
# --> Apple if (YAML_CPP_FORMAT_SOURCE)
if(APPLE) find_program(YAML_CPP_CLANG_FORMAT_EXE NAMES clang-format)
option(YAML_APPLE_UNIVERSAL_BIN "Apple: Build universal binary" OFF)
endif() endif()
# --> 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
if(MSVC)
option(YAML_MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON)
option(YAML_MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs (/ML until VS .NET 2003)" OFF)
endif()
###
### 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)
endif()
set(library_sources
${sources}
${public_headers}
${private_headers}
${contrib_sources}
${contrib_public_headers}
${contrib_private_headers}
)
add_sources(${library_sources})
if(VERBOSE)
message(STATUS "sources: ${sources}")
message(STATUS "public_headers: ${public_headers}")
message(STATUS "private_headers: ${private_headers}")
message(STATUS "contrib_sources: ${contrib_sources}")
message(STATUS "contrib_public_headers: ${contrib_public_headers}")
message(STATUS "contrib_private_headers: ${contrib_private_headers}")
endif()
if (CMAKE_VERSION VERSION_LESS 2.8.12)
include_directories(${YAML_CPP_SOURCE_DIR}/src)
include_directories(${YAML_CPP_SOURCE_DIR}/include)
endif()
###
### General compilation settings
###
set(yaml_c_flags ${CMAKE_C_FLAGS})
set(yaml_cxx_flags ${CMAKE_CXX_FLAGS})
if (YAML_BUILD_SHARED_LIBS) if (YAML_BUILD_SHARED_LIBS)
set(LABEL_SUFFIX "shared") set(yaml-cpp-type SHARED)
set(yaml-cpp-label-postfix "shared")
else() else()
set(LABEL_SUFFIX "static") set(yaml-cpp-type STATIC)
set(yaml-cpp-label-postfix "static")
endif() endif()
if(APPLE) set(build-shared $<BOOL:${YAML_BUILD_SHARED_LIBS}>)
if(YAML_APPLE_UNIVERSAL_BIN) set(build-windows-dll $<AND:$<BOOL:${CMAKE_HOST_WIN32}>,${build-shared}>)
set(CMAKE_OSX_ARCHITECTURES ppc;i386) set(not-msvc $<NOT:$<CXX_COMPILER_ID:MSVC>>)
endif() set(msvc-shared_rt $<BOOL:${YAML_MSVC_SHARED_RT}>)
if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
set(CMAKE_MSVC_RUNTIME_LIBRARY
MultiThreaded$<$<CONFIG:Debug>:Debug>$<${msvc-shared_rt}:DLL>)
endif() endif()
if(IPHONE) set(contrib-pattern "src/contrib/*.cpp")
set(CMAKE_OSX_SYSROOT "iphoneos4.2") set(src-pattern "src/*.cpp")
set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") if (CMAKE_VERSION VERSION_GREATER 3.12)
list(INSERT contrib-pattern 0 CONFIGURE_DEPENDS)
list(INSERT src-pattern 0 CONFIGURE_DEPENDS)
endif() endif()
if(WIN32) file(GLOB yaml-cpp-contrib-sources ${contrib-pattern})
if(YAML_BUILD_SHARED_LIBS) file(GLOB yaml-cpp-sources ${src-pattern})
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()
# GCC or Clang or Intel Compiler specialities set(msvc-rt $<TARGET_PROPERTY:MSVC_RUNTIME_LIBRARY>)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR
(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR
CMAKE_CXX_COMPILER_ID MATCHES "Intel")
### General stuff set(msvc-rt-mtd-static $<STREQUAL:${msvc-rt},MultiThreadedDebug>)
if(WIN32) set(msvc-rt-mt-static $<STREQUAL:${msvc-rt},MultiThreaded>)
set(CMAKE_SHARED_LIBRARY_PREFIX "") # DLLs do not have a "lib" prefix
set(CMAKE_IMPORT_LIBRARY_PREFIX "") # same for DLL import libs
set(CMAKE_LINK_DEF_FILE_FLAG "") # CMake workaround (2.8.3)
endif()
### Project stuff set(msvc-rt-mtd-dll $<STREQUAL:${msvc-rt},MultiThreadedDebugDLL>)
if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(msvc-rt-mt-dll $<STREQUAL:${msvc-rt},MultiThreadedDLL>)
set(CMAKE_BUILD_TYPE Release)
endif()
#
set(GCC_EXTRA_OPTIONS "")
#
if(YAML_BUILD_SHARED_LIBS)
set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} -fPIC")
endif()
#
set(FLAG_TESTED "-Wextra -Wshadow -Weffc++ -pedantic -pedantic-errors")
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}")
### Make specific set(backport-msvc-runtime $<VERSION_LESS:${CMAKE_VERSION},3.15>)
if(${CMAKE_BUILD_TOOL} MATCHES make OR ${CMAKE_BUILD_TOOL} MATCHES gmake)
add_custom_target(debuggable ${CMAKE_MAKE_PROGRAM} clean
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}
COMMENT "Adjusting settings for debug compilation"
VERBATIM)
add_custom_target(releasable ${CMAKE_MAKE_PROGRAM} clean
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR}
COMMENT "Adjusting settings for release compilation"
VERBATIM)
endif()
endif()
# Microsoft VisualC++ specialities add_library(yaml-cpp ${yaml-cpp-type} "")
if(MSVC) add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp)
### 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 YAML_MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML)
if(YAML_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 set_property(TARGET yaml-cpp
foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) PROPERTY
foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY})
set(var_name "${flag_var}") set_property(TARGET yaml-cpp
if(NOT "${config_name}" STREQUAL "") PROPERTY
set(var_name "${var_name}_${config_name}") CXX_STANDARD_REQUIRED ON)
endif()
string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}")
set(${var_name} "${${var_name}}" CACHE STRING "" FORCE)
endforeach()
endforeach()
endif()
#
set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_SUFFIX}")
# b) Change prefix for static libraries
set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs
# c) Correct suffixes for static libraries
if (NOT YAML_BUILD_SHARED_LIBS) if (NOT YAML_BUILD_SHARED_LIBS)
### General stuff set_property(TARGET yaml-cpp PROPERTY POSITION_INDEPENDENT_CODE ${YAML_ENABLE_PIC})
set(LIB_TARGET_SUFFIX "${LIB_SUFFIX}${LIB_RT_SUFFIX}")
endif() 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
###
set(INCLUDE_INSTALL_ROOT_DIR include)
set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_ROOT_DIR}/yaml-cpp)
set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}")
set(_INSTALL_DESTINATIONS
RUNTIME DESTINATION bin
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
)
###
### Library
###
if(YAML_BUILD_SHARED_LIBS)
add_library(yaml-cpp SHARED ${library_sources})
else()
add_library(yaml-cpp STATIC ${library_sources})
endif()
if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
target_include_directories(yaml-cpp target_include_directories(yaml-cpp
PUBLIC $<BUILD_INTERFACE:${YAML_CPP_SOURCE_DIR}/include> PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_ROOT_DIR}> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE $<BUILD_INTERFACE:${YAML_CPP_SOURCE_DIR}/src>) $<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(YAML_CPP_MAIN_PROJECT)
target_compile_options(yaml-cpp
PRIVATE
$<${not-msvc}:-Wall -Wextra -Wshadow -Weffc++ -Wno-long-long>
$<${not-msvc}:-pedantic -pedantic-errors>)
endif()
target_compile_options(yaml-cpp
PRIVATE
$<$<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>
# /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>)
target_compile_definitions(yaml-cpp
PUBLIC
$<$<NOT:$<BOOL:${YAML_BUILD_SHARED_LIBS}>>:YAML_CPP_STATIC_DEFINE>
PRIVATE
$<${build-windows-dll}:${PROJECT_NAME}_DLL>
$<$<NOT:$<BOOL:${YAML_CPP_BUILD_CONTRIB}>>:YAML_CPP_NO_CONTRIB>)
target_sources(yaml-cpp
PRIVATE
$<$<BOOL:${YAML_CPP_BUILD_CONTRIB}>:${yaml-cpp-contrib-sources}>
${yaml-cpp-sources})
if (NOT DEFINED CMAKE_DEBUG_POSTFIX)
set(CMAKE_DEBUG_POSTFIX "d")
endif() endif()
set_target_properties(yaml-cpp PROPERTIES set_target_properties(yaml-cpp PROPERTIES
CXX_STANDARD 11 VERSION "${PROJECT_VERSION}"
CXX_STANDARD_REQUIRED ON SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
) PROJECT_LABEL "yaml-cpp ${yaml-cpp-label-postfix}"
DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
set_target_properties(yaml-cpp PROPERTIES set(EXPORT_TARGETS yaml-cpp::yaml-cpp)
COMPILE_FLAGS "${yaml_c_flags} ${yaml_cxx_flags}" configure_package_config_file(
) "${PROJECT_SOURCE_DIR}/yaml-cpp-config.cmake.in"
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
INSTALL_DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}"
PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR)
unset(EXPORT_TARGETS)
set_target_properties(yaml-cpp PROPERTIES write_basic_package_version_file(
VERSION "${YAML_CPP_VERSION}"
SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}"
PROJECT_LABEL "yaml-cpp ${LABEL_SUFFIX}"
)
if(IPHONE)
set_target_properties(yaml-cpp PROPERTIES
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0"
)
endif()
if(MSVC)
if(NOT YAML_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()
if (YAML_CPP_INSTALL)
install(TARGETS yaml-cpp EXPORT yaml-cpp-targets ${_INSTALL_DESTINATIONS})
install(
DIRECTORY ${header_directory}
DESTINATION ${INCLUDE_INSTALL_DIR}
FILES_MATCHING PATTERN "*.h"
)
endif()
export(
TARGETS yaml-cpp
FILE "${PROJECT_BINARY_DIR}/yaml-cpp-targets.cmake")
export(PACKAGE yaml-cpp)
set(EXPORT_TARGETS yaml-cpp CACHE INTERNAL "export targets")
set(CONFIG_INCLUDE_DIRS "${YAML_CPP_SOURCE_DIR}/include")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config.cmake.in
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake" @ONLY)
if(WIN32 AND NOT CYGWIN)
set(INSTALL_CMAKE_DIR CMake)
else()
set(INSTALL_CMAKE_DIR ${LIB_INSTALL_DIR}/cmake/yaml-cpp)
endif()
file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_ROOT_DIR}")
set(CONFIG_INCLUDE_DIRS "\${YAML_CPP_CMAKE_DIR}/${REL_INCLUDE_DIR}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config.cmake.in
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/yaml-cpp-config.cmake" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp-config-version.cmake.in
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" @ONLY)
if (YAML_CPP_INSTALL)
install(FILES
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/yaml-cpp-config.cmake"
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake"
DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) COMPATIBILITY AnyNewerVersion)
install(EXPORT yaml-cpp-targets DESTINATION ${INSTALL_CMAKE_DIR})
if(UNIX) configure_file(yaml-cpp.pc.in yaml-cpp.pc @ONLY)
set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc)
configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) if (YAML_CPP_INSTALL)
install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) install(TARGETS yaml-cpp
EXPORT yaml-cpp-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h")
install(EXPORT yaml-cpp-targets
NAMESPACE yaml-cpp::
DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}")
install(FILES
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake"
DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}")
install(FILES "${PROJECT_BINARY_DIR}/yaml-cpp.pc"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif() endif()
endif()
###
### Extras
###
if(YAML_CPP_BUILD_TESTS) if(YAML_CPP_BUILD_TESTS)
enable_testing()
add_subdirectory(test) add_subdirectory(test)
endif() endif()
if(YAML_CPP_BUILD_TOOLS) if(YAML_CPP_BUILD_TOOLS)
add_subdirectory(util) add_subdirectory(util)
endif() endif()
### Formatting if (YAML_CPP_FORMAT_SOURCE AND YAML_CPP_CLANG_FORMAT_EXE)
get_property(all_sources GLOBAL PROPERTY SRCS_LIST)
add_custom_target(format add_custom_target(format
COMMAND clang-format --style=file -i ${all_sources} COMMAND clang-format --style=file -i $<TARGET_PROPERTY:yaml-cpp,SOURCES>
COMMAND_EXPAND_LISTS
COMMENT "Running clang-format" COMMENT "Running clang-format"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
VERBATIM) VERBATIM)
endif()
# uninstall target
if(YAML_CPP_INSTALL AND NOT YAML_CPP_DISABLE_UNINSTALL AND NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()

View File

@@ -17,9 +17,9 @@ Commit messages should be in the imperative mood, as described in the [Git contr
# Tests # Tests
Please verify the tests pass by running the target `tests/run_tests`. Please verify the tests pass by configuring CMake with `-D YAML_CPP_BUILD_TESTS=ON` and running the target `test/yaml-cpp-tests`.
If you are adding functionality, add tests accordingly. If you are adding functionality, add tests accordingly. Note that the "spec tests" are reserved for examples directly from the YAML spec, so if you have new examples, put them in other test files.
# Pull request process # Pull request process

14
MODULE.bazel Normal file
View File

@@ -0,0 +1,14 @@
"""
yaml-cpp is a YAML parser and emitter in c++ matching the YAML specification.
"""
module(
name = "yaml-cpp",
compatibility_level = 1,
version = "0.8.0",
)
bazel_dep(name = "platforms", version = "0.0.7")
bazel_dep(name = "rules_cc", version = "0.0.8")
bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True)

114
MODULE.bazel.lock generated Normal file
View File

@@ -0,0 +1,114 @@
{
"lockFileVersion": 11,
"registryFileHashes": {
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/source.json": "06cc0842d241da0c5edc755edb3c7d0d008d304330e57ecf2d6449fb0b633a82",
"https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef",
"https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862",
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
"https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/source.json": "082ed5f9837901fada8c68c2f3ddc958bb22b6d654f71dd73f3df30d45d4b749",
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
"https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5",
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
"https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6",
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
"https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b",
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
"https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
"https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
"https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430",
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
"https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1",
"https://bcr.bazel.build/modules/rules_java/7.6.5/source.json": "a805b889531d1690e3c72a7a7e47a870d00323186a9904b36af83aa3d053ee8d",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35",
"https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
"https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c",
"https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9",
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
"https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
"https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014",
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
"https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459",
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d"
},
"selectedYankedVersions": {},
"moduleExtensions": {
"@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": {
"general": {
"bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=",
"usagesDigest": "+hz7IHWN6A1oVJJWNDB6yZRG+RYhF76wAYItpAeIUIg=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"local_config_apple_cc_toolchains": {
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
"ruleClassName": "_apple_cc_autoconf_toolchains",
"attributes": {}
},
"local_config_apple_cc": {
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
"ruleClassName": "_apple_cc_autoconf",
"attributes": {}
}
},
"recordedRepoMappingEntries": [
[
"apple_support~",
"bazel_tools",
"bazel_tools"
]
]
}
},
"@@platforms//host:extension.bzl%host_platform": {
"general": {
"bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
"usagesDigest": "pCYpDQmqMbmiiPI1p2Kd3VLm5T48rRAht5WdW0X2GlA=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"host_platform": {
"bzlFile": "@@platforms//host:extension.bzl",
"ruleClassName": "host_platform_repo",
"attributes": {}
}
},
"recordedRepoMappingEntries": []
}
}
}
}

View File

@@ -1,51 +1,86 @@
# yaml-cpp [![Build Status](https://travis-ci.org/jbeder/yaml-cpp.svg?branch=master)](https://travis-ci.org/jbeder/yaml-cpp) [![Documentation](https://codedocs.xyz/jbeder/yaml-cpp.svg)](https://codedocs.xyz/jbeder/yaml-cpp/) # yaml-cpp ![Build Status](https://github.com/jbeder/yaml-cpp/actions/workflows/build.yml/badge.svg) [![Documentation](https://codedocs.xyz/jbeder/yaml-cpp.svg)](https://codedocs.xyz/jbeder/yaml-cpp/)
yaml-cpp is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html). `yaml-cpp` is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html).
To get a feel for how it can be used, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) or [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML). For the old API (version < 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)). ## Usage
# Problems? # See [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) and [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML) for reference. For the old API (until 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)).
## Any 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). 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 # ## How to Build
yaml-cpp uses [CMake](http://www.cmake.org) to support cross-platform building. The basic steps to build are: `yaml-cpp` uses [CMake](http://www.cmake.org) to support cross-platform building. Install [CMake](http://www.cmake.org) _(Resources -> Download)_ before proceeding. The basic steps to build are:
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.
**Note:** If you don't use the provided installer for your platform, make sure that you add CMake's bin folder to your path. #### 1. Navigate into the source directory, create build folder and run `CMake`:
2. Navigate into the source directory, and type: ```sh
```
mkdir build mkdir build
cd build cd build
cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=on|OFF] ..
``` ```
3. Run CMake. The basic syntax is: * The `generator` option is the build system you'd like to use. Run `cmake` without arguments to see a full list of available generators.
* On Windows, you might use "Visual Studio 12 2013" (VS 2013 32-bits), or "Visual Studio 14 2015 Win64" (VS 2015 64-bits).
* On OS X, you might use "Xcode".
* On a UNIX-like system, omit the option (for a Makefile).
``` * `yaml-cpp` builds a static library by default, you may want to build a shared library by specifying `-DYAML_BUILD_SHARED_LIBS=ON`.
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: * [Debug mode of the GNU standard C++
* 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. library](https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html)
* On OS X, you might use "Xcode" to generate an Xcode project can be used when both `yaml-cpp` and client code is compiled with the
* On a UNIX-y system, simply omit the option to generate a makefile `_GLIBCXX_DEBUG` flag (e.g. by calling CMake with `-D
CMAKE_CXX_FLAGS_DEBUG='-g -D_GLIBCXX_DEBUG'` option).
* yaml-cpp defaults to building a static library, but you may build a shared library by specifying `-DYAML_BUILD_SHARED_LIBS=ON`. Note that for `yaml-cpp` unit tests to run successfully, the _GoogleTest_
library also must be built with this flag, i.e. the system one cannot be
used (the _YAML_USE_SYSTEM_GTEST_ CMake option must be _OFF_, which is the
default).
* For more options on customizing the build, see the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file. * For more options on customizing the build, see the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file.
4. Build it! #### 2. Build it!
* The command you'll need to run depends on the generator you chose earlier.
5. To clean up, just remove the `build` directory. **Note:** To clean up, just remove the `build` directory.
# Recent Release # ## How to Integrate it within your project using CMake
[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. You can use for example FetchContent :
```cmake
include(FetchContent)
FetchContent_Declare(
yaml-cpp
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
GIT_TAG <tag_name> # Can be a tag (yaml-cpp-x.x.x), a commit hash, or a branch name (master)
)
FetchContent_MakeAvailable(yaml-cpp)
target_link_libraries(YOUR_LIBRARY PUBLIC yaml-cpp::yaml-cpp) # The library or executable that require yaml-cpp library
```
## Recent Releases
[yaml-cpp 0.8.0](https://github.com/jbeder/yaml-cpp/releases/tag/0.8.0) released!
[yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old API. [yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old API.
**The old API will continue to be supported, and will still receive bugfixes!** The 0.3.x and 0.4.x versions will be old API releases, and 0.5.x and above will all be new API releases. **The old API will stop receiving bugfixes in 2026.** The 0.3.x versions provide the old API, and 0.5.x and above all provide the new API.
# API Documentation
The autogenerated API reference is hosted on [CodeDocs](https://codedocs.xyz/jbeder/yaml-cpp/index.html)
# Third Party Integrations
The following projects are not officially supported:
- [Qt wrapper](https://gist.github.com/brcha/d392b2fe5f1e427cc8a6)
- [UnrealEngine Wrapper](https://github.com/jwindgassen/UnrealYAML)

13
SECURITY.md Normal file
View File

@@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
Security updates are applied only to the latest release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/jbeder/yaml-cpp/security/advisories/new).
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base.

21
cmake_uninstall.cmake.in Normal file
View File

@@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif()
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif()
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif()
endforeach()

52
docs/Breaking-Changes.md Normal file
View File

@@ -0,0 +1,52 @@
# The following is a list of breaking changes to yaml-cpp, by version #
# New API #
## HEAD ##
* Throws an exception when trying to parse a negative number as an unsigned integer.
* Supports the `as<int8_t>`/`as<uint8_t>`, which throws an exception when the value exceeds the range of `int8_t`/`uint8_t`.
## 0.6.0 ##
* Requires C++11.
## 0.5.3 ##
_none_
## 0.5.2 ##
_none_
## 0.5.1 ##
* `Node::clear` was replaced by `Node::reset`, which takes an optional node, similar to smart pointers.
## 0.5.0 ##
Initial version of the new API.
# Old API #
## 0.3.0 ##
_none_
## 0.2.7 ##
* `YAML::Binary` now takes `const unsigned char *` for the binary data (instead of `const char *`).
## 0.2.6 ##
* `Node::GetType()` is now `Node::Type()`, and returns an enum `NodeType::value`, where:
> > ` struct NodeType { enum value { Null, Scalar, Sequence, Map }; }; `
* `Node::GetTag()` is now `Node::Tag()`
* `Node::Identity()` is removed, and `Node::IsAlias()` and `Node::IsReferenced()` have been merged into `Node::IsAliased()`. The reason: there's no reason to distinguish an alias node from its anchor - whichever happens to be emitted first will be the anchor, and the rest will be aliases.
* `Node::Read<T>` is now `Node::to<T>`. This wasn't a documented function, so it shouldn't break anything.
* `Node`'s comparison operators (for example, `operator == (const Node&, const T&)`) have all been removed. These weren't documented either (they were just used for the tests), so this shouldn't break anything either.
* The emitter no longer produces the document start by default - if you want it, you can supply it with the manipulator `YAML::BeginDoc`.
## 0.2.5 ##
This wiki was started with v0.2.5.

226
docs/How-To-Emit-YAML.md Normal file
View File

@@ -0,0 +1,226 @@
## Contents ##
# Basic Emitting #
The model for emitting YAML is `std::ostream` manipulators. A `YAML::Emitter` objects acts as an output stream, and its output can be retrieved through the `c_str()` function (as in `std::string`). For a simple example:
```cpp
#include "yaml-cpp/yaml.h"
int main()
{
YAML::Emitter out;
out << "Hello, World!";
std::cout << "Here's the output YAML:\n" << out.c_str(); // prints "Hello, World!"
return 0;
}
```
# Simple Lists and Maps #
A `YAML::Emitter` object acts as a state machine, and we use manipulators to move it between states. Here's a simple sequence:
```cpp
YAML::Emitter out;
out << YAML::BeginSeq;
out << "eggs";
out << "bread";
out << "milk";
out << YAML::EndSeq;
```
produces
```yaml
- eggs
- bread
- milk
```
A simple map:
```cpp
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "name";
out << YAML::Value << "Ryan Braun";
out << YAML::Key << "position";
out << YAML::Value << "LF";
out << YAML::EndMap;
```
produces
```yaml
name: Ryan Braun
position: LF
```
These elements can, of course, be nested:
```cpp
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "name";
out << YAML::Value << "Barack Obama";
out << YAML::Key << "children";
out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
out << YAML::EndMap;
```
produces
```yaml
name: Barack Obama
children:
- Sasha
- Malia
```
# Using Manipulators #
To deviate from standard formatting, you can use manipulators to modify the output format. For example,
```cpp
YAML::Emitter out;
out << YAML::Literal << "A\n B\n C";
```
produces
```yaml
|
A
B
C
```
and
```cpp
YAML::Emitter out;
out << YAML::Flow;
out << YAML::BeginSeq << 2 << 3 << 5 << 7 << 11 << YAML::EndSeq;
```
produces
```yaml
[2, 3, 5, 7, 11]
```
Comments act like manipulators:
```cpp
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "method";
out << YAML::Value << "least squares";
out << YAML::Comment("should we change this method?");
out << YAML::EndMap;
```
produces
```yaml
method: least squares # should we change this method?
```
And so do aliases/anchors:
```cpp
YAML::Emitter out;
out << YAML::BeginSeq;
out << YAML::Anchor("fred");
out << YAML::BeginMap;
out << YAML::Key << "name" << YAML::Value << "Fred";
out << YAML::Key << "age" << YAML::Value << "42";
out << YAML::EndMap;
out << YAML::Alias("fred");
out << YAML::EndSeq;
```
produces
```yaml
- &fred
name: Fred
age: 42
- *fred
```
# STL Containers, and Other Overloads #
We overload `operator <<` for `std::vector`, `std::list`, and `std::map`, so you can write stuff like:
{% raw %}
```cpp
std::vector <int> squares = {1, 4, 9, 16};
std::map <std::string, int> ages = {{"Daniel", 26}, {"Jesse", 24}};
YAML::Emitter out;
out << YAML::BeginSeq;
out << YAML::Flow << squares;
out << ages;
out << YAML::EndSeq;
```
{% endraw %}
produces
```yaml
- [1, 4, 9, 16]
-
Daniel: 26
Jesse: 24
```
Of course, you can overload `operator <<` for your own types:
```cpp
struct Vec3 { int x; int y; int z; };
YAML::Emitter& operator << (YAML::Emitter& out, const Vec3& v) {
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
```
and it'll play nicely with everything else.
# Using Existing Nodes #
We also overload `operator << ` for `YAML::Node`s in both APIs, so you can output existing Nodes. Of course, Nodes in the old API are read-only, so it's tricky to emit them if you want to modify them. So use the new API!
# Output Encoding #
The output is always UTF-8. By default, yaml-cpp will output as much as it can without escaping any characters. If you want to restrict the output to ASCII, use the manipulator `YAML::EscapeNonAscii`:
```cpp
emitter.SetOutputCharset(YAML::EscapeNonAscii);
```
# Lifetime of Manipulators #
Manipulators affect the **next** output item in the stream. If that item is a `BeginSeq` or `BeginMap`, the manipulator lasts until the corresponding `EndSeq` or `EndMap`. (However, within that sequence or map, you can override the manipulator locally, etc.; in effect, there's a "manipulator stack" behind the scenes.)
If you want to permanently change a setting, there are global setters corresponding to each manipulator, e.g.:
```cpp
YAML::Emitter out;
out.SetIndent(4);
out.SetMapStyle(YAML::Flow);
```
# When Something Goes Wrong #
If something goes wrong when you're emitting a document, it must be something like forgetting a `YAML::EndSeq`, or a misplaced `YAML::Key`. In this case, emitting silently fails (no more output is emitted) and an error flag is set. For example:
```cpp
YAML::Emitter out;
assert(out.good());
out << YAML::Key;
assert(!out.good());
std::cout << "Emitter error: " << out.GetLastError() << "\n";
```

View File

@@ -0,0 +1,265 @@
_The following describes the old API. For the new API, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial)._
## Contents ##
# Basic Parsing #
The parser accepts streams, not file names, so you need to first load the file. Since a YAML file can contain many documents, you can grab them one-by-one. A simple way to parse a YAML file might be:
```
#include <fstream>
#include "yaml-cpp/yaml.h"
int main()
{
std::ifstream fin("test.yaml");
YAML::Parser parser(fin);
YAML::Node doc;
while(parser.GetNextDocument(doc)) {
// ...
}
return 0;
}
```
# Reading From the Document #
Suppose we have a document consisting only of a scalar. We can read that scalar like this:
```
YAML::Node doc; // let's say we've already parsed this document
std::string scalar;
doc >> scalar;
std::cout << "That scalar was: " << scalar << std::endl;
```
How about sequences? Let's say our document now consists only of a sequences of scalars. We can use an iterator:
```
YAML::Node doc; // already parsed
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
std::string scalar;
*it >> scalar;
std::cout << "Found scalar: " << scalar << std::endl;
}
```
... or we can just loop through:
```
YAML::Node doc; // already parsed
for(unsigned i=0;i<doc.size();i++) {
std::string scalar;
doc[i] >> scalar;
std::cout << "Found scalar: " << scalar << std::endl;
}
```
And finally maps. For now, let's say our document is a map with all keys/values being scalars. Again, we can iterate:
```
YAML::Node doc; // already parsed
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
std::string key, value;
it.first() >> key;
it.second() >> value;
std::cout << "Key: " << key << ", value: " << value << std::endl;
}
```
Note that dereferencing a map iterator is undefined; instead, use the `first` and `second` methods to get the key and value nodes, respectively.
Alternatively, we can pick off the values one-by-one, if we know the keys:
```
YAML::Node doc; // already parsed
std::string name;
doc["name"] >> name;
int age;
doc["age"] >> age;
std::cout << "Found entry with name '" << name << "' and age '" << age << "'\n";
```
One thing to be keep in mind: reading a map by key (as immediately above) requires looping through all entries until we find the right key, which is an O(n) operation. So if you're reading the entire map this way, it'll be O(n^2). For small n, this isn't a big deal, but I wouldn't recommend reading maps with a very large number of entries (>100, say) this way.
## Optional Keys ##
If you try to access a key that doesn't exist, `yaml-cpp` throws an exception (see [When Something Goes Wrong](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)#When_Something_Goes_Wrong). If you have optional keys, it's often easier to use `FindValue` instead of `operator[]`:
```
YAML::Node doc; // already parsed
if(const YAML::Node *pName = doc.FindValue("name")) {
std::string name;
*pName >> name;
std::cout << "Key 'name' exists, with value '" << name << "'\n";
} else {
std::cout << "Key 'name' doesn't exist\n";
}
```
# Getting More Complicated #
The above three methods can be combined to read from an arbitrary document. But we can make life a lot easier. Suppose we're reading 3-vectors (i.e., vectors with three components), so we've got a structure looking like this:
```
struct Vec3 {
float x, y, z;
};
```
We can read this in one operation by overloading the extraction (>>) operator:
```
void operator >> (const YAML::Node& node, Vec3& v)
{
node[0] >> v.x;
node[1] >> v.y;
node[2] >> v.z;
}
// now it's a piece of cake to read it
YAML::Node doc; // already parsed
Vec3 v;
doc >> v;
std::cout << "Here's the vector: (" << v.x << ", " << v.y << ", " << v.z << ")\n";
```
# A Complete Example #
Here's a complete example of how to parse a complex YAML file:
`monsters.yaml`
```
- name: Ogre
position: [0, 5, 0]
powers:
- name: Club
damage: 10
- name: Fist
damage: 8
- name: Dragon
position: [1, 0, 10]
powers:
- name: Fire Breath
damage: 25
- name: Claws
damage: 15
- name: Wizard
position: [5, -3, 0]
powers:
- name: Acid Rain
damage: 50
- name: Staff
damage: 3
```
`main.cpp`
```
#include "yaml-cpp/yaml.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
// our data types
struct Vec3 {
float x, y, z;
};
struct Power {
std::string name;
int damage;
};
struct Monster {
std::string name;
Vec3 position;
std::vector <Power> powers;
};
// now the extraction operators for these types
void operator >> (const YAML::Node& node, Vec3& v) {
node[0] >> v.x;
node[1] >> v.y;
node[2] >> v.z;
}
void operator >> (const YAML::Node& node, Power& power) {
node["name"] >> power.name;
node["damage"] >> power.damage;
}
void operator >> (const YAML::Node& node, Monster& monster) {
node["name"] >> monster.name;
node["position"] >> monster.position;
const YAML::Node& powers = node["powers"];
for(unsigned i=0;i<powers.size();i++) {
Power power;
powers[i] >> power;
monster.powers.push_back(power);
}
}
int main()
{
std::ifstream fin("monsters.yaml");
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
for(unsigned i=0;i<doc.size();i++) {
Monster monster;
doc[i] >> monster;
std::cout << monster.name << "\n";
}
return 0;
}
```
# When Something Goes Wrong #
... we throw an exception (all exceptions are derived from `YAML::Exception`). If there's a parsing exception (i.e., a malformed YAML document), we throw a `YAML::ParserException`:
```
try {
std::ifstream fin("test.yaml");
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
// do stuff
} catch(YAML::ParserException& e) {
std::cout << e.what() << "\n";
}
```
If you make a programming error (say, trying to read a scalar from a sequence node, or grabbing a key that doesn't exist), we throw some kind of `YAML::RepresentationException`. To prevent this, you can check what kind of node something is:
```
YAML::Node node;
YAML::NodeType::value type = node.Type(); // should be:
// YAML::NodeType::Null
// YAML::NodeType::Scalar
// YAML::NodeType::Sequence
// YAML::NodeType::Map
```
# Note about copying `YAML::Node` #
Currently `YAML::Node` is non-copyable, so you need to do something like
```
const YAML::Node& node = doc["whatever"];
```
This is intended behavior. If you want to copy a node, use the `Clone` function:
```
std::auto_ptr<YAML::Node> pCopy = myOtherNode.Clone();
```
The intent is that if you'd like to keep a `YAML::Node` around for longer than the document will stay in scope, you can clone it and store it as long as you like.

18
docs/Strings.md Normal file
View File

@@ -0,0 +1,18 @@
# Encodings and `yaml-cpp` #
`yaml-cpp` will parse any file as specified by the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html#id2570322). Internally, it stores all strings in UTF-8, and representation is done with UTF-8. This means that in
```
std::string str;
node >> str;
```
`str` will be UTF-8. Similarly, if you're accessing a map by string key, you need to pass the key in UTF-8. If your application uses a different encoding, you need to convert to and from UTF-8 to work with `yaml-cpp`. (It's possible we'll add some small conversion functions, but for now it's restricted.)
---
For convenience, Richard Weeks has kindly provided a google gadget that converts Unicode to a string literal. It's a Google Gadget, so unfortunately it does not work on GitHub. Patches welcome to port it to a usable format here:
```
<wiki:gadget url="http://hosting.gmodules.com/ig/gadgets/file/111180078345548400783/c-style-utf8-encoder.xml"/>
```

201
docs/Tutorial.md Normal file
View File

@@ -0,0 +1,201 @@
# Introduction #
A typical example, loading a configuration file, might look like this:
```cpp
YAML::Node config = YAML::LoadFile("config.yaml");
if (config["lastLogin"]) {
std::cout << "Last logged in: " << config["lastLogin"].as<DateTime>() << "\n";
}
const std::string username = config["username"].as<std::string>();
const std::string password = config["password"].as<std::string>();
login(username, password);
config["lastLogin"] = getCurrentDateTime();
std::ofstream fout("config.yaml");
fout << config;
```
# Basic Parsing and Node Editing #
All nodes in a YAML document (including the root) are represented by `YAML::Node`. You can check what kind it is:
```cpp
YAML::Node node = YAML::Load("[1, 2, 3]");
assert(node.Type() == YAML::NodeType::Sequence);
assert(node.IsSequence()); // a shortcut!
```
Collection nodes (sequences and maps) act somewhat like STL vectors and maps:
```cpp
YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]");
for (std::size_t i=0;i<primes.size();i++) {
std::cout << primes[i].as<int>() << "\n";
}
// or:
for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) {
std::cout << it->as<int>() << "\n";
}
primes.push_back(13);
assert(primes.size() == 6);
```
and
```cpp
YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}");
for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) {
std::cout << "Playing at " << it->first.as<std::string>() << " is " << it->second.as<std::string>() << "\n";
}
lineup["RF"] = "Corey Hart";
lineup["C"] = "Jonathan Lucroy";
assert(lineup.size() == 5);
```
Querying for keys does **not** create them automatically (this makes handling optional map entries very easy)
```cpp
YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}");
if (node["name"]) {
std::cout << node["name"].as<std::string>() << "\n";
}
if (node["mascot"]) {
std::cout << node["mascot"].as<std::string>() << "\n";
}
assert(node.size() == 2); // the previous call didn't create a node
```
If you're not sure what kind of data you're getting, you can query the type of a node:
```cpp
switch (node.Type()) {
case Null: // ...
case Scalar: // ...
case Sequence: // ...
case Map: // ...
case Undefined: // ...
}
```
or ask directly whether it's a particular type, e.g.:
```cpp
if (node.IsSequence()) {
// ...
}
```
# Building Nodes #
You can build `YAML::Node` from scratch:
```cpp
YAML::Node node; // starts out as null
node["key"] = "value"; // it now is a map node
node["seq"].push_back("first element"); // node["seq"] automatically becomes a sequence
node["seq"].push_back("second element");
node["mirror"] = node["seq"][0]; // this creates an alias
node["seq"][0] = "1st element"; // this also changes node["mirror"]
node["mirror"] = "element #1"; // and this changes node["seq"][0] - they're really the "same" node
node["self"] = node; // you can even create self-aliases
node[node["mirror"]] = node["seq"]; // and strange loops :)
```
The above node is now:
```yaml
&1
key: value
&2 seq: [&3 "element #1", second element]
mirror: *3
self: *1
*3 : *2
```
# How Sequences Turn Into Maps #
Sequences can be turned into maps by asking for non-integer keys. For example,
```cpp
YAML::Node node = YAML::Load("[1, 2, 3]");
node[1] = 5; // still a sequence, [1, 5, 3]
node.push_back(-3) // still a sequence, [1, 5, 3, -3]
node["key"] = "value"; // now it's a map! {0: 1, 1: 5, 2: 3, 3: -3, key: value}
```
Indexing a sequence node by an index that's not in its range will _usually_ turn it into a map, but if the index is one past the end of the sequence, then the sequence will grow by one to accommodate it. (That's the **only** exception to this rule.) For example,
```cpp
YAML::Node node = YAML::Load("[1, 2, 3]");
node[3] = 4; // still a sequence, [1, 2, 3, 4]
node[10] = 10; // now it's a map! {0: 1, 1: 2, 2: 3, 3: 4, 10: 10}
```
# Converting To/From Native Data Types #
Yaml-cpp has built-in conversion to and from most built-in data types, as well as `std::vector`, `std::list`, and `std::map`. The following examples demonstrate when those conversions are used:
```cpp
YAML::Node node = YAML::Load("{pi: 3.14159, [0, 1]: integers}");
// this needs the conversion from Node to double
double pi = node["pi"].as<double>();
// this needs the conversion from double to Node
node["e"] = 2.71828;
// this needs the conversion from Node to std::vector<int> (*not* the other way around!)
std::vector<int> v;
v.push_back(0);
v.push_back(1);
std::string str = node[v].as<std::string>();
```
To use yaml-cpp with your own data types, you need to specialize the YAML::convert<> template class. For example, suppose you had a simple `Vec3` class:
```cpp
struct Vec3 { double x, y, z; /* etc - make sure you have overloaded operator== */ };
```
You could write
```cpp
namespace YAML {
template<>
struct convert<Vec3> {
static Node encode(const Vec3& rhs) {
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
return node;
}
static bool decode(const Node& node, Vec3& rhs) {
if(!node.IsSequence() || node.size() != 3) {
return false;
}
rhs.x = node[0].as<double>();
rhs.y = node[1].as<double>();
rhs.z = node[2].as<double>();
return true;
}
};
}
```
Then you could use `Vec3` wherever you could use any other type:
```cpp
YAML::Node node = YAML::Load("start: [1, 3, 0]");
Vec3 v = node["start"].as<Vec3>();
node["end"] = Vec3(2, -1, 0);
```

1
docs/_config.yml Normal file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-slate

1
docs/index.md Normal file
View File

@@ -0,0 +1 @@
To learn how to use the library, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) and [How To Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML)

View File

@@ -10,7 +10,7 @@
#include <cstddef> #include <cstddef>
namespace YAML { namespace YAML {
typedef std::size_t anchor_t; using anchor_t = std::size_t;
const anchor_t NullAnchor = 0; const anchor_t NullAnchor = 0;
} }

View File

@@ -15,7 +15,7 @@ class Parser;
// GraphBuilderInterface // GraphBuilderInterface
// . Abstraction of node creation // . 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. // functions.
class GraphBuilderInterface { class GraphBuilderInterface {
public: public:
@@ -73,9 +73,9 @@ class GraphBuilder : public GraphBuilderInterface {
typedef typename Impl::Map Map; typedef typename Impl::Map Map;
GraphBuilder(Impl &impl) : m_impl(impl) { GraphBuilder(Impl &impl) : m_impl(impl) {
Map *pMap = NULL; Map *pMap = nullptr;
Sequence *pSeq = NULL; Sequence *pSeq = nullptr;
Node *pNode = NULL; Node *pNode = nullptr;
// Type consistency checks // Type consistency checks
pNode = pMap; pNode = pMap;

View File

@@ -0,0 +1,77 @@
#ifndef DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000
#define DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000
#if defined(_MSC_VER) || \
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "exceptions.h"
namespace YAML {
/**
* @brief The DeepRecursion class
* An exception class which is thrown by DepthGuard. Ideally it should be
* a member of DepthGuard. However, DepthGuard is a templated class which means
* that any catch points would then need to know the template parameters. It is
* simpler for clients to not have to know at the catch point what was the
* maximum depth.
*/
class DeepRecursion : public ParserException {
public:
virtual ~DeepRecursion() = default;
DeepRecursion(int depth, const Mark& mark_, const std::string& msg_);
// Returns the recursion depth when the exception was thrown
int depth() const {
return m_depth;
}
private:
int m_depth = 0;
};
/**
* @brief The DepthGuard class
* DepthGuard takes a reference to an integer. It increments the integer upon
* construction of DepthGuard and decrements the integer upon destruction.
*
* If the integer would be incremented past max_depth, then an exception is
* thrown. This is ideally geared toward guarding against deep recursion.
*
* @param max_depth
* compile-time configurable maximum depth.
*/
template <int max_depth = 2000>
class DepthGuard final {
public:
DepthGuard(int & depth_, const Mark& mark_, const std::string& msg_) : m_depth(depth_) {
++m_depth;
if ( max_depth <= m_depth ) {
throw DeepRecursion{m_depth, mark_, msg_};
}
}
DepthGuard(const DepthGuard & copy_ctor) = delete;
DepthGuard(DepthGuard && move_ctor) = delete;
DepthGuard & operator=(const DepthGuard & copy_assign) = delete;
DepthGuard & operator=(DepthGuard && move_assign) = delete;
~DepthGuard() {
--m_depth;
}
int current_depth() const {
return m_depth;
}
private:
int & m_depth;
};
} // namespace YAML
#endif // DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000

View File

@@ -1,33 +1,59 @@
#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || \ // Definition YAML_CPP_STATIC_DEFINE using to building YAML-CPP as static
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ // library (definition created by CMake or defined manually)
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once // Definition yaml_cpp_EXPORTS using to building YAML-CPP as dll/so library
// (definition created by CMake or defined manually)
#ifdef YAML_CPP_STATIC_DEFINE
# define YAML_CPP_API
# define YAML_CPP_NO_EXPORT
#else
# if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
# ifndef YAML_CPP_API
# ifdef yaml_cpp_EXPORTS
/* We are building this library */
# define YAML_CPP_API __declspec(dllexport)
# else
/* We are using this library */
# define YAML_CPP_API __declspec(dllimport)
# endif
# endif
# ifndef YAML_CPP_NO_EXPORT
# define YAML_CPP_NO_EXPORT
# endif
# else /* No _MSC_VER */
# ifndef YAML_CPP_API
# ifdef yaml_cpp_EXPORTS
/* We are building this library */
# define YAML_CPP_API __attribute__((visibility("default")))
# else
/* We are using this library */
# define YAML_CPP_API __attribute__((visibility("default")))
# endif
# endif
# ifndef YAML_CPP_NO_EXPORT
# define YAML_CPP_NO_EXPORT __attribute__((visibility("hidden")))
# endif
# endif /* _MSC_VER */
#endif /* YAML_CPP_STATIC_DEFINE */
#ifndef YAML_CPP_DEPRECATED
# ifdef _MSC_VER
# define YAML_CPP_DEPRECATED __declspec(deprecated)
# else
# define YAML_CPP_DEPRECATED __attribute__ ((__deprecated__))
# endif
#endif #endif
// The following ifdef block is the standard way of creating macros which make #ifndef YAML_CPP_DEPRECATED_EXPORT
// exporting from a DLL simpler. All files within this DLL are compiled with the # define YAML_CPP_DEPRECATED_EXPORT YAML_CPP_API YAML_CPP_DEPRECATED
// yaml_cpp_EXPORTS symbol defined on the command line. This symbol should not #endif
// 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 #ifndef YAML_CPP_DEPRECATED_NO_EXPORT
// manually) # define YAML_CPP_DEPRECATED_NO_EXPORT YAML_CPP_NO_EXPORT YAML_CPP_DEPRECATED
#ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake #endif
// or defined manually)
// #pragma message( "Defining YAML_CPP_API for DLL export" )
#define YAML_CPP_API __declspec(dllexport)
#else // yaml_cpp_EXPORTS
// #pragma message( "Defining YAML_CPP_API for DLL import" )
#define YAML_CPP_API __declspec(dllimport)
#endif // yaml_cpp_EXPORTS
#else // YAML_CPP_DLL
#define YAML_CPP_API
#endif // YAML_CPP_DLL
#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif /* DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 */

View File

@@ -23,22 +23,23 @@ class Emitter;
class EmitFromEvents : public EventHandler { class EmitFromEvents : public EventHandler {
public: public:
EmitFromEvents(Emitter& emitter); EmitFromEvents(Emitter& emitter);
~EmitFromEvents() override = default;
virtual void OnDocumentStart(const Mark& mark); void OnDocumentStart(const Mark& mark) override;
virtual void OnDocumentEnd(); void OnDocumentEnd() override;
virtual void OnNull(const Mark& mark, anchor_t anchor); void OnNull(const Mark& mark, anchor_t anchor) override;
virtual void OnAlias(const Mark& mark, anchor_t anchor); void OnAlias(const Mark& mark, anchor_t anchor) override;
virtual void OnScalar(const Mark& mark, const std::string& tag, void OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value); anchor_t anchor, const std::string& value) override;
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, void OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style); anchor_t anchor, EmitterStyle::value style) override;
virtual void OnSequenceEnd(); void OnSequenceEnd() override;
virtual void OnMapStart(const Mark& mark, const std::string& tag, void OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style); anchor_t anchor, EmitterStyle::value style) override;
virtual void OnMapEnd(); void OnMapEnd() override;
private: private:
void BeginNode(); void BeginNode();

View File

@@ -9,18 +9,24 @@
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
#include <cstring>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
#include <string_view>
#endif
#include "yaml-cpp/binary.h" #include "yaml-cpp/binary.h"
#include "yaml-cpp/dll.h" #include "yaml-cpp/dll.h"
#include "yaml-cpp/emitterdef.h" #include "yaml-cpp/emitterdef.h"
#include "yaml-cpp/emittermanip.h" #include "yaml-cpp/emittermanip.h"
#include "yaml-cpp/null.h" #include "yaml-cpp/null.h"
#include "yaml-cpp/ostream_wrapper.h" #include "yaml-cpp/ostream_wrapper.h"
#include "yaml-cpp/fptostring.h"
namespace YAML { namespace YAML {
class Binary; class Binary;
@@ -50,6 +56,7 @@ class YAML_CPP_API Emitter {
bool SetOutputCharset(EMITTER_MANIP value); bool SetOutputCharset(EMITTER_MANIP value);
bool SetStringFormat(EMITTER_MANIP value); bool SetStringFormat(EMITTER_MANIP value);
bool SetBoolFormat(EMITTER_MANIP value); bool SetBoolFormat(EMITTER_MANIP value);
bool SetNullFormat(EMITTER_MANIP value);
bool SetIntBase(EMITTER_MANIP value); bool SetIntBase(EMITTER_MANIP value);
bool SetSeqFormat(EMITTER_MANIP value); bool SetSeqFormat(EMITTER_MANIP value);
bool SetMapFormat(EMITTER_MANIP value); bool SetMapFormat(EMITTER_MANIP value);
@@ -58,6 +65,7 @@ class YAML_CPP_API Emitter {
bool SetPostCommentIndent(std::size_t n); bool SetPostCommentIndent(std::size_t n);
bool SetFloatPrecision(std::size_t n); bool SetFloatPrecision(std::size_t n);
bool SetDoublePrecision(std::size_t n); bool SetDoublePrecision(std::size_t n);
void RestoreGlobalModifiedSettings();
// local setters // local setters
Emitter& SetLocalValue(EMITTER_MANIP value); Emitter& SetLocalValue(EMITTER_MANIP value);
@@ -65,6 +73,7 @@ class YAML_CPP_API Emitter {
Emitter& SetLocalPrecision(const _Precision& precision); Emitter& SetLocalPrecision(const _Precision& precision);
// overloads of write // overloads of write
Emitter& Write(const char* str, std::size_t size);
Emitter& Write(const std::string& str); Emitter& Write(const std::string& str);
Emitter& Write(bool b); Emitter& Write(bool b);
Emitter& Write(char ch); Emitter& Write(char ch);
@@ -123,6 +132,7 @@ class YAML_CPP_API Emitter {
void SpaceOrIndentTo(bool requireSpace, std::size_t indent); void SpaceOrIndentTo(bool requireSpace, std::size_t indent);
const char* ComputeFullBoolName(bool b) const; const char* ComputeFullBoolName(bool b) const;
const char* ComputeNullName() const;
bool CanEmitNewline() const; bool CanEmitNewline() const;
private: private:
@@ -138,6 +148,7 @@ inline Emitter& Emitter::WriteIntegralType(T value) {
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
std::stringstream stream; std::stringstream stream;
stream.imbue(std::locale("C"));
PrepareIntegralStream(stream); PrepareIntegralStream(stream);
stream << value; stream << value;
m_stream << stream.str(); m_stream << stream.str();
@@ -155,6 +166,7 @@ inline Emitter& Emitter::WriteStreamable(T value) {
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
std::stringstream stream; std::stringstream stream;
stream.imbue(std::locale("C"));
SetStreamablePrecision<T>(stream); SetStreamablePrecision<T>(stream);
bool special = false; bool special = false;
@@ -164,19 +176,18 @@ inline Emitter& Emitter::WriteStreamable(T value) {
std::isnan(value)) { std::isnan(value)) {
special = true; special = true;
stream << ".nan"; stream << ".nan";
} else if (std::numeric_limits<T>::has_infinity) { } else if (std::numeric_limits<T>::has_infinity && std::isinf(value)) {
if (value == std::numeric_limits<T>::infinity()) {
special = true;
stream << ".inf";
} else if (value == -std::numeric_limits<T>::infinity()) {
special = true; special = true;
if (std::signbit(value)) {
stream << "-.inf"; stream << "-.inf";
} else {
stream << ".inf";
} }
} }
} }
if (!special) { if (!special) {
stream << value; stream << FpToString(value, stream.precision());
} }
m_stream << stream.str(); m_stream << stream.str();
@@ -196,8 +207,13 @@ inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
} }
// overloads of insertion // overloads of insertion
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
inline Emitter& operator<<(Emitter& emitter, const std::string_view& v) {
return emitter.Write(v.data(), v.size());
}
#endif
inline Emitter& operator<<(Emitter& emitter, const std::string& v) { inline Emitter& operator<<(Emitter& emitter, const std::string& v) {
return emitter.Write(v); return emitter.Write(v.data(), v.size());
} }
inline Emitter& operator<<(Emitter& emitter, bool v) { inline Emitter& operator<<(Emitter& emitter, bool v) {
return emitter.Write(v); return emitter.Write(v);
@@ -228,7 +244,7 @@ inline Emitter& operator<<(Emitter& emitter, const Binary& b) {
} }
inline Emitter& operator<<(Emitter& emitter, const char* v) { inline Emitter& operator<<(Emitter& emitter, const char* v) {
return emitter.Write(std::string(v)); return emitter.Write(v, std::strlen(v));
} }
inline Emitter& operator<<(Emitter& emitter, int v) { inline Emitter& operator<<(Emitter& emitter, int v) {

View File

@@ -19,6 +19,7 @@ enum EMITTER_MANIP {
// output character set // output character set
EmitNonAscii, EmitNonAscii,
EscapeNonAscii, EscapeNonAscii,
EscapeAsJson,
// string manipulators // string manipulators
// Auto, // duplicate // Auto, // duplicate
@@ -26,6 +27,12 @@ enum EMITTER_MANIP {
DoubleQuoted, DoubleQuoted,
Literal, Literal,
// null manipulators
LowerNull,
UpperNull,
CamelNull,
TildeNull,
// bool manipulators // bool manipulators
YesNoBool, // yes, no YesNoBool, // yes, no
TrueFalseBool, // true, false TrueFalseBool, // true, false
@@ -74,14 +81,14 @@ struct _Alias {
std::string content; 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 { struct _Anchor {
_Anchor(const std::string& content_) : content(content_) {} _Anchor(const std::string& content_) : content(content_) {}
std::string 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 _Tag {
struct Type { struct Type {
@@ -96,11 +103,11 @@ struct _Tag {
Type::value type; Type::value type;
}; };
inline _Tag VerbatimTag(const std::string content) { inline _Tag VerbatimTag(const std::string& content) {
return _Tag("", content, _Tag::Type::Verbatim); 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); return _Tag("", content, _Tag::Type::PrimaryHandle);
} }
@@ -108,7 +115,7 @@ inline _Tag LocalTag(const std::string& prefix, const std::string content) {
return _Tag(prefix, content, _Tag::Type::NamedHandle); 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); return _Tag("", content, _Tag::Type::NamedHandle);
} }
@@ -117,7 +124,7 @@ struct _Comment {
std::string content; 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 { struct _Precision {
_Precision(int floatPrecision_, int doublePrecision_) _Precision(int floatPrecision_, int doublePrecision_)

View File

@@ -8,9 +8,10 @@
#endif #endif
namespace YAML { namespace YAML {
struct EmitterStyle { namespace EmitterStyle {
enum value { Default, Block, Flow }; enum value { Default, Block, Flow };
}; }
} }
#endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -17,7 +17,7 @@ struct Mark;
class EventHandler { class EventHandler {
public: public:
virtual ~EventHandler() {} virtual ~EventHandler() = default;
virtual void OnDocumentStart(const Mark& mark) = 0; virtual void OnDocumentStart(const Mark& mark) = 0;
virtual void OnDocumentEnd() = 0; virtual void OnDocumentEnd() = 0;

View File

@@ -8,19 +8,12 @@
#endif #endif
#include "yaml-cpp/mark.h" #include "yaml-cpp/mark.h"
#include "yaml-cpp/noexcept.h"
#include "yaml-cpp/traits.h" #include "yaml-cpp/traits.h"
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
// 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
namespace YAML { namespace YAML {
// error messages // error messages
namespace ErrorMsg { namespace ErrorMsg {
@@ -55,6 +48,8 @@ const char* const UNKNOWN_TOKEN = "unknown token";
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar"; const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
const char* const EOF_IN_SCALAR = "illegal EOF in scalar"; const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
const char* const CHAR_IN_SCALAR = "illegal character in scalar"; const char* const CHAR_IN_SCALAR = "illegal character in scalar";
const char* const UNEXPECTED_SCALAR = "unexpected scalar";
const char* const UNEXPECTED_FLOW = "plain value cannot start with flow indicator character";
const char* const TAB_IN_INDENTATION = const char* const TAB_IN_INDENTATION =
"illegal tab when looking for indentation"; "illegal tab when looking for indentation";
const char* const FLOW_END = "illegal flow end"; const char* const FLOW_END = "illegal flow end";
@@ -72,7 +67,7 @@ const char* const ZERO_INDENT_IN_BLOCK =
const char* const CHAR_IN_BLOCK = "unexpected character in block scalar"; const char* const CHAR_IN_BLOCK = "unexpected character in block scalar";
const char* const AMBIGUOUS_ANCHOR = const char* const AMBIGUOUS_ANCHOR =
"cannot assign the same alias to multiple nodes"; "cannot assign the same alias to multiple nodes";
const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined"; const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined: ";
const char* const INVALID_NODE = const char* const INVALID_NODE =
"invalid node; this may result from using a map iterator as a sequence " "invalid node; this may result from using a map iterator as a sequence "
@@ -107,6 +102,12 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
return stream.str(); return stream.str();
} }
inline const std::string KEY_NOT_FOUND_WITH_KEY(const char* key) {
std::stringstream stream;
stream << KEY_NOT_FOUND << ": " << key;
return stream.str();
}
template <typename T> template <typename T>
inline const std::string KEY_NOT_FOUND_WITH_KEY( 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) {
@@ -127,6 +128,12 @@ inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) {
return stream.str(); return stream.str();
} }
inline const std::string BAD_SUBSCRIPT_WITH_KEY(const char* key) {
std::stringstream stream;
stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
return stream.str();
}
template <typename T> template <typename T>
inline const std::string BAD_SUBSCRIPT_WITH_KEY( inline const std::string BAD_SUBSCRIPT_WITH_KEY(
const T& key, typename enable_if<is_numeric<T>>::type* = nullptr) { const T& key, typename enable_if<is_numeric<T>>::type* = nullptr) {
@@ -143,13 +150,13 @@ inline const std::string INVALID_NODE_WITH_KEY(const std::string& key) {
stream << "invalid node; first invalid key: \"" << key << "\""; stream << "invalid node; first invalid key: \"" << key << "\"";
return stream.str(); return stream.str();
} }
} } // namespace ErrorMsg
class YAML_CPP_API Exception : public std::runtime_error { class YAML_CPP_API Exception : public std::runtime_error {
public: public:
Exception(const Mark& mark_, const std::string& msg_) Exception(const Mark& mark_, const std::string& msg_)
: std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {} : std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {}
virtual ~Exception() YAML_CPP_NOEXCEPT; ~Exception() YAML_CPP_NOEXCEPT override;
Exception(const Exception&) = default; Exception(const Exception&) = default;
@@ -175,7 +182,7 @@ class YAML_CPP_API ParserException : public Exception {
ParserException(const Mark& mark_, const std::string& msg_) ParserException(const Mark& mark_, const std::string& msg_)
: Exception(mark_, msg_) {} : Exception(mark_, msg_) {}
ParserException(const ParserException&) = default; ParserException(const ParserException&) = default;
virtual ~ParserException() YAML_CPP_NOEXCEPT; ~ParserException() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API RepresentationException : public Exception { class YAML_CPP_API RepresentationException : public Exception {
@@ -183,7 +190,7 @@ class YAML_CPP_API RepresentationException : public Exception {
RepresentationException(const Mark& mark_, const std::string& msg_) RepresentationException(const Mark& mark_, const std::string& msg_)
: Exception(mark_, msg_) {} : Exception(mark_, msg_) {}
RepresentationException(const RepresentationException&) = default; RepresentationException(const RepresentationException&) = default;
virtual ~RepresentationException() YAML_CPP_NOEXCEPT; ~RepresentationException() YAML_CPP_NOEXCEPT override;
}; };
// representation exceptions // representation exceptions
@@ -192,7 +199,7 @@ class YAML_CPP_API InvalidScalar : public RepresentationException {
InvalidScalar(const Mark& mark_) InvalidScalar(const Mark& mark_)
: RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {} : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
InvalidScalar(const InvalidScalar&) = default; InvalidScalar(const InvalidScalar&) = default;
virtual ~InvalidScalar() YAML_CPP_NOEXCEPT; ~InvalidScalar() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API KeyNotFound : public RepresentationException { class YAML_CPP_API KeyNotFound : public RepresentationException {
@@ -202,7 +209,7 @@ class YAML_CPP_API KeyNotFound : public RepresentationException {
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) { : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
} }
KeyNotFound(const KeyNotFound&) = default; KeyNotFound(const KeyNotFound&) = default;
virtual ~KeyNotFound() YAML_CPP_NOEXCEPT; ~KeyNotFound() YAML_CPP_NOEXCEPT override;
}; };
template <typename T> template <typename T>
@@ -210,7 +217,7 @@ class YAML_CPP_API TypedKeyNotFound : public KeyNotFound {
public: public:
TypedKeyNotFound(const Mark& mark_, const T& key_) TypedKeyNotFound(const Mark& mark_, const T& key_)
: KeyNotFound(mark_, key_), key(key_) {} : KeyNotFound(mark_, key_), key(key_) {}
virtual ~TypedKeyNotFound() YAML_CPP_NOEXCEPT {} ~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default;
T key; T key;
}; };
@@ -223,11 +230,11 @@ inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
class YAML_CPP_API InvalidNode : public RepresentationException { class YAML_CPP_API InvalidNode : public RepresentationException {
public: public:
InvalidNode(std::string key) InvalidNode(const std::string& key)
: RepresentationException(Mark::null_mark(), : RepresentationException(Mark::null_mark(),
ErrorMsg::INVALID_NODE_WITH_KEY(key)) {} ErrorMsg::INVALID_NODE_WITH_KEY(key)) {}
InvalidNode(const InvalidNode&) = default; InvalidNode(const InvalidNode&) = default;
virtual ~InvalidNode() YAML_CPP_NOEXCEPT; ~InvalidNode() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API BadConversion : public RepresentationException { class YAML_CPP_API BadConversion : public RepresentationException {
@@ -235,7 +242,7 @@ class YAML_CPP_API BadConversion : public RepresentationException {
explicit BadConversion(const Mark& mark_) explicit BadConversion(const Mark& mark_)
: RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {} : RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
BadConversion(const BadConversion&) = default; BadConversion(const BadConversion&) = default;
virtual ~BadConversion() YAML_CPP_NOEXCEPT; ~BadConversion() YAML_CPP_NOEXCEPT override;
}; };
template <typename T> template <typename T>
@@ -249,17 +256,16 @@ class YAML_CPP_API BadDereference : public RepresentationException {
BadDereference() BadDereference()
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {} : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
BadDereference(const BadDereference&) = default; BadDereference(const BadDereference&) = default;
virtual ~BadDereference() YAML_CPP_NOEXCEPT; ~BadDereference() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API BadSubscript : public RepresentationException { class YAML_CPP_API BadSubscript : public RepresentationException {
public: public:
template <typename Key> template <typename Key>
BadSubscript(const Key& key) BadSubscript(const Mark& mark_, const Key& key)
: RepresentationException(Mark::null_mark(), : RepresentationException(mark_, ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {}
ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {}
BadSubscript(const BadSubscript&) = default; BadSubscript(const BadSubscript&) = default;
virtual ~BadSubscript() YAML_CPP_NOEXCEPT; ~BadSubscript() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API BadPushback : public RepresentationException { class YAML_CPP_API BadPushback : public RepresentationException {
@@ -267,7 +273,7 @@ class YAML_CPP_API BadPushback : public RepresentationException {
BadPushback() BadPushback()
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {} : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
BadPushback(const BadPushback&) = default; BadPushback(const BadPushback&) = default;
virtual ~BadPushback() YAML_CPP_NOEXCEPT; ~BadPushback() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API BadInsert : public RepresentationException { class YAML_CPP_API BadInsert : public RepresentationException {
@@ -275,7 +281,7 @@ class YAML_CPP_API BadInsert : public RepresentationException {
BadInsert() BadInsert()
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {} : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
BadInsert(const BadInsert&) = default; BadInsert(const BadInsert&) = default;
virtual ~BadInsert() YAML_CPP_NOEXCEPT; ~BadInsert() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API EmitterException : public Exception { class YAML_CPP_API EmitterException : public Exception {
@@ -283,17 +289,17 @@ class YAML_CPP_API EmitterException : public Exception {
EmitterException(const std::string& msg_) EmitterException(const std::string& msg_)
: Exception(Mark::null_mark(), msg_) {} : Exception(Mark::null_mark(), msg_) {}
EmitterException(const EmitterException&) = default; EmitterException(const EmitterException&) = default;
virtual ~EmitterException() YAML_CPP_NOEXCEPT; ~EmitterException() YAML_CPP_NOEXCEPT override;
}; };
class YAML_CPP_API BadFile : public Exception { class YAML_CPP_API BadFile : public Exception {
public: public:
BadFile() : Exception(Mark::null_mark(), ErrorMsg::BAD_FILE) {} explicit BadFile(const std::string& filename)
: Exception(Mark::null_mark(),
std::string(ErrorMsg::BAD_FILE) + ": " + filename) {}
BadFile(const BadFile&) = default; BadFile(const BadFile&) = default;
virtual ~BadFile() YAML_CPP_NOEXCEPT; ~BadFile() YAML_CPP_NOEXCEPT override;
}; };
} } // namespace YAML
#undef YAML_CPP_NOEXCEPT
#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -0,0 +1,15 @@
#ifndef YAML_H_FPTOSTRING
#define YAML_H_FPTOSTRING
#include "yaml-cpp/dll.h"
#include <string>
namespace YAML {
// "precision = 0" refers to shortest known unique representation of the value
YAML_CPP_API std::string FpToString(float v, size_t precision = 0);
YAML_CPP_API std::string FpToString(double v, size_t precision = 0);
YAML_CPP_API std::string FpToString(long double v, size_t precision = 0);
}
#endif

View File

@@ -8,18 +8,28 @@
#endif #endif
#include <array> #include <array>
#include <cmath>
#include <limits> #include <limits>
#include <list> #include <list>
#include <map> #include <map>
#include <unordered_map>
#include <sstream> #include <sstream>
#include <type_traits>
#include <valarray>
#include <vector> #include <vector>
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
#include <string_view>
#endif
#include "yaml-cpp/binary.h" #include "yaml-cpp/binary.h"
#include "yaml-cpp/node/impl.h" #include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/iterator.h" #include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/node/node.h" #include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/type.h" #include "yaml-cpp/node/type.h"
#include "yaml-cpp/null.h" #include "yaml-cpp/null.h"
#include "yaml-cpp/fptostring.h"
namespace YAML { namespace YAML {
class Binary; class Binary;
@@ -71,14 +81,33 @@ struct convert<std::string> {
// C-strings can only be encoded // C-strings can only be encoded
template <> template <>
struct convert<const char*> { struct convert<const char*> {
static Node encode(const char*& rhs) { return Node(rhs); } static Node encode(const char* rhs) { return Node(rhs); }
};
template <>
struct convert<char*> {
static Node encode(const char* rhs) { return Node(rhs); }
}; };
template <std::size_t N> template <std::size_t N>
struct convert<const char[N]> { struct convert<char[N]> {
static Node encode(const char(&rhs)[N]) { return Node(rhs); } static Node encode(const char* rhs) { return Node(rhs); }
}; };
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
template <>
struct convert<std::string_view> {
static Node encode(std::string_view rhs) { return Node(std::string(rhs)); }
static bool decode(const Node& node, std::string_view& rhs) {
if (!node.IsScalar())
return false;
rhs = node.Scalar();
return true;
}
};
#endif
template <> template <>
struct convert<_Null> { struct convert<_Null> {
static Node encode(const _Null& /* rhs */) { return Node(); } static Node encode(const _Null& /* rhs */) { return Node(); }
@@ -88,24 +117,81 @@ struct convert<_Null> {
} }
}; };
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 << FpToString(rhs, stream.precision());
}
}
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;
}
template <typename T>
typename std::enable_if<(std::is_same<T, unsigned char>::value ||
std::is_same<T, signed char>::value), bool>::type
ConvertStreamTo(std::stringstream& stream, T& rhs) {
int num;
if ((stream >> std::noskipws >> num) && (stream >> std::ws).eof()) {
if (num >= (std::numeric_limits<T>::min)() &&
num <= (std::numeric_limits<T>::max)()) {
rhs = static_cast<T>(num);
return true;
}
}
return false;
}
template <typename T>
typename std::enable_if<!(std::is_same<T, unsigned char>::value ||
std::is_same<T, signed char>::value), bool>::type
ConvertStreamTo(std::stringstream& stream, T& rhs) {
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) {
return true;
}
return false;
}
}
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ #define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
template <> \ template <> \
struct convert<type> { \ struct convert<type> { \
\
static Node encode(const type& rhs) { \ static Node encode(const type& rhs) { \
std::stringstream stream; \ std::stringstream stream; \
stream.imbue(std::locale("C")); \
stream.precision(std::numeric_limits<type>::max_digits10); \ stream.precision(std::numeric_limits<type>::max_digits10); \
stream << rhs; \ conversion::inner_encode(rhs, stream); \
return Node(stream.str()); \ return Node(stream.str()); \
} \ } \
\ \
static bool decode(const Node& node, type& rhs) { \ static bool decode(const Node& node, type& rhs) { \
if (node.Type() != NodeType::Scalar) \ if (node.Type() != NodeType::Scalar) { \
return false; \ return false; \
} \
const std::string& input = node.Scalar(); \ const std::string& input = node.Scalar(); \
std::stringstream stream(input); \ std::stringstream stream(input); \
stream.imbue(std::locale("C")); \
stream.unsetf(std::ios::dec); \ stream.unsetf(std::ios::dec); \
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \ if ((stream.peek() == '-') && std::is_unsigned<type>::value) { \
return false; \
} \
if (conversion::ConvertStreamTo(stream, rhs)) { \
return true; \ return true; \
} \
if (std::numeric_limits<type>::has_infinity) { \ if (std::numeric_limits<type>::has_infinity) { \
if (conversion::IsInfinity(input)) { \ if (conversion::IsInfinity(input)) { \
rhs = std::numeric_limits<type>::infinity(); \ rhs = std::numeric_limits<type>::infinity(); \
@@ -163,81 +249,104 @@ struct convert<bool> {
}; };
// std::map // std::map
template <typename K, typename V> template <typename K, typename V, typename C, typename A>
struct convert<std::map<K, V>> { struct convert<std::map<K, V, C, A>> {
static Node encode(const std::map<K, V>& rhs) { static Node encode(const std::map<K, V, C, A>& rhs) {
Node node(NodeType::Map); Node node(NodeType::Map);
for (typename std::map<K, V>::const_iterator it = rhs.begin(); for (const auto& element : rhs)
it != rhs.end(); ++it) node.force_insert(element.first, element.second);
node.force_insert(it->first, it->second);
return node; return node;
} }
static bool decode(const Node& node, std::map<K, V>& rhs) { static bool decode(const Node& node, std::map<K, V, C, A>& rhs) {
if (!node.IsMap()) if (!node.IsMap())
return false; return false;
rhs.clear(); rhs.clear();
for (const_iterator it = node.begin(); it != node.end(); ++it) for (const auto& element : node)
#if defined(__GNUC__) && __GNUC__ < 4 #if defined(__GNUC__) && __GNUC__ < 4
// workaround for GCC 3: // workaround for GCC 3:
rhs[it->first.template as<K>()] = it->second.template as<V>(); rhs[element.first.template as<K>()] = element.second.template as<V>();
#else #else
rhs[it->first.as<K>()] = it->second.as<V>(); rhs[element.first.as<K>()] = element.second.as<V>();
#endif
return true;
}
};
// std::unordered_map
template <typename K, typename V, typename H, typename P, typename A>
struct convert<std::unordered_map<K, V, H, P, A>> {
static Node encode(const std::unordered_map<K, V, H, P, A>& rhs) {
Node node(NodeType::Map);
for (const auto& element : rhs)
node.force_insert(element.first, element.second);
return node;
}
static bool decode(const Node& node, std::unordered_map<K, V, H, P, A>& rhs) {
if (!node.IsMap())
return false;
rhs.clear();
for (const auto& element : node)
#if defined(__GNUC__) && __GNUC__ < 4
// workaround for GCC 3:
rhs[element.first.template as<K>()] = element.second.template as<V>();
#else
rhs[element.first.as<K>()] = element.second.as<V>();
#endif #endif
return true; return true;
} }
}; };
// std::vector // std::vector
template <typename T> template <typename T, typename A>
struct convert<std::vector<T>> { struct convert<std::vector<T, A>> {
static Node encode(const std::vector<T>& rhs) { static Node encode(const std::vector<T, A>& rhs) {
Node node(NodeType::Sequence); Node node(NodeType::Sequence);
for (typename std::vector<T>::const_iterator it = rhs.begin(); for (const auto& element : rhs)
it != rhs.end(); ++it) node.push_back(element);
node.push_back(*it);
return node; return node;
} }
static bool decode(const Node& node, std::vector<T>& rhs) { static bool decode(const Node& node, std::vector<T, A>& rhs) {
if (!node.IsSequence()) if (!node.IsSequence())
return false; return false;
rhs.clear(); rhs.clear();
for (const_iterator it = node.begin(); it != node.end(); ++it) for (const auto& element : node)
#if defined(__GNUC__) && __GNUC__ < 4 #if defined(__GNUC__) && __GNUC__ < 4
// workaround for GCC 3: // workaround for GCC 3:
rhs.push_back(it->template as<T>()); rhs.push_back(element.template as<T>());
#else #else
rhs.push_back(it->as<T>()); rhs.push_back(element.as<T>());
#endif #endif
return true; return true;
} }
}; };
// std::list // std::list
template <typename T> template <typename T, typename A>
struct convert<std::list<T>> { struct convert<std::list<T,A>> {
static Node encode(const std::list<T>& rhs) { static Node encode(const std::list<T,A>& rhs) {
Node node(NodeType::Sequence); Node node(NodeType::Sequence);
for (typename std::list<T>::const_iterator it = rhs.begin(); for (const auto& element : rhs)
it != rhs.end(); ++it) node.push_back(element);
node.push_back(*it);
return node; return node;
} }
static bool decode(const Node& node, std::list<T>& rhs) { static bool decode(const Node& node, std::list<T,A>& rhs) {
if (!node.IsSequence()) if (!node.IsSequence())
return false; return false;
rhs.clear(); rhs.clear();
for (const_iterator it = node.begin(); it != node.end(); ++it) for (const auto& element : node)
#if defined(__GNUC__) && __GNUC__ < 4 #if defined(__GNUC__) && __GNUC__ < 4
// workaround for GCC 3: // workaround for GCC 3:
rhs.push_back(it->template as<T>()); rhs.push_back(element.template as<T>());
#else #else
rhs.push_back(it->as<T>()); rhs.push_back(element.as<T>());
#endif #endif
return true; return true;
} }
@@ -276,6 +385,37 @@ struct convert<std::array<T, N>> {
} }
}; };
// std::valarray
template <typename T>
struct convert<std::valarray<T>> {
static Node encode(const std::valarray<T>& rhs) {
Node node(NodeType::Sequence);
for (const auto& element : rhs) {
node.push_back(element);
}
return node;
}
static bool decode(const Node& node, std::valarray<T>& rhs) {
if (!node.IsSequence()) {
return false;
}
rhs.resize(node.size());
for (auto i = 0u; i < node.size(); ++i) {
#if defined(__GNUC__) && __GNUC__ < 4
// workaround for GCC 3:
rhs[i] = node[i].template as<T>();
#else
rhs[i] = node[i].as<T>();
#endif
}
return true;
}
};
// std::pair // std::pair
template <typename T, typename U> template <typename T, typename U>
struct convert<std::pair<T, U>> { struct convert<std::pair<T, U>> {

View File

@@ -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

View File

@@ -9,6 +9,8 @@
#include "yaml-cpp/node/detail/node.h" #include "yaml-cpp/node/detail/node.h"
#include "yaml-cpp/node/detail/node_data.h" #include "yaml-cpp/node/detail/node_data.h"
#include <algorithm>
#include <type_traits> #include <type_traits>
namespace YAML { namespace YAML {
@@ -33,7 +35,7 @@ struct get_idx<Key,
static node* get(std::vector<node*>& sequence, const Key& key, static node* get(std::vector<node*>& sequence, const Key& key,
shared_memory_holder pMemory) { shared_memory_holder pMemory) {
if (key > sequence.size() || (key > 0 && !sequence[key - 1]->is_defined())) if (key > sequence.size() || (key > 0 && !sequence[key - 1]->is_defined()))
return 0; return nullptr;
if (key == sequence.size()) if (key == sequence.size())
sequence.push_back(&pMemory->create_node()); sequence.push_back(&pMemory->create_node());
return sequence[key]; return sequence[key];
@@ -58,7 +60,9 @@ struct get_idx<Key, typename std::enable_if<std::is_signed<Key>::value>::type> {
template <typename Key, typename Enable = void> template <typename Key, typename Enable = void>
struct remove_idx { struct remove_idx {
static bool remove(std::vector<node*>&, const Key&) { return false; } static bool remove(std::vector<node*>&, const Key&, std::size_t&) {
return false;
}
}; };
template <typename Key> template <typename Key>
@@ -66,11 +70,15 @@ struct remove_idx<
Key, typename std::enable_if<std::is_unsigned<Key>::value && Key, typename std::enable_if<std::is_unsigned<Key>::value &&
!std::is_same<Key, bool>::value>::type> { !std::is_same<Key, bool>::value>::type> {
static bool remove(std::vector<node*>& sequence, const Key& key) { static bool remove(std::vector<node*>& sequence, const Key& key,
std::size_t& seqSize) {
if (key >= sequence.size()) { if (key >= sequence.size()) {
return false; return false;
} else { } else {
sequence.erase(sequence.begin() + key); sequence.erase(sequence.begin() + key);
if (seqSize > key) {
--seqSize;
}
return true; return true;
} }
} }
@@ -80,9 +88,10 @@ template <typename Key>
struct remove_idx<Key, struct remove_idx<Key,
typename std::enable_if<std::is_signed<Key>::value>::type> { typename std::enable_if<std::is_signed<Key>::value>::type> {
static bool remove(std::vector<node*>& sequence, const Key& key) { static bool remove(std::vector<node*>& sequence, const Key& key,
std::size_t& seqSize) {
return key >= 0 ? remove_idx<std::size_t>::remove( return key >= 0 ? remove_idx<std::size_t>::remove(
sequence, static_cast<std::size_t>(key)) sequence, static_cast<std::size_t>(key), seqSize)
: false; : false;
} }
}; };
@@ -97,7 +106,11 @@ inline bool node::equals(const T& rhs, shared_memory_holder pMemory) {
} }
inline bool node::equals(const char* rhs, shared_memory_holder pMemory) { inline bool node::equals(const char* rhs, shared_memory_holder pMemory) {
return equals<std::string>(rhs, pMemory); std::string lhs;
if (convert<std::string>::decode(Node(*this, std::move(pMemory)), lhs)) {
return lhs == rhs;
}
return false;
} }
// indexing // indexing
@@ -115,16 +128,14 @@ inline node* node_data::get(const Key& key,
return pNode; return pNode;
return nullptr; return nullptr;
case NodeType::Scalar: case NodeType::Scalar:
throw BadSubscript(key); throw BadSubscript(m_mark, key);
} }
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { auto it = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) {
if (it->first->equals(key, pMemory)) { return m.first->equals(key, pMemory);
return it->second; });
}
}
return nullptr; return it != m_map.end() ? it->second : nullptr;
} }
template <typename Key> template <typename Key>
@@ -143,14 +154,16 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
convert_to_map(pMemory); convert_to_map(pMemory);
break; break;
case NodeType::Scalar: case NodeType::Scalar:
throw BadSubscript(key); throw BadSubscript(m_mark, key);
} }
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { auto it = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) {
if (it->first->equals(key, pMemory)) { return m.first->equals(key, pMemory);
});
if (it != m_map.end()) {
return *it->second; return *it->second;
} }
}
node& k = convert_to_node(key, pMemory); node& k = convert_to_node(key, pMemory);
node& v = pMemory->create_node(); node& v = pMemory->create_node();
@@ -161,8 +174,10 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
template <typename Key> template <typename Key>
inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) { inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
if (m_type == NodeType::Sequence) { if (m_type == NodeType::Sequence) {
return remove_idx<Key>::remove(m_sequence, key); return remove_idx<Key>::remove(m_sequence, key, m_seqSize);
} else if (m_type == NodeType::Map) { }
if (m_type == NodeType::Map) {
kv_pairs::iterator it = m_undefinedPairs.begin(); kv_pairs::iterator it = m_undefinedPairs.begin();
while (it != m_undefinedPairs.end()) { while (it != m_undefinedPairs.end()) {
kv_pairs::iterator jt = std::next(it); kv_pairs::iterator jt = std::next(it);
@@ -172,13 +187,15 @@ inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
it = jt; it = jt;
} }
for (node_map::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) { auto iter = std::find_if(m_map.begin(), m_map.end(), [&](const kv_pair m) {
if (iter->first->equals(key, pMemory)) { return m.first->equals(key, pMemory);
});
if (iter != m_map.end()) {
m_map.erase(iter); m_map.erase(iter);
return true; return true;
} }
} }
}
return false; return false;
} }

View File

@@ -26,7 +26,7 @@ class iterator_base {
template <typename> template <typename>
friend class iterator_base; friend class iterator_base;
struct enabler {}; struct enabler {};
typedef node_iterator base_type; using base_type = node_iterator;
struct proxy { struct proxy {
explicit proxy(const V& x) : m_ref(x) {} explicit proxy(const V& x) : m_ref(x) {}
@@ -41,7 +41,7 @@ class iterator_base {
using value_type = V; using value_type = V;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using pointer = V*; using pointer = V*;
using reference = V; using reference = V&;
public: public:
iterator_base() : m_iterator(), m_pMemory() {} iterator_base() : m_iterator(), m_pMemory() {}

View File

@@ -20,8 +20,8 @@ template <typename V>
class iterator_base; class iterator_base;
} }
typedef detail::iterator_base<detail::iterator_value> iterator; using iterator = detail::iterator_base<detail::iterator_value>;
typedef detail::iterator_base<const detail::iterator_value> const_iterator; using const_iterator = detail::iterator_base<const detail::iterator_value>;
} }
#endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -27,7 +27,7 @@ class YAML_CPP_API memory {
void merge(const memory& rhs); void merge(const memory& rhs);
private: private:
typedef std::set<shared_node> Nodes; using Nodes = std::set<shared_node>;
Nodes m_nodes; Nodes m_nodes;
}; };

View File

@@ -13,12 +13,18 @@
#include "yaml-cpp/node/ptr.h" #include "yaml-cpp/node/ptr.h"
#include "yaml-cpp/node/type.h" #include "yaml-cpp/node/type.h"
#include <set> #include <set>
#include <atomic>
namespace YAML { namespace YAML {
namespace detail { namespace detail {
class node { class node {
private:
struct less {
bool operator ()(const node* l, const node* r) const {return l->m_index < r->m_index;}
};
public: public:
node() : m_pRef(new node_ref), m_dependencies{} {} node() : m_pRef(new node_ref), m_dependencies{}, m_index{} {}
node(const node&) = delete; node(const node&) = delete;
node& operator=(const node&) = delete; node& operator=(const node&) = delete;
@@ -42,9 +48,8 @@ class node {
return; return;
m_pRef->mark_defined(); m_pRef->mark_defined();
for (nodes::iterator it = m_dependencies.begin(); for (node* dependency : m_dependencies)
it != m_dependencies.end(); ++it) dependency->mark_defined();
(*it)->mark_defined();
m_dependencies.clear(); m_dependencies.clear();
} }
@@ -109,6 +114,7 @@ class node {
void push_back(node& input, shared_memory_holder pMemory) { void push_back(node& input, shared_memory_holder pMemory) {
m_pRef->push_back(input, pMemory); m_pRef->push_back(input, pMemory);
input.add_dependency(*this); input.add_dependency(*this);
m_index = m_amount.fetch_add(1);
} }
void insert(node& key, node& value, shared_memory_holder pMemory) { void insert(node& key, node& value, shared_memory_holder pMemory) {
m_pRef->insert(key, value, pMemory); m_pRef->insert(key, value, pMemory);
@@ -120,7 +126,7 @@ class node {
template <typename Key> template <typename Key>
node* get(const Key& key, shared_memory_holder pMemory) const { 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 // 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). // key).
return static_cast<const node_ref&>(*m_pRef).get(key, pMemory); return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
} }
@@ -137,7 +143,7 @@ class node {
node* get(node& key, shared_memory_holder pMemory) const { node* get(node& key, shared_memory_holder pMemory) const {
// NOTE: this returns a non-const node so that the top-level Node can wrap // 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). // key).
return static_cast<const node_ref&>(*m_pRef).get(key, pMemory); return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
} }
@@ -160,8 +166,10 @@ class node {
private: private:
shared_node_ref m_pRef; shared_node_ref m_pRef;
typedef std::set<node*> nodes; using nodes = std::set<node*, less>;
nodes m_dependencies; nodes m_dependencies;
size_t m_index;
static YAML_CPP_API std::atomic<size_t> m_amount;
}; };
} // namespace detail } // namespace detail
} // namespace YAML } // namespace YAML

View File

@@ -60,8 +60,8 @@ class YAML_CPP_API node_data {
node_iterator end(); node_iterator end();
// sequence // sequence
void push_back(node& node, shared_memory_holder pMemory); void push_back(node& node, const shared_memory_holder& pMemory);
void insert(node& key, node& value, shared_memory_holder pMemory); void insert(node& key, node& value, const shared_memory_holder& pMemory);
// indexing // indexing
template <typename Key> template <typename Key>
@@ -71,9 +71,9 @@ class YAML_CPP_API node_data {
template <typename Key> template <typename Key>
bool remove(const Key& key, shared_memory_holder pMemory); bool remove(const Key& key, shared_memory_holder pMemory);
node* get(node& key, shared_memory_holder pMemory) const; node* get(node& key, const shared_memory_holder& pMemory) const;
node& get(node& key, shared_memory_holder pMemory); node& get(node& key, const shared_memory_holder& pMemory);
bool remove(node& key, shared_memory_holder pMemory); bool remove(node& key, const shared_memory_holder& pMemory);
// map // map
template <typename Key, typename Value> template <typename Key, typename Value>
@@ -91,8 +91,8 @@ class YAML_CPP_API node_data {
void reset_map(); void reset_map();
void insert_map_pair(node& key, node& value); void insert_map_pair(node& key, node& value);
void convert_to_map(shared_memory_holder pMemory); void convert_to_map(const shared_memory_holder& pMemory);
void convert_sequence_to_map(shared_memory_holder pMemory); void convert_sequence_to_map(const shared_memory_holder& pMemory);
template <typename T> template <typename T>
static node& convert_to_node(const T& rhs, shared_memory_holder pMemory); static node& convert_to_node(const T& rhs, shared_memory_holder pMemory);
@@ -108,17 +108,17 @@ class YAML_CPP_API node_data {
std::string m_scalar; std::string m_scalar;
// sequence // sequence
typedef std::vector<node*> node_seq; using node_seq = std::vector<node *>;
node_seq m_sequence; node_seq m_sequence;
mutable std::size_t m_seqSize; mutable std::size_t m_seqSize;
// map // map
typedef std::vector<std::pair<node*, node*>> node_map; using node_map = std::vector<std::pair<node*, node*>>;
node_map m_map; node_map m_map;
typedef std::pair<node*, node*> kv_pair; using kv_pair = std::pair<node*, node*>;
typedef std::list<kv_pair> kv_pairs; using kv_pairs = std::list<kv_pair>;
mutable kv_pairs m_undefinedPairs; mutable kv_pairs m_undefinedPairs;
}; };
} }

View File

@@ -24,7 +24,7 @@ struct iterator_type {
template <typename V> template <typename V>
struct node_iterator_value : public std::pair<V*, 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(nullptr) {} node_iterator_value() : kv(), pNode(nullptr) {}
explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {} explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {}
@@ -36,26 +36,23 @@ struct node_iterator_value : public std::pair<V*, V*> {
V* pNode; V* pNode;
}; };
typedef std::vector<node*> node_seq; using node_seq = std::vector<node *>;
typedef std::vector<std::pair<node*, node*>> node_map; using node_map = std::vector<std::pair<node*, node*>>;
template <typename V> template <typename V>
struct node_iterator_type { struct node_iterator_type {
typedef node_seq::iterator seq; using seq = node_seq::iterator;
typedef node_map::iterator map; using map = node_map::iterator;
}; };
template <typename V> template <typename V>
struct node_iterator_type<const V> { struct node_iterator_type<const V> {
typedef node_seq::const_iterator seq; using seq = node_seq::const_iterator;
typedef node_map::const_iterator map; using map = node_map::const_iterator;
}; };
template <typename V> template <typename V>
class node_iterator_base class node_iterator_base {
: public std::iterator<std::forward_iterator_tag, node_iterator_value<V>,
std::ptrdiff_t, node_iterator_value<V>*,
node_iterator_value<V>> {
private: private:
struct enabler {}; struct enabler {};
@@ -68,9 +65,13 @@ class node_iterator_base
}; };
public: public:
typedef typename node_iterator_type<V>::seq SeqIter; using iterator_category = std::forward_iterator_tag;
typedef typename node_iterator_type<V>::map MapIter; using value_type = node_iterator_value<V>;
typedef node_iterator_value<V> value_type; 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() node_iterator_base()
: m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {} : m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {}
@@ -172,8 +173,8 @@ class node_iterator_base
MapIter m_mapIt, m_mapEnd; MapIter m_mapIt, m_mapEnd;
}; };
typedef node_iterator_base<node> node_iterator; using node_iterator = node_iterator_base<node>;
typedef node_iterator_base<const node> const_node_iterator; using const_node_iterator = node_iterator_base<const node>;
} }
} }

View File

@@ -42,11 +42,7 @@ inline Node::Node(const detail::iterator_value& rhs)
m_pMemory(rhs.m_pMemory), m_pMemory(rhs.m_pMemory),
m_pNode(rhs.m_pNode) {} m_pNode(rhs.m_pNode) {}
inline Node::Node(const Node& rhs) inline Node::Node(const Node&) = default;
: m_isValid(rhs.m_isValid),
m_invalidKey(rhs.m_invalidKey),
m_pMemory(rhs.m_pMemory),
m_pNode(rhs.m_pNode) {}
inline Node::Node(Zombie) inline Node::Node(Zombie)
: m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {} : m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}
@@ -57,7 +53,7 @@ inline Node::Node(Zombie, const std::string& key)
inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory) inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory)
: m_isValid(true), m_invalidKey{}, 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 { inline void Node::EnsureNodeExists() const {
if (!m_isValid) if (!m_isValid)
@@ -101,7 +97,7 @@ struct as_if {
if (!node.m_pNode) if (!node.m_pNode)
return fallback; return fallback;
T t; T t = fallback;
if (convert<T>::decode(node, t)) if (convert<T>::decode(node, t))
return t; return t;
return fallback; return fallback;
@@ -114,6 +110,8 @@ struct as_if<std::string, S> {
const Node& node; const Node& node;
std::string operator()(const S& fallback) const { std::string operator()(const S& fallback) const {
if (node.Type() == NodeType::Null)
return "null";
if (node.Type() != NodeType::Scalar) if (node.Type() != NodeType::Scalar)
return fallback; return fallback;
return node.Scalar(); return node.Scalar();
@@ -126,8 +124,8 @@ struct as_if<T, void> {
const Node& node; const Node& node;
T operator()() const { T operator()() const {
if (!node.m_pNode) if (!node.m_pNode) // no fallback
throw TypedBadConversion<T>(node.Mark()); throw InvalidNode(node.m_invalidKey);
T t; T t;
if (convert<T>::decode(node, t)) if (convert<T>::decode(node, t))
@@ -142,6 +140,10 @@ struct as_if<std::string, void> {
const Node& node; const Node& node;
std::string operator()() const { std::string operator()() const {
if (node.Type() == NodeType::Undefined) // no fallback
throw InvalidNode(node.m_invalidKey);
if (node.Type() == NodeType::Null)
return "null";
if (node.Type() != NodeType::Scalar) if (node.Type() != NodeType::Scalar)
throw TypedBadConversion<std::string>(node.Mark()); throw TypedBadConversion<std::string>(node.Mark());
return node.Scalar(); return node.Scalar();
@@ -176,8 +178,6 @@ inline const std::string& Node::Tag() const {
} }
inline void Node::SetTag(const std::string& tag) { inline void Node::SetTag(const std::string& tag) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->set_tag(tag); m_pNode->set_tag(tag);
} }
@@ -189,8 +189,6 @@ inline EmitterStyle::value Node::Style() const {
} }
inline void Node::SetStyle(EmitterStyle::value style) { inline void Node::SetStyle(EmitterStyle::value style) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->set_style(style); m_pNode->set_style(style);
} }
@@ -206,15 +204,11 @@ inline bool Node::is(const Node& rhs) const {
template <typename T> template <typename T>
inline Node& Node::operator=(const T& rhs) { inline Node& Node::operator=(const T& rhs) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
Assign(rhs); Assign(rhs);
return *this; return *this;
} }
inline Node& Node::operator=(const Node& rhs) { inline Node& Node::operator=(const Node& rhs) {
if (!m_isValid || !rhs.m_isValid)
throw InvalidNode(m_invalidKey);
if (is(rhs)) if (is(rhs))
return *this; return *this;
AssignNode(rhs); AssignNode(rhs);
@@ -237,29 +231,21 @@ inline void Node::Assign(const T& rhs) {
template <> template <>
inline void Node::Assign(const std::string& rhs) { inline void Node::Assign(const std::string& rhs) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->set_scalar(rhs); m_pNode->set_scalar(rhs);
} }
inline void Node::Assign(const char* rhs) { inline void Node::Assign(const char* rhs) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->set_scalar(rhs); m_pNode->set_scalar(rhs);
} }
inline void Node::Assign(char* rhs) { inline void Node::Assign(char* rhs) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->set_scalar(rhs); m_pNode->set_scalar(rhs);
} }
inline void Node::AssignData(const Node& rhs) { inline void Node::AssignData(const Node& rhs) {
if (!m_isValid || !rhs.m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
rhs.EnsureNodeExists(); rhs.EnsureNodeExists();
@@ -268,7 +254,7 @@ inline void Node::AssignData(const Node& rhs) {
} }
inline void Node::AssignNode(const Node& rhs) { inline void Node::AssignNode(const Node& rhs) {
if (!m_isValid || !rhs.m_isValid) if (!m_isValid)
throw InvalidNode(m_invalidKey); throw InvalidNode(m_invalidKey);
rhs.EnsureNodeExists(); rhs.EnsureNodeExists();
@@ -324,8 +310,6 @@ inline void Node::push_back(const T& rhs) {
} }
inline void Node::push_back(const Node& rhs) { inline void Node::push_back(const Node& rhs) {
if (!m_isValid || !rhs.m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
rhs.EnsureNodeExists(); rhs.EnsureNodeExists();
@@ -333,51 +317,6 @@ inline void Node::push_back(const Node& rhs) {
m_pMemory->merge(*rhs.m_pMemory); m_pMemory->merge(*rhs.m_pMemory);
} }
// helpers for indexing
namespace detail {
template <typename T>
struct to_value_t {
explicit to_value_t(const T& t_) : t(t_) {}
const T& t;
typedef const T& return_type;
const T& operator()() const { return t; }
};
template <>
struct to_value_t<const char*> {
explicit to_value_t(const char* t_) : t(t_) {}
const char* t;
typedef std::string return_type;
const std::string operator()() const { return t; }
};
template <>
struct to_value_t<char*> {
explicit to_value_t(char* t_) : t(t_) {}
const char* t;
typedef std::string return_type;
const std::string operator()() const { return t; }
};
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;
const std::string operator()() const { return t; }
};
// converts C-strings to std::strings so they can be copied
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> template<typename Key>
std::string key_to_string(const Key& key) { std::string key_to_string(const Key& key) {
return streamable_to_string<Key, is_streamable<std::stringstream, Key>::value>().impl(key); return streamable_to_string<Key, is_streamable<std::stringstream, Key>::value>().impl(key);
@@ -386,11 +325,9 @@ std::string key_to_string(const Key& key) {
// indexing // indexing
template <typename Key> template <typename Key>
inline const Node Node::operator[](const Key& key) const { inline const Node Node::operator[](const Key& key) const {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
detail::node* value = static_cast<const detail::node&>(*m_pNode).get( detail::node* value =
detail::to_value(key), m_pMemory); static_cast<const detail::node&>(*m_pNode).get(key, m_pMemory);
if (!value) { if (!value) {
return Node(ZombieNode, key_to_string(key)); return Node(ZombieNode, key_to_string(key));
} }
@@ -399,24 +336,18 @@ inline const Node Node::operator[](const Key& key) const {
template <typename Key> template <typename Key>
inline Node Node::operator[](const Key& key) { inline Node Node::operator[](const Key& key) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
detail::node& value = m_pNode->get(detail::to_value(key), m_pMemory); detail::node& value = m_pNode->get(key, m_pMemory);
return Node(value, m_pMemory); return Node(value, m_pMemory);
} }
template <typename Key> template <typename Key>
inline bool Node::remove(const Key& key) { inline bool Node::remove(const Key& key) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
return m_pNode->remove(detail::to_value(key), m_pMemory); return m_pNode->remove(key, m_pMemory);
} }
inline const Node Node::operator[](const Node& key) const { inline const Node Node::operator[](const Node& key) const {
if (!m_isValid || !key.m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
key.EnsureNodeExists(); key.EnsureNodeExists();
m_pMemory->merge(*key.m_pMemory); m_pMemory->merge(*key.m_pMemory);
@@ -429,8 +360,6 @@ inline const Node Node::operator[](const Node& key) const {
} }
inline Node Node::operator[](const Node& key) { inline Node Node::operator[](const Node& key) {
if (!m_isValid || !key.m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
key.EnsureNodeExists(); key.EnsureNodeExists();
m_pMemory->merge(*key.m_pMemory); m_pMemory->merge(*key.m_pMemory);
@@ -439,8 +368,6 @@ inline Node Node::operator[](const Node& key) {
} }
inline bool Node::remove(const Node& key) { inline bool Node::remove(const Node& key) {
if (!m_isValid || !key.m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
key.EnsureNodeExists(); key.EnsureNodeExists();
return m_pNode->remove(*key.m_pNode, m_pMemory); return m_pNode->remove(*key.m_pNode, m_pMemory);
@@ -449,11 +376,8 @@ inline bool Node::remove(const Node& key) {
// map // map
template <typename Key, typename Value> template <typename Key, typename Value>
inline void Node::force_insert(const Key& key, const Value& value) { inline void Node::force_insert(const Key& key, const Value& value) {
if (!m_isValid)
throw InvalidNode(m_invalidKey);
EnsureNodeExists(); EnsureNodeExists();
m_pNode->force_insert(detail::to_value(key), detail::to_value(value), m_pNode->force_insert(key, value, m_pMemory);
m_pMemory);
} }
// free functions // free functions

View File

@@ -15,10 +15,13 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
// Assert in place so gcc + libc++ combination properly builds
static_assert(std::is_constructible<YAML::Node, const YAML::Node&>::value, "Node must be copy constructable");
namespace YAML { namespace YAML {
namespace detail { namespace detail {
struct iterator_value : public Node, std::pair<Node, Node> { struct iterator_value : public Node, std::pair<Node, Node> {
iterator_value() {} iterator_value() = default;
explicit iterator_value(const Node& rhs) explicit iterator_value(const Node& rhs)
: Node(rhs), : Node(rhs),
std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {} std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {}

View File

@@ -13,7 +13,6 @@
#include "yaml-cpp/dll.h" #include "yaml-cpp/dll.h"
#include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/mark.h" #include "yaml-cpp/mark.h"
#include "yaml-cpp/node/detail/bool_type.h"
#include "yaml-cpp/node/detail/iterator_fwd.h" #include "yaml-cpp/node/detail/iterator_fwd.h"
#include "yaml-cpp/node/ptr.h" #include "yaml-cpp/node/ptr.h"
#include "yaml-cpp/node/type.h" #include "yaml-cpp/node/type.h"
@@ -39,8 +38,8 @@ class YAML_CPP_API Node {
template <typename T, typename S> template <typename T, typename S>
friend struct as_if; friend struct as_if;
typedef YAML::iterator iterator; using iterator = YAML::iterator;
typedef YAML::const_iterator const_iterator; using const_iterator = YAML::const_iterator;
Node(); Node();
explicit Node(NodeType::value type); explicit Node(NodeType::value type);
@@ -59,7 +58,7 @@ class YAML_CPP_API Node {
bool IsMap() const { return Type() == NodeType::Map; } bool IsMap() const { return Type() == NodeType::Map; }
// bool conversions // bool conversions
YAML_CPP_OPERATOR_BOOL() explicit operator bool() const { return IsDefined(); }
bool operator!() const { return !IsDefined(); } bool operator!() const { return !IsDefined(); }
// access // access

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#endif #endif
#include "yaml-cpp/dll.h"
#include <memory> #include <memory>
namespace YAML { namespace YAML {
@@ -18,11 +17,11 @@ class node_data;
class memory; class memory;
class memory_holder; class memory_holder;
typedef std::shared_ptr<node> shared_node; using shared_node = std::shared_ptr<node>;
typedef std::shared_ptr<node_ref> shared_node_ref; using shared_node_ref = std::shared_ptr<node_ref>;
typedef std::shared_ptr<node_data> shared_node_data; using shared_node_data = std::shared_ptr<node_data>;
typedef std::shared_ptr<memory_holder> shared_memory_holder; using shared_memory_holder = std::shared_ptr<memory_holder>;
typedef std::shared_ptr<memory> shared_memory; using shared_memory = std::shared_ptr<memory>;
} }
} }

View File

@@ -8,9 +8,10 @@
#endif #endif
namespace YAML { namespace YAML {
struct NodeType { namespace NodeType {
enum value { Undefined, Null, Scalar, Sequence, Map }; enum value { Undefined, Null, Scalar, Sequence, Map };
}; }
} }
#endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View 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

View File

@@ -8,7 +8,7 @@
#endif #endif
#include "yaml-cpp/dll.h" #include "yaml-cpp/dll.h"
#include <string> #include <cstddef>
namespace YAML { namespace YAML {
class Node; class Node;
@@ -18,7 +18,7 @@ inline bool operator==(const _Null&, const _Null&) { return true; }
inline bool operator!=(const _Null&, const _Null&) { return false; } inline bool operator!=(const _Null&, const _Null&) { return false; }
YAML_CPP_API bool IsNull(const Node& node); // old API only YAML_CPP_API bool IsNull(const Node& node); // old API only
YAML_CPP_API bool IsNullString(const std::string& str); YAML_CPP_API bool IsNullString(const char* str, std::size_t size);
extern YAML_CPP_API _Null Null; extern YAML_CPP_API _Null Null;
} }

View File

@@ -16,8 +16,8 @@ namespace YAML {
template <typename Seq> template <typename Seq>
inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) { inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) {
emitter << BeginSeq; emitter << BeginSeq;
for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it) for (const auto& v : seq)
emitter << *it; emitter << v;
emitter << EndSeq; emitter << EndSeq;
return emitter; return emitter;
} }
@@ -39,10 +39,9 @@ inline Emitter& operator<<(Emitter& emitter, const std::set<T>& v) {
template <typename K, typename V> template <typename K, typename V>
inline Emitter& operator<<(Emitter& emitter, const std::map<K, V>& m) { inline Emitter& operator<<(Emitter& emitter, const std::map<K, V>& m) {
typedef typename std::map<K, V> map;
emitter << BeginMap; emitter << BeginMap;
for (typename map::const_iterator it = m.begin(); it != m.end(); ++it) for (const auto& v : m)
emitter << Key << it->first << Value << it->second; emitter << Key << v.first << Value << v.second;
emitter << EndMap; emitter << EndMap;
return emitter; return emitter;
} }

View File

@@ -84,7 +84,7 @@ struct is_numeric<long double> {
template <bool, class T = void> template <bool, class T = void>
struct enable_if_c { struct enable_if_c {
typedef T type; using type = T;
}; };
template <class T> template <class T>
@@ -95,7 +95,7 @@ struct enable_if : public enable_if_c<Cond::value, T> {};
template <bool, class T = void> template <bool, class T = void>
struct disable_if_c { struct disable_if_c {
typedef T type; using type = T;
}; };
template <class T> template <class T>
@@ -107,9 +107,9 @@ struct disable_if : public disable_if_c<Cond::value, T> {};
template <typename S, typename T> template <typename S, typename T>
struct is_streamable { struct is_streamable {
template <typename SS, typename TT> template <typename StreamT, typename ValueT>
static auto test(int) static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type()); -> decltype(std::declval<StreamT&>() << std::declval<ValueT>(), std::true_type());
template <typename, typename> template <typename, typename>
static auto test(...) -> std::false_type; static auto test(...) -> std::false_type;
@@ -121,6 +121,7 @@ template<typename Key, bool Streamable>
struct streamable_to_string { struct streamable_to_string {
static std::string impl(const Key& key) { static std::string impl(const Key& key) {
std::stringstream ss; std::stringstream ss;
ss.imbue(std::locale("C"));
ss << key; ss << key;
return ss.str(); return ss.str();
} }

View File

@@ -66,7 +66,7 @@ static const unsigned char decoding[] = {
}; };
std::vector<unsigned char> DecodeBase64(const std::string &input) { 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()) if (input.empty())
return ret_type(); return ret_type();
@@ -75,11 +75,11 @@ std::vector<unsigned char> DecodeBase64(const std::string &input) {
unsigned value = 0; unsigned value = 0;
for (std::size_t i = 0, cnt = 0; i < input.size(); i++) { for (std::size_t i = 0, cnt = 0; i < input.size(); i++) {
if (std::isspace(input[i])) { if (std::isspace(static_cast<unsigned char>(input[i]))) {
// skip newlines // skip newlines
continue; continue;
} }
unsigned char d = decoding[static_cast<unsigned>(input[i])]; unsigned char d = decoding[static_cast<unsigned char>(input[i])];
if (d == 255) if (d == 255)
return ret_type(); return ret_type();
@@ -97,4 +97,4 @@ std::vector<unsigned char> DecodeBase64(const std::string &input) {
ret.resize(out - &ret[0]); ret.resize(out - &ret[0]);
return ret; return ret;
} }
} } // namespace YAML

4196
src/contrib/dragonbox.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,7 @@ void* BuildGraphOfNextDocument(Parser& parser,
GraphBuilderAdapter eventHandler(graphBuilder); GraphBuilderAdapter eventHandler(graphBuilder);
if (parser.HandleNextDocument(eventHandler)) { if (parser.HandleNextDocument(eventHandler)) {
return eventHandler.RootNode(); return eventHandler.RootNode();
} else { }
return nullptr; return nullptr;
} }
} } // namespace YAML
}

View File

@@ -91,4 +91,4 @@ void GraphBuilderAdapter::DispositionNode(void *pNode) {
m_builder.AppendToSequence(pContainer, pNode); m_builder.AppendToSequence(pContainer, pNode);
} }
} }
} } // namespace YAML

View File

@@ -13,7 +13,6 @@
#include "yaml-cpp/anchor.h" #include "yaml-cpp/anchor.h"
#include "yaml-cpp/contrib/anchordict.h" #include "yaml-cpp/contrib/anchordict.h"
#include "yaml-cpp/contrib/graphbuilder.h"
#include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/eventhandler.h" #include "yaml-cpp/eventhandler.h"

View File

@@ -16,11 +16,7 @@ std::string tolower(const std::string& str) {
template <typename T> template <typename T>
bool IsEntirely(const std::string& str, T func) { bool IsEntirely(const std::string& str, T func) {
for (std::size_t i = 0; i < str.size(); i++) return std::all_of(str.begin(), str.end(), [=](char ch) { return func(ch); });
if (!func(str[i]))
return false;
return true;
} }
// IsFlexibleCase // IsFlexibleCase
@@ -39,7 +35,7 @@ bool IsFlexibleCase(const std::string& str) {
std::string rest = str.substr(1); std::string rest = str.substr(1);
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper)); return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
} }
} } // namespace
namespace YAML { namespace YAML {
bool convert<bool>::decode(const Node& node, bool& rhs) { bool convert<bool>::decode(const Node& node, bool& rhs) {
@@ -52,19 +48,22 @@ bool convert<bool>::decode(const Node& node, bool& rhs) {
static const struct { static const struct {
std::string truename, falsename; std::string truename, falsename;
} names[] = { } names[] = {
{"y", "n"}, {"yes", "no"}, {"true", "false"}, {"on", "off"}, {"y", "n"},
{"yes", "no"},
{"true", "false"},
{"on", "off"},
}; };
if (!IsFlexibleCase(node.Scalar())) if (!IsFlexibleCase(node.Scalar()))
return false; return false;
for (unsigned i = 0; i < sizeof(names) / sizeof(names[0]); i++) { for (const auto& name : names) {
if (names[i].truename == tolower(node.Scalar())) { if (name.truename == tolower(node.Scalar())) {
rhs = true; rhs = true;
return true; return true;
} }
if (names[i].falsename == tolower(node.Scalar())) { if (name.falsename == tolower(node.Scalar())) {
rhs = false; rhs = false;
return true; return true;
} }
@@ -72,4 +71,4 @@ bool convert<bool>::decode(const Node& node, bool& rhs) {
return false; return false;
} }
} } // namespace YAML

9
src/depthguard.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include "yaml-cpp/depthguard.h"
namespace YAML {
DeepRecursion::DeepRecursion(int depth, const Mark& mark_,
const std::string& msg_)
: ParserException(mark_, msg_), m_depth(depth) {}
} // namespace YAML

View File

@@ -3,9 +3,9 @@
namespace YAML { namespace YAML {
Directives::Directives() : version{true, 1, 2}, tags{} {} Directives::Directives() : version{true, 1, 2}, tags{} {}
const std::string Directives::TranslateTagHandle( std::string Directives::TranslateTagHandle(
const std::string& handle) const { const std::string& handle) const {
std::map<std::string, std::string>::const_iterator it = tags.find(handle); auto it = tags.find(handle);
if (it == tags.end()) { if (it == tags.end()) {
if (handle == "!!") if (handle == "!!")
return "tag:yaml.org,2002:"; return "tag:yaml.org,2002:";

View File

@@ -19,7 +19,7 @@ struct Version {
struct Directives { struct Directives {
Directives(); Directives();
const std::string TranslateTagHandle(const std::string& handle) const; std::string TranslateTagHandle(const std::string& handle) const;
Version version; Version version;
std::map<std::string, std::string> tags; std::map<std::string, std::string> tags;

View File

@@ -1,7 +1,7 @@
#include "yaml-cpp/node/emit.h" #include "yaml-cpp/node/emit.h"
#include "nodeevents.h"
#include "yaml-cpp/emitfromevents.h" #include "yaml-cpp/emitfromevents.h"
#include "yaml-cpp/emitter.h" #include "yaml-cpp/emitter.h"
#include "nodeevents.h"
namespace YAML { namespace YAML {
Emitter& operator<<(Emitter& out, const Node& node) { Emitter& operator<<(Emitter& out, const Node& node) {

View File

@@ -59,6 +59,8 @@ void EmitFromEvents::OnSequenceStart(const Mark&, const std::string& tag,
default: default:
break; break;
} }
// Restore the global settings to eliminate the override from node style
m_emitter.RestoreGlobalModifiedSettings();
m_emitter << BeginSeq; m_emitter << BeginSeq;
m_stateStack.push(State::WaitingForSequenceEntry); m_stateStack.push(State::WaitingForSequenceEntry);
} }
@@ -83,6 +85,8 @@ void EmitFromEvents::OnMapStart(const Mark&, const std::string& tag,
default: default:
break; break;
} }
// Restore the global settings to eliminate the override from node style
m_emitter.RestoreGlobalModifiedSettings();
m_emitter << BeginMap; m_emitter << BeginMap;
m_stateStack.push(State::WaitingForKey); m_stateStack.push(State::WaitingForKey);
} }
@@ -112,8 +116,13 @@ void EmitFromEvents::BeginNode() {
} }
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) { void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) {
if (!tag.empty() && tag != "?" && tag != "!") if (!tag.empty() && tag != "?" && tag != "!"){
if (tag[0] == '!') {
m_emitter << LocalTag(std::string(tag.begin()+1, tag.end()));
} else {
m_emitter << VerbatimTag(tag); m_emitter << VerbatimTag(tag);
}
}
if (anchor) if (anchor)
m_emitter << Anchor(ToString(anchor)); m_emitter << Anchor(ToString(anchor));
} }

View File

@@ -16,7 +16,7 @@ Emitter::Emitter() : m_pState(new EmitterState), m_stream{} {}
Emitter::Emitter(std::ostream& stream) Emitter::Emitter(std::ostream& stream)
: m_pState(new EmitterState), m_stream(stream) {} : m_pState(new EmitterState), m_stream(stream) {}
Emitter::~Emitter() {} Emitter::~Emitter() = default;
const char* Emitter::c_str() const { return m_stream.str(); } const char* Emitter::c_str() const { return m_stream.str(); }
@@ -49,6 +49,10 @@ bool Emitter::SetBoolFormat(EMITTER_MANIP value) {
return ok; return ok;
} }
bool Emitter::SetNullFormat(EMITTER_MANIP value) {
return m_pState->SetNullFormat(value, FmtScope::Global);
}
bool Emitter::SetIntBase(EMITTER_MANIP value) { bool Emitter::SetIntBase(EMITTER_MANIP value) {
return m_pState->SetIntFormat(value, FmtScope::Global); return m_pState->SetIntFormat(value, FmtScope::Global);
} }
@@ -86,6 +90,10 @@ bool Emitter::SetDoublePrecision(std::size_t n) {
return m_pState->SetDoublePrecision(n, FmtScope::Global); return m_pState->SetDoublePrecision(n, FmtScope::Global);
} }
void Emitter::RestoreGlobalModifiedSettings() {
m_pState->RestoreGlobalModifiedSettings();
}
// SetLocalValue // SetLocalValue
// . Either start/end a group, or set a modifier locally // . Either start/end a group, or set a modifier locally
Emitter& Emitter::SetLocalValue(EMITTER_MANIP value) { Emitter& Emitter::SetLocalValue(EMITTER_MANIP value) {
@@ -197,6 +205,7 @@ void Emitter::EmitBeginSeq() {
void Emitter::EmitEndSeq() { void Emitter::EmitEndSeq() {
if (!good()) if (!good())
return; return;
FlowType::value originalType = m_pState->CurGroupFlowType();
if (m_pState->CurGroupChildCount() == 0) if (m_pState->CurGroupChildCount() == 0)
m_pState->ForceFlow(); m_pState->ForceFlow();
@@ -204,9 +213,14 @@ void Emitter::EmitEndSeq() {
if (m_pState->CurGroupFlowType() == FlowType::Flow) { if (m_pState->CurGroupFlowType() == FlowType::Flow) {
if (m_stream.comment()) if (m_stream.comment())
m_stream << "\n"; m_stream << "\n";
if (originalType == FlowType::Block || m_pState->HasBegunNode())
m_stream << IndentTo(m_pState->CurIndent()); m_stream << IndentTo(m_pState->CurIndent());
if (m_pState->CurGroupChildCount() == 0) if (originalType == FlowType::Block) {
m_stream << "["; m_stream << "[";
} else {
if (m_pState->CurGroupChildCount() == 0 && !m_pState->HasBegunNode())
m_stream << "[";
}
m_stream << "]"; m_stream << "]";
} }
@@ -227,6 +241,7 @@ void Emitter::EmitBeginMap() {
void Emitter::EmitEndMap() { void Emitter::EmitEndMap() {
if (!good()) if (!good())
return; return;
FlowType::value originalType = m_pState->CurGroupFlowType();
if (m_pState->CurGroupChildCount() == 0) if (m_pState->CurGroupChildCount() == 0)
m_pState->ForceFlow(); m_pState->ForceFlow();
@@ -235,8 +250,12 @@ void Emitter::EmitEndMap() {
if (m_stream.comment()) if (m_stream.comment())
m_stream << "\n"; m_stream << "\n";
m_stream << IndentTo(m_pState->CurIndent()); m_stream << IndentTo(m_pState->CurIndent());
if (m_pState->CurGroupChildCount() == 0) if (originalType == FlowType::Block) {
m_stream << "{"; m_stream << "{";
} else {
if (m_pState->CurGroupChildCount() == 0 && !m_pState->HasBegunNode())
m_stream << "{";
}
m_stream << "}"; m_stream << "}";
} }
@@ -486,6 +505,9 @@ void Emitter::FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
if (m_stream.comment()) if (m_stream.comment())
m_stream << "\n"; m_stream << "\n";
m_stream << IndentTo(lastIndent); m_stream << IndentTo(lastIndent);
if (m_pState->HasAlias()) {
m_stream << " ";
}
m_stream << ":"; m_stream << ":";
} }
@@ -512,7 +534,8 @@ void Emitter::BlockMapPrepareNode(EmitterNodeType::value child) {
if (m_pState->GetMapKeyFormat() == LongKey) if (m_pState->GetMapKeyFormat() == LongKey)
m_pState->SetLongKey(); m_pState->SetLongKey();
if (child == EmitterNodeType::BlockSeq || if (child == EmitterNodeType::BlockSeq ||
child == EmitterNodeType::BlockMap) child == EmitterNodeType::BlockMap ||
child == EmitterNodeType::Property)
m_pState->SetLongKey(); m_pState->SetLongKey();
if (m_pState->CurGroupLongKey()) if (m_pState->CurGroupLongKey())
@@ -556,6 +579,8 @@ void Emitter::BlockMapPrepareLongKey(EmitterNodeType::value child) {
break; break;
case EmitterNodeType::BlockSeq: case EmitterNodeType::BlockSeq:
case EmitterNodeType::BlockMap: case EmitterNodeType::BlockMap:
if (m_pState->HasBegunContent())
m_stream << "\n";
break; break;
} }
} }
@@ -579,8 +604,12 @@ void Emitter::BlockMapPrepareLongKeyValue(EmitterNodeType::value child) {
case EmitterNodeType::Scalar: case EmitterNodeType::Scalar:
case EmitterNodeType::FlowSeq: case EmitterNodeType::FlowSeq:
case EmitterNodeType::FlowMap: case EmitterNodeType::FlowMap:
SpaceOrIndentTo(true, curIndent + 1);
break;
case EmitterNodeType::BlockSeq: case EmitterNodeType::BlockSeq:
case EmitterNodeType::BlockMap: case EmitterNodeType::BlockMap:
if (m_pState->HasBegunContent())
m_stream << "\n";
SpaceOrIndentTo(true, curIndent + 1); SpaceOrIndentTo(true, curIndent + 1);
break; break;
} }
@@ -619,6 +648,9 @@ void Emitter::BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent(); const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent();
if (!m_pState->HasBegunNode()) { if (!m_pState->HasBegunNode()) {
if (m_pState->HasAlias()) {
m_stream << " ";
}
m_stream << ":"; m_stream << ":";
} }
@@ -672,32 +704,45 @@ void Emitter::StartedScalar() { m_pState->StartedScalar(); }
// ******************************************************************************************* // *******************************************************************************************
// overloads of Write // overloads of Write
Emitter& Emitter::Write(const std::string& str) { StringEscaping::value GetStringEscapingStyle(const EMITTER_MANIP emitterManip) {
switch (emitterManip) {
case EscapeNonAscii:
return StringEscaping::NonAscii;
case EscapeAsJson:
return StringEscaping::JSON;
default:
return StringEscaping::None;
break;
}
}
Emitter& Emitter::Write(const char* str, std::size_t size) {
if (!good()) if (!good())
return *this; return *this;
const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii; StringEscaping::value stringEscaping = GetStringEscapingStyle(m_pState->GetOutputCharset());
const StringFormat::value strFormat =
Utils::ComputeStringFormat(str, m_pState->GetStringFormat(),
m_pState->CurGroupFlowType(), escapeNonAscii);
if (strFormat == StringFormat::Literal) const StringFormat::value strFormat =
Utils::ComputeStringFormat(str, size, m_pState->GetStringFormat(),
m_pState->CurGroupFlowType(), stringEscaping == StringEscaping::NonAscii);
if (strFormat == StringFormat::Literal || size > 1024)
m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local); m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
switch (strFormat) { switch (strFormat) {
case StringFormat::Plain: case StringFormat::Plain:
m_stream << str; m_stream.write(str, size);
break; break;
case StringFormat::SingleQuoted: case StringFormat::SingleQuoted:
Utils::WriteSingleQuotedString(m_stream, str); Utils::WriteSingleQuotedString(m_stream, str, size);
break; break;
case StringFormat::DoubleQuoted: case StringFormat::DoubleQuoted:
Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii); Utils::WriteDoubleQuotedString(m_stream, str, size, stringEscaping);
break; break;
case StringFormat::Literal: case StringFormat::Literal:
Utils::WriteLiteralString(m_stream, str, Utils::WriteLiteralString(m_stream, str, size,
m_pState->CurIndent() + m_pState->GetIndent()); m_pState->CurIndent() + m_pState->GetIndent());
break; break;
} }
@@ -707,6 +752,10 @@ Emitter& Emitter::Write(const std::string& str) {
return *this; return *this;
} }
Emitter& Emitter::Write(const std::string& str) {
return Write(str.data(), str.size());
}
std::size_t Emitter::GetFloatPrecision() const { std::size_t Emitter::GetFloatPrecision() const {
return m_pState->GetFloatPrecision(); return m_pState->GetFloatPrecision();
} }
@@ -764,6 +813,21 @@ const char* Emitter::ComputeFullBoolName(bool b) const {
// these answers // these answers
} }
const char* Emitter::ComputeNullName() const {
switch (m_pState->GetNullFormat()) {
case LowerNull:
return "null";
case UpperNull:
return "NULL";
case CamelNull:
return "Null";
case TildeNull:
// fallthrough
default:
return "~";
}
}
Emitter& Emitter::Write(bool b) { Emitter& Emitter::Write(bool b) {
if (!good()) if (!good())
return *this; return *this;
@@ -785,8 +849,10 @@ Emitter& Emitter::Write(char ch) {
if (!good()) if (!good())
return *this; return *this;
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
Utils::WriteChar(m_stream, ch); Utils::WriteChar(m_stream, ch, GetStringEscapingStyle(m_pState->GetOutputCharset()));
StartedScalar(); StartedScalar();
return *this; return *this;
@@ -803,13 +869,15 @@ Emitter& Emitter::Write(const _Alias& alias) {
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
if (!Utils::WriteAlias(m_stream, alias.content)) { if (!Utils::WriteAlias(m_stream, alias.content.data(), alias.content.size())) {
m_pState->SetError(ErrorMsg::INVALID_ALIAS); m_pState->SetError(ErrorMsg::INVALID_ALIAS);
return *this; return *this;
} }
StartedScalar(); StartedScalar();
m_pState->SetAlias();
return *this; return *this;
} }
@@ -824,7 +892,7 @@ Emitter& Emitter::Write(const _Anchor& anchor) {
PrepareNode(EmitterNodeType::Property); PrepareNode(EmitterNodeType::Property);
if (!Utils::WriteAnchor(m_stream, anchor.content)) { if (!Utils::WriteAnchor(m_stream, anchor.content.data(), anchor.content.size())) {
m_pState->SetError(ErrorMsg::INVALID_ANCHOR); m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
return *this; return *this;
} }
@@ -873,7 +941,7 @@ Emitter& Emitter::Write(const _Comment& comment) {
if (m_stream.col() > 0) if (m_stream.col() > 0)
m_stream << Indentation(m_pState->GetPreCommentIndent()); m_stream << Indentation(m_pState->GetPreCommentIndent());
Utils::WriteComment(m_stream, comment.content, Utils::WriteComment(m_stream, comment.content.data(), comment.content.size(),
m_pState->GetPostCommentIndent()); m_pState->GetPostCommentIndent());
m_pState->SetNonContent(); m_pState->SetNonContent();
@@ -887,7 +955,7 @@ Emitter& Emitter::Write(const _Null& /*null*/) {
PrepareNode(EmitterNodeType::Scalar); PrepareNode(EmitterNodeType::Scalar);
m_stream << "~"; m_stream << ComputeNullName();
StartedScalar(); StartedScalar();

View File

@@ -13,6 +13,7 @@ EmitterState::EmitterState()
m_boolFmt(TrueFalseBool), m_boolFmt(TrueFalseBool),
m_boolLengthFmt(LongBool), m_boolLengthFmt(LongBool),
m_boolCaseFmt(LowerCase), m_boolCaseFmt(LowerCase),
m_nullFmt(TildeNull),
m_intFmt(Dec), m_intFmt(Dec),
m_indent(2), m_indent(2),
m_preCommentIndent(2), m_preCommentIndent(2),
@@ -28,11 +29,12 @@ EmitterState::EmitterState()
m_groups{}, m_groups{},
m_curIndent(0), m_curIndent(0),
m_hasAnchor(false), m_hasAnchor(false),
m_hasAlias(false),
m_hasTag(false), m_hasTag(false),
m_hasNonContent(false), m_hasNonContent(false),
m_docCount(0) {} m_docCount(0) {}
EmitterState::~EmitterState() {} EmitterState::~EmitterState() = default;
// SetLocalValue // SetLocalValue
// . We blindly tries to set all possible formatters to this value // . We blindly tries to set all possible formatters to this value
@@ -43,6 +45,7 @@ void EmitterState::SetLocalValue(EMITTER_MANIP value) {
SetBoolFormat(value, FmtScope::Local); SetBoolFormat(value, FmtScope::Local);
SetBoolCaseFormat(value, FmtScope::Local); SetBoolCaseFormat(value, FmtScope::Local);
SetBoolLengthFormat(value, FmtScope::Local); SetBoolLengthFormat(value, FmtScope::Local);
SetNullFormat(value, FmtScope::Local);
SetIntFormat(value, FmtScope::Local); SetIntFormat(value, FmtScope::Local);
SetFlowType(GroupType::Seq, value, FmtScope::Local); SetFlowType(GroupType::Seq, value, FmtScope::Local);
SetFlowType(GroupType::Map, value, FmtScope::Local); SetFlowType(GroupType::Map, value, FmtScope::Local);
@@ -51,6 +54,8 @@ void EmitterState::SetLocalValue(EMITTER_MANIP value) {
void EmitterState::SetAnchor() { m_hasAnchor = true; } void EmitterState::SetAnchor() { m_hasAnchor = true; }
void EmitterState::SetAlias() { m_hasAlias = true; }
void EmitterState::SetTag() { m_hasTag = true; } void EmitterState::SetTag() { m_hasTag = true; }
void EmitterState::SetNonContent() { m_hasNonContent = true; } void EmitterState::SetNonContent() { m_hasNonContent = true; }
@@ -85,6 +90,7 @@ void EmitterState::StartedNode() {
} }
m_hasAnchor = false; m_hasAnchor = false;
m_hasAlias = false;
m_hasTag = false; m_hasTag = false;
m_hasNonContent = false; m_hasNonContent = false;
} }
@@ -94,14 +100,12 @@ EmitterNodeType::value EmitterState::NextGroupType(
if (type == GroupType::Seq) { if (type == GroupType::Seq) {
if (GetFlowType(type) == Block) if (GetFlowType(type) == Block)
return EmitterNodeType::BlockSeq; return EmitterNodeType::BlockSeq;
else
return EmitterNodeType::FlowSeq; return EmitterNodeType::FlowSeq;
} else { }
if (GetFlowType(type) == Block) if (GetFlowType(type) == Block)
return EmitterNodeType::BlockMap; return EmitterNodeType::BlockMap;
else
return EmitterNodeType::FlowMap; return EmitterNodeType::FlowMap;
}
// can't happen // can't happen
assert(false); assert(false);
@@ -156,9 +160,15 @@ void EmitterState::EndedGroup(GroupType::value type) {
if (m_groups.empty()) { if (m_groups.empty()) {
if (type == GroupType::Seq) { if (type == GroupType::Seq) {
return SetError(ErrorMsg::UNEXPECTED_END_SEQ); return SetError(ErrorMsg::UNEXPECTED_END_SEQ);
} else { }
return SetError(ErrorMsg::UNEXPECTED_END_MAP); return SetError(ErrorMsg::UNEXPECTED_END_MAP);
} }
if (m_hasTag) {
SetError(ErrorMsg::INVALID_TAG);
}
if (m_hasAnchor) {
SetError(ErrorMsg::INVALID_ANCHOR);
} }
// get rid of the current group // get rid of the current group
@@ -180,6 +190,9 @@ void EmitterState::EndedGroup(GroupType::value type) {
m_globalModifiedSettings.restore(); m_globalModifiedSettings.restore();
ClearModifiedSettings(); ClearModifiedSettings();
m_hasAnchor = false;
m_hasTag = false;
m_hasNonContent = false;
} }
EmitterNodeType::value EmitterState::CurGroupNodeType() const { EmitterNodeType::value EmitterState::CurGroupNodeType() const {
@@ -220,11 +233,16 @@ std::size_t EmitterState::LastIndent() const {
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); } void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
void EmitterState::RestoreGlobalModifiedSettings() {
m_globalModifiedSettings.restore();
}
bool EmitterState::SetOutputCharset(EMITTER_MANIP value, bool EmitterState::SetOutputCharset(EMITTER_MANIP value,
FmtScope::value scope) { FmtScope::value scope) {
switch (value) { switch (value) {
case EmitNonAscii: case EmitNonAscii:
case EscapeNonAscii: case EscapeNonAscii:
case EscapeAsJson:
_Set(m_charset, value, scope); _Set(m_charset, value, scope);
return true; return true;
default: default:
@@ -282,6 +300,19 @@ bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value,
} }
} }
bool EmitterState::SetNullFormat(EMITTER_MANIP value, FmtScope::value scope) {
switch (value) {
case LowerNull:
case UpperNull:
case CamelNull:
case TildeNull:
_Set(m_nullFmt, value, scope);
return true;
default:
return false;
}
}
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) { bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) {
switch (value) { switch (value) {
case Dec: case Dec:

View File

@@ -43,6 +43,7 @@ class EmitterState {
// node handling // node handling
void SetAnchor(); void SetAnchor();
void SetAlias();
void SetTag(); void SetTag();
void SetNonContent(); void SetNonContent();
void SetLongKey(); void SetLongKey();
@@ -65,6 +66,7 @@ class EmitterState {
std::size_t LastIndent() const; std::size_t LastIndent() const;
std::size_t CurIndent() const { return m_curIndent; } std::size_t CurIndent() const { return m_curIndent; }
bool HasAnchor() const { return m_hasAnchor; } bool HasAnchor() const { return m_hasAnchor; }
bool HasAlias() const { return m_hasAlias; }
bool HasTag() const { return m_hasTag; } bool HasTag() const { return m_hasTag; }
bool HasBegunNode() const { bool HasBegunNode() const {
return m_hasAnchor || m_hasTag || m_hasNonContent; return m_hasAnchor || m_hasTag || m_hasNonContent;
@@ -72,6 +74,7 @@ class EmitterState {
bool HasBegunContent() const { return m_hasAnchor || m_hasTag; } bool HasBegunContent() const { return m_hasAnchor || m_hasTag; }
void ClearModifiedSettings(); void ClearModifiedSettings();
void RestoreGlobalModifiedSettings();
// formatters // formatters
void SetLocalValue(EMITTER_MANIP value); void SetLocalValue(EMITTER_MANIP value);
@@ -91,6 +94,9 @@ class EmitterState {
bool SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope); bool SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope);
EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); } EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); }
bool SetNullFormat(EMITTER_MANIP value, FmtScope::value scope);
EMITTER_MANIP GetNullFormat() const { return m_nullFmt.get(); }
bool SetIntFormat(EMITTER_MANIP value, FmtScope::value scope); bool SetIntFormat(EMITTER_MANIP value, FmtScope::value scope);
EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); } EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); }
@@ -131,6 +137,7 @@ class EmitterState {
Setting<EMITTER_MANIP> m_boolFmt; Setting<EMITTER_MANIP> m_boolFmt;
Setting<EMITTER_MANIP> m_boolLengthFmt; Setting<EMITTER_MANIP> m_boolLengthFmt;
Setting<EMITTER_MANIP> m_boolCaseFmt; Setting<EMITTER_MANIP> m_boolCaseFmt;
Setting<EMITTER_MANIP> m_nullFmt;
Setting<EMITTER_MANIP> m_intFmt; Setting<EMITTER_MANIP> m_intFmt;
Setting<std::size_t> m_indent; Setting<std::size_t> m_indent;
Setting<std::size_t> m_preCommentIndent, m_postCommentIndent; Setting<std::size_t> m_preCommentIndent, m_postCommentIndent;
@@ -182,6 +189,7 @@ class EmitterState {
std::vector<std::unique_ptr<Group>> m_groups; std::vector<std::unique_ptr<Group>> m_groups;
std::size_t m_curIndent; std::size_t m_curIndent;
bool m_hasAnchor; bool m_hasAnchor;
bool m_hasAlias;
bool m_hasTag; bool m_hasTag;
bool m_hasNonContent; bool m_hasNonContent;
std::size_t m_docCount; std::size_t m_docCount;

View File

@@ -1,3 +1,5 @@
#include <algorithm>
#include <cstdint>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
@@ -87,8 +89,8 @@ int Utf8BytesIndicated(char ch) {
bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; } bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; }
bool GetNextCodePointAndAdvance(int& codePoint, bool GetNextCodePointAndAdvance(int& codePoint,
std::string::const_iterator& first, const char*& first,
std::string::const_iterator last) { const char* last) {
if (first == last) if (first == last)
return false; return false;
@@ -151,39 +153,39 @@ void WriteCodePoint(ostream_wrapper& out, int codePoint) {
} }
} }
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType, bool IsValidPlainScalar(const char* str, std::size_t size, FlowType::value flowType,
bool allowOnlyAscii) { bool allowOnlyAscii) {
// check against null // check against null
if (IsNullString(str)) { if (IsNullString(str, size)) {
return false; return false;
} }
// check the start // check the start
const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow() const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow()
: Exp::PlainScalar()); : Exp::PlainScalar());
if (!start.Matches(str)) { if (!start.Matches(StringCharSource(str, size))) {
return false; return false;
} }
// and check the end for plain whitespace (which can't be faithfully kept in a // and check the end for plain whitespace (which can't be faithfully kept in a
// plain scalar) // plain scalar)
if (!str.empty() && *str.rbegin() == ' ') { if (size != 0 && str[size - 1] == ' ') {
return false; return false;
} }
// then check until something is disallowed // then check until something is disallowed
static const RegEx& disallowed_flow = static const RegEx disallowed_flow =
Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) | Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) |
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() | Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
Exp::Tab(); Exp::Tab() | Exp::Ampersand();
static const RegEx& disallowed_block = static const RegEx disallowed_block =
Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) | Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) |
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() | Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
Exp::Tab(); Exp::Tab() | Exp::Ampersand();
const RegEx& disallowed = const RegEx& disallowed =
flowType == FlowType::Flow ? disallowed_flow : disallowed_block; flowType == FlowType::Flow ? disallowed_flow : disallowed_block;
StringCharSource buffer(str.c_str(), str.size()); StringCharSource buffer(str, size);
while (buffer) { while (buffer) {
if (disallowed.Matches(buffer)) { if (disallowed.Matches(buffer)) {
return false; return false;
@@ -197,48 +199,54 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
return true; return true;
} }
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) { bool IsValidSingleQuotedScalar(const char* str, std::size_t size, bool escapeNonAscii) {
// TODO: check for non-printable characters? // TODO: check for non-printable characters?
for (std::size_t i = 0; i < str.size(); i++) { return std::none_of(str, str + size, [=](char ch) {
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) { return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch))) ||
return false; (ch == '\n');
} });
if (str[i] == '\n') {
return false;
}
}
return true;
} }
bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType, bool IsValidLiteralScalar(const char* str, std::size_t size, FlowType::value flowType,
bool escapeNonAscii) { bool escapeNonAscii) {
if (flowType == FlowType::Flow) { if (flowType == FlowType::Flow) {
return false; return false;
} }
// TODO: check for non-printable characters? // TODO: check for non-printable characters?
for (std::size_t i = 0; i < str.size(); i++) { return std::none_of(str, str + size, [=](char ch) {
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) { return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch)));
return false; });
}
}
return true;
} }
void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint) { std::pair<uint16_t, uint16_t> EncodeUTF16SurrogatePair(int codePoint) {
const uint32_t leadOffset = 0xD800 - (0x10000 >> 10);
return {
leadOffset | (codePoint >> 10),
0xDC00 | (codePoint & 0x3FF),
};
}
void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint, StringEscaping::value stringEscapingStyle) {
static const char hexDigits[] = "0123456789abcdef"; static const char hexDigits[] = "0123456789abcdef";
out << "\\"; out << "\\";
int digits = 8; int digits = 8;
if (codePoint < 0xFF) { if (codePoint < 0xFF && stringEscapingStyle != StringEscaping::JSON) {
out << "x"; out << "x";
digits = 2; digits = 2;
} else if (codePoint < 0xFFFF) { } else if (codePoint < 0xFFFF) {
out << "u"; out << "u";
digits = 4; digits = 4;
} else { } else if (stringEscapingStyle != StringEscaping::JSON) {
out << "U"; out << "U";
digits = 8; digits = 8;
} else {
auto surrogatePair = EncodeUTF16SurrogatePair(codePoint);
WriteDoubleQuoteEscapeSequence(out, surrogatePair.first, stringEscapingStyle);
WriteDoubleQuoteEscapeSequence(out, surrogatePair.second, stringEscapingStyle);
return;
} }
// Write digits into the escape sequence // Write digits into the escape sequence
@@ -246,10 +254,10 @@ void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint) {
out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF]; out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
} }
bool WriteAliasName(ostream_wrapper& out, const std::string& str) { bool WriteAliasName(ostream_wrapper& out, const char* str, std::size_t size) {
int codePoint; int codePoint;
for (std::string::const_iterator i = str.begin(); for (const char* i = str;
GetNextCodePointAndAdvance(codePoint, i, str.end());) { GetNextCodePointAndAdvance(codePoint, i, str + size);) {
if (!IsAnchorChar(codePoint)) { if (!IsAnchorChar(codePoint)) {
return false; return false;
} }
@@ -260,25 +268,25 @@ bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
} }
} // namespace } // namespace
StringFormat::value ComputeStringFormat(const std::string& str, StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
EMITTER_MANIP strFormat, EMITTER_MANIP strFormat,
FlowType::value flowType, FlowType::value flowType,
bool escapeNonAscii) { bool escapeNonAscii) {
switch (strFormat) { switch (strFormat) {
case Auto: case Auto:
if (IsValidPlainScalar(str, flowType, escapeNonAscii)) { if (IsValidPlainScalar(str, size, flowType, escapeNonAscii)) {
return StringFormat::Plain; return StringFormat::Plain;
} }
return StringFormat::DoubleQuoted; return StringFormat::DoubleQuoted;
case SingleQuoted: case SingleQuoted:
if (IsValidSingleQuotedScalar(str, escapeNonAscii)) { if (IsValidSingleQuotedScalar(str, size, escapeNonAscii)) {
return StringFormat::SingleQuoted; return StringFormat::SingleQuoted;
} }
return StringFormat::DoubleQuoted; return StringFormat::DoubleQuoted;
case DoubleQuoted: case DoubleQuoted:
return StringFormat::DoubleQuoted; return StringFormat::DoubleQuoted;
case Literal: case Literal:
if (IsValidLiteralScalar(str, flowType, escapeNonAscii)) { if (IsValidLiteralScalar(str, size, flowType, escapeNonAscii)) {
return StringFormat::Literal; return StringFormat::Literal;
} }
return StringFormat::DoubleQuoted; return StringFormat::DoubleQuoted;
@@ -289,11 +297,11 @@ StringFormat::value ComputeStringFormat(const std::string& str,
return StringFormat::DoubleQuoted; return StringFormat::DoubleQuoted;
} }
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) { bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size) {
out << "'"; out << "'";
int codePoint; int codePoint;
for (std::string::const_iterator i = str.begin(); for (const char* i = str;
GetNextCodePointAndAdvance(codePoint, i, str.end());) { GetNextCodePointAndAdvance(codePoint, i, str + size);) {
if (codePoint == '\n') { if (codePoint == '\n') {
return false; // We can't handle a new line and the attendant indentation return false; // We can't handle a new line and the attendant indentation
// yet // yet
@@ -309,12 +317,12 @@ bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
return true; return true;
} }
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str, bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
bool escapeNonAscii) { StringEscaping::value stringEscaping) {
out << "\""; out << "\"";
int codePoint; int codePoint;
for (std::string::const_iterator i = str.begin(); for (const char* i = str;
GetNextCodePointAndAdvance(codePoint, i, str.end());) { GetNextCodePointAndAdvance(codePoint, i, str + size);) {
switch (codePoint) { switch (codePoint) {
case '\"': case '\"':
out << "\\\""; out << "\\\"";
@@ -334,16 +342,19 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
case '\b': case '\b':
out << "\\b"; out << "\\b";
break; break;
case '\f':
out << "\\f";
break;
default: default:
if (codePoint < 0x20 || if (codePoint < 0x20 ||
(codePoint >= 0x80 && (codePoint >= 0x80 &&
codePoint <= 0xA0)) { // Control characters and non-breaking space codePoint <= 0xA0)) { // Control characters and non-breaking space
WriteDoubleQuoteEscapeSequence(out, codePoint); WriteDoubleQuoteEscapeSequence(out, codePoint, stringEscaping);
} else if (codePoint == 0xFEFF) { // Byte order marks (ZWNS) should be } else if (codePoint == 0xFEFF) { // Byte order marks (ZWNS) should be
// escaped (YAML 1.2, sec. 5.2) // escaped (YAML 1.2, sec. 5.2)
WriteDoubleQuoteEscapeSequence(out, codePoint); WriteDoubleQuoteEscapeSequence(out, codePoint, stringEscaping);
} else if (escapeNonAscii && codePoint > 0x7E) { } else if (stringEscaping == StringEscaping::NonAscii && codePoint > 0x7E) {
WriteDoubleQuoteEscapeSequence(out, codePoint); WriteDoubleQuoteEscapeSequence(out, codePoint, stringEscaping);
} else { } else {
WriteCodePoint(out, codePoint); WriteCodePoint(out, codePoint);
} }
@@ -353,53 +364,57 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
return true; return true;
} }
bool WriteLiteralString(ostream_wrapper& out, const std::string& str, bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
std::size_t indent) { std::size_t indent) {
out << "|\n"; out << "|\n";
out << IndentTo(indent);
int codePoint; int codePoint;
for (std::string::const_iterator i = str.begin(); for (const char* i = str;
GetNextCodePointAndAdvance(codePoint, i, str.end());) { GetNextCodePointAndAdvance(codePoint, i, str + size);) {
if (codePoint == '\n') { if (codePoint == '\n') {
out << "\n" << IndentTo(indent); out << "\n";
} else { } else {
out<< IndentTo(indent);
WriteCodePoint(out, codePoint); WriteCodePoint(out, codePoint);
} }
} }
return true; return true;
} }
bool WriteChar(ostream_wrapper& out, char ch) { bool WriteChar(ostream_wrapper& out, char ch, StringEscaping::value stringEscapingStyle) {
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) { if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
out << ch; out << ch;
} else if (ch == '\"') { } else if (ch == '\"') {
out << "\"\\\"\""; out << R"("\"")";
} else if (ch == '\t') { } else if (ch == '\t') {
out << "\"\\t\""; out << R"("\t")";
} else if (ch == '\n') { } else if (ch == '\n') {
out << "\"\\n\""; out << R"("\n")";
} else if (ch == '\b') { } else if (ch == '\b') {
out << "\"\\b\""; out << R"("\b")";
} else if (ch == '\r') {
out << R"("\r")";
} else if (ch == '\f') {
out << R"("\f")";
} else if (ch == '\\') { } else if (ch == '\\') {
out << "\"\\\\\""; out << R"("\\")";
} else if (0x20 <= ch && ch <= 0x7e) { } else if (0x20 <= ch && ch <= 0x7e) {
out << "\"" << ch << "\""; out << "\"" << ch << "\"";
} else { } else {
out << "\""; out << "\"";
WriteDoubleQuoteEscapeSequence(out, ch); WriteDoubleQuoteEscapeSequence(out, ch, stringEscapingStyle);
out << "\""; out << "\"";
} }
return true; return true;
} }
bool WriteComment(ostream_wrapper& out, const std::string& str, bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
std::size_t postCommentIndent) { std::size_t postCommentIndent) {
const std::size_t curIndent = out.col(); const std::size_t curIndent = out.col();
out << "#" << Indentation(postCommentIndent); out << "#" << Indentation(postCommentIndent);
out.set_comment(); out.set_comment();
int codePoint; int codePoint;
for (std::string::const_iterator i = str.begin(); for (const char* i = str;
GetNextCodePointAndAdvance(codePoint, i, str.end());) { GetNextCodePointAndAdvance(codePoint, i, str + size);) {
if (codePoint == '\n') { if (codePoint == '\n') {
out << "\n" out << "\n"
<< IndentTo(curIndent) << "#" << Indentation(postCommentIndent); << IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
@@ -411,14 +426,14 @@ bool WriteComment(ostream_wrapper& out, const std::string& str,
return true; return true;
} }
bool WriteAlias(ostream_wrapper& out, const std::string& str) { bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size) {
out << "*"; out << "*";
return WriteAliasName(out, str); return WriteAliasName(out, str, size);
} }
bool WriteAnchor(ostream_wrapper& out, const std::string& str) { bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size) {
out << "&"; out << "&";
return WriteAliasName(out, str); return WriteAliasName(out, str, size);
} }
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim) { bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim) {
@@ -475,8 +490,9 @@ bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
} }
bool WriteBinary(ostream_wrapper& out, const Binary& binary) { bool WriteBinary(ostream_wrapper& out, const Binary& binary) {
WriteDoubleQuotedString(out, EncodeBase64(binary.data(), binary.size()), std::string encoded = EncodeBase64(binary.data(), binary.size());
false); WriteDoubleQuotedString(out, encoded.data(), encoded.size(),
StringEscaping::None);
return true; return true;
} }
} // namespace Utils } // namespace Utils

View File

@@ -24,22 +24,27 @@ struct StringFormat {
enum value { Plain, SingleQuoted, DoubleQuoted, Literal }; enum value { Plain, SingleQuoted, DoubleQuoted, Literal };
}; };
struct StringEscaping {
enum value { None, NonAscii, JSON };
};
namespace Utils { namespace Utils {
StringFormat::value ComputeStringFormat(const std::string& str, StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
EMITTER_MANIP strFormat, EMITTER_MANIP strFormat,
FlowType::value flowType, FlowType::value flowType,
bool escapeNonAscii); bool escapeNonAscii);
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str); bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size);
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str, bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
bool escapeNonAscii); StringEscaping::value stringEscaping);
bool WriteLiteralString(ostream_wrapper& out, const std::string& str, bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
std::size_t indent); std::size_t indent);
bool WriteChar(ostream_wrapper& out, char ch); bool WriteChar(ostream_wrapper& out, char ch,
bool WriteComment(ostream_wrapper& out, const std::string& str, StringEscaping::value stringEscapingStyle);
bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
std::size_t postCommentIndent); std::size_t postCommentIndent);
bool WriteAlias(ostream_wrapper& out, const std::string& str); bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size);
bool WriteAnchor(ostream_wrapper& out, const std::string& str); bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size);
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim); bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim);
bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix, bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
const std::string& tag); const std::string& tag);

View File

@@ -1,31 +1,20 @@
#include "yaml-cpp/exceptions.h" #include "yaml-cpp/exceptions.h"
#include "yaml-cpp/noexcept.h"
// 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
namespace YAML { namespace YAML {
// These destructors are defined out-of-line so the vtable is only emitted once. // These destructors are defined out-of-line so the vtable is only emitted once.
Exception::~Exception() YAML_CPP_NOEXCEPT {} Exception::~Exception() YAML_CPP_NOEXCEPT = default;
ParserException::~ParserException() YAML_CPP_NOEXCEPT {} ParserException::~ParserException() YAML_CPP_NOEXCEPT = default;
RepresentationException::~RepresentationException() YAML_CPP_NOEXCEPT {} RepresentationException::~RepresentationException() YAML_CPP_NOEXCEPT = default;
InvalidScalar::~InvalidScalar() YAML_CPP_NOEXCEPT {} InvalidScalar::~InvalidScalar() YAML_CPP_NOEXCEPT = default;
KeyNotFound::~KeyNotFound() YAML_CPP_NOEXCEPT {} KeyNotFound::~KeyNotFound() YAML_CPP_NOEXCEPT = default;
InvalidNode::~InvalidNode() YAML_CPP_NOEXCEPT {} InvalidNode::~InvalidNode() YAML_CPP_NOEXCEPT = default;
BadConversion::~BadConversion() YAML_CPP_NOEXCEPT {} BadConversion::~BadConversion() YAML_CPP_NOEXCEPT = default;
BadDereference::~BadDereference() YAML_CPP_NOEXCEPT {} BadDereference::~BadDereference() YAML_CPP_NOEXCEPT = default;
BadSubscript::~BadSubscript() YAML_CPP_NOEXCEPT {} BadSubscript::~BadSubscript() YAML_CPP_NOEXCEPT = default;
BadPushback::~BadPushback() YAML_CPP_NOEXCEPT {} BadPushback::~BadPushback() YAML_CPP_NOEXCEPT = default;
BadInsert::~BadInsert() YAML_CPP_NOEXCEPT {} BadInsert::~BadInsert() YAML_CPP_NOEXCEPT = default;
EmitterException::~EmitterException() YAML_CPP_NOEXCEPT {} EmitterException::~EmitterException() YAML_CPP_NOEXCEPT = default;
BadFile::~BadFile() YAML_CPP_NOEXCEPT {} BadFile::~BadFile() YAML_CPP_NOEXCEPT = default;
} } // namespace YAML
#undef YAML_CPP_NOEXCEPT

View File

@@ -12,8 +12,7 @@ namespace YAML {
namespace Exp { namespace Exp {
unsigned ParseHex(const std::string& str, const Mark& mark) { unsigned ParseHex(const std::string& str, const Mark& mark) {
unsigned value = 0; unsigned value = 0;
for (std::size_t i = 0; i < str.size(); i++) { for (char ch : str) {
char ch = str[i];
int digit = 0; int digit = 0;
if ('a' <= ch && ch <= 'f') if ('a' <= ch && ch <= 'f')
digit = ch - 'a' + 10; digit = ch - 'a' + 10;
@@ -55,12 +54,14 @@ std::string Escape(Stream& in, int codeLength) {
// now break it up into chars // now break it up into chars
if (value <= 0x7F) if (value <= 0x7F)
return Str(value); return Str(value);
else if (value <= 0x7FF)
if (value <= 0x7FF)
return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
else if (value <= 0xFFFF)
if (value <= 0xFFFF)
return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) +
Str(0x80 + (value & 0x3F)); Str(0x80 + (value & 0x3F));
else
return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
} }
@@ -104,7 +105,7 @@ std::string Escape(Stream& in) {
case 'e': case 'e':
return "\x1B"; return "\x1B";
case ' ': case ' ':
return "\x20"; return R"( )";
case '\"': case '\"':
return "\""; return "\"";
case '\'': case '\'':
@@ -132,5 +133,5 @@ std::string Escape(Stream& in) {
std::stringstream msg; std::stringstream msg;
throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch); throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch);
} }
} } // namespace Exp
} } // namespace YAML

View File

@@ -37,7 +37,7 @@ inline const RegEx& Blank() {
return e; return e;
} }
inline const RegEx& Break() { inline const RegEx& Break() {
static const RegEx e = RegEx('\n') | RegEx("\r\n"); static const RegEx e = RegEx('\n') | RegEx("\r\n") | RegEx('\r');
return e; return e;
} }
inline const RegEx& BlankOrBreak() { inline const RegEx& BlankOrBreak() {
@@ -110,13 +110,17 @@ inline const RegEx& Value() {
return e; return e;
} }
inline const RegEx& ValueInFlow() { inline const RegEx& ValueInFlow() {
static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx(",}", REGEX_OR)); static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx(",]}", REGEX_OR));
return e; return e;
} }
inline const RegEx& ValueInJSONFlow() { inline const RegEx& ValueInJSONFlow() {
static const RegEx e = RegEx(':'); static const RegEx e = RegEx(':');
return e; return e;
} }
inline const RegEx& Ampersand() {
static const RegEx e = RegEx('&');
return e;
}
inline const RegEx Comment() { inline const RegEx Comment() {
static const RegEx e = RegEx('#'); static const RegEx e = RegEx('#');
return e; return e;
@@ -155,7 +159,7 @@ inline const RegEx& PlainScalar() {
inline const RegEx& PlainScalarInFlow() { inline const RegEx& PlainScalarInFlow() {
static const RegEx e = static const RegEx e =
!(BlankOrBreak() | RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) | !(BlankOrBreak() | RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) |
(RegEx("-:", REGEX_OR) + Blank())); (RegEx("-:", REGEX_OR) + (Blank() | RegEx())));
return e; return e;
} }
inline const RegEx& EndScalar() { inline const RegEx& EndScalar() {

238
src/fptostring.cpp Normal file
View File

@@ -0,0 +1,238 @@
#include "yaml-cpp/fptostring.h"
#include "contrib/dragonbox.h"
#include <array>
#include <cassert>
#include <cmath>
#include <limits>
#include <sstream>
#include <tuple>
namespace YAML {
namespace detail {
namespace fp_formatting {
/**
* Converts a integer into its ASCII digits.
*
* @param begin/end - a buffer, must be at least 20bytes long.
* @param value - input value.
* @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
* @return - number of digits filled into the buffer (or -1 if preconditions are not meet)
*
* Example:
* std::array<char, 20> buffer;
* auto ct = ConvertToChars(buffer.begin(), buffer.end(), 23, 3);
* assert(ct = 3);
* assert(buffer[0] == '0');
* assert(buffer[1] == '2');
* assert(buffer[2] == '3');
*/
int ConvertToChars(char* begin, char* end, size_t value, int width=1) {
// precondition of this function (will trigger in debug build)
assert(width >= 1);
assert(end >= begin); // end must be after begin
assert(end-begin >= width); // Buffer must be large enough
assert(end-begin >= 20); // 2^64 has 20digits, so at least 20 digits must be available
// defensive programming, abort if precondition are not met (will trigger in release build)
if (width < 1) {
return -1;
}
if (end < begin) {
return -1;
}
if (end-begin < width) {
return -1;
}
if (end-begin < 20) {
return -1;
}
// count number of digits, and fill digits array accordingly
int digits_ct{};
while (value > 0) {
char c = value % 10 + '0';
value = value / 10;
digits_ct += 1;
*(end-digits_ct) = c;
}
while(digits_ct < width) {
assert(digits_ct < 64);
digits_ct += 1;
*(end-digits_ct) = '0';
}
// move data to the front of the array
std::memmove(begin, end-digits_ct, digits_ct);
return digits_ct;
}
/**
* Converts a float or double to a string.
*
* converts a value 'v' to a string. Uses dragonbox for formatting.
*/
template <typename T>
std::string FpToString(T v, int precision = 0) {
// hard coded constant, at which exponent should switch to a scientific notation
int const lowerExponentThreshold = -5;
int const upperExponentThreshold = (precision==0)?6:precision;
if (precision == 0) {
precision = 6;
}
// dragonbox/to_decimal does not handle value 0, inf, NaN
if (v == 0 || std::isinf(v) || std::isnan(v)) {
std::stringstream ss;
ss.imbue(std::locale("C"));
ss << v;
return ss.str();
}
auto r = jkj::dragonbox::to_decimal(v);
auto digits = std::array<char, 20>{}; // max digits of size_t is 20.
auto digits_ct = ConvertToChars(digits.data(), digits.data() + digits.size(), r.significand);
// defensive programming, ConvertToChars arguments are invalid
if (digits_ct == -1) {
std::stringstream ss;
ss.imbue(std::locale("C"));
ss << v;
return ss.str();
}
// check if requested precision is lower than
// required digits for exact representation
if (digits_ct > precision) {
auto diff = digits_ct - precision;
r.exponent += diff;
digits_ct = precision;
// round numbers if required
if (digits[digits_ct] >= '5') {
int i{digits_ct-1};
digits[i] += 1;
while (digits[i] == '9'+1) {
digits_ct -= 1;
r.exponent += 1;
if (i > 0) {
digits[i-1] += 1;
i -= 1;
} else {
digits_ct = 1;
digits[0] = '1';
break;
}
}
}
}
std::array<char, 28> output_buffer; // max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
auto output_ptr = &output_buffer[0];
// print '-' symbol for negative numbers
if (r.is_negative) {
*(output_ptr++) = '-';
}
// exponent if only a single non-zero digit is before the decimal point
int const exponent = r.exponent + digits_ct - 1;
// case 1: scientific notation
if (exponent >= upperExponentThreshold || exponent <= lowerExponentThreshold) {
// print first digit
*(output_ptr++) = digits[0];
// print digits after decimal point
if (digits_ct > 1) {
*(output_ptr++) = '.';
// print significant numbers after decimal point
for (int i{1}; i < digits_ct; ++i) {
*(output_ptr++) = digits[i];
}
}
*(output_ptr++) = 'e';
*(output_ptr++) = (exponent>=0)?'+':'-';
auto exp_digits = std::array<char, 20>{};
auto exp_digits_ct = ConvertToChars(exp_digits.data(), exp_digits.data() + exp_digits.size(), std::abs(exponent), /*.precision=*/ 2);
// defensive programming, ConvertToChars arguments are invalid
if (exp_digits_ct == -1) {
std::stringstream ss;
ss.imbue(std::locale("C"));
ss << v;
return ss.str();
}
for (int i{0}; i < exp_digits_ct; ++i) {
*(output_ptr++) = exp_digits[i];
}
// case 2: default notation
} else {
auto const digits_end = digits.begin() + digits_ct;
auto digits_iter = digits.begin();
// print digits before point
int const before_decimal_digits = digits_ct + r.exponent;
if (before_decimal_digits > 0) {
// print digits before point
for (int i{0}; i < std::min(before_decimal_digits, digits_ct); ++i) {
*(output_ptr++) = *(digits_iter++);
}
// print trailing zeros before point
for (int i{0}; i < before_decimal_digits - digits_ct; ++i) {
*(output_ptr++) = '0';
}
// print 0 before point if none where printed before
} else {
*(output_ptr++) = '0';
}
if (digits_iter != digits_end) {
*(output_ptr++) = '.';
// print 0 after decimal point, to fill until first digits
int const after_decimal_zeros = -digits_ct - r.exponent;
for (int i{0}; i < after_decimal_zeros; ++i) {
*(output_ptr++) = '0';
}
// print significant numbers after decimal point
for (;digits_iter < digits_end; ++digits_iter) {
*(output_ptr++) = *digits_iter;
}
}
}
*output_ptr = '\0';
return std::string{&output_buffer[0], output_ptr};
}
}
}
std::string FpToString(float v, size_t precision) {
return detail::fp_formatting::FpToString(v, precision);
}
std::string FpToString(double v, size_t precision) {
return detail::fp_formatting::FpToString(v, precision);
}
/**
* dragonbox only works for floats/doubles not long double
*/
std::string FpToString(long double v, size_t precision) {
std::stringstream ss;
ss.imbue(std::locale("C"));
if (precision == 0) {
precision = std::numeric_limits<long double>::max_digits10;
}
ss.precision(precision);
ss << v;
return ss.str();
}
}

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#endif #endif
#include <iostream>
#include <cstddef> #include <cstddef>
#include "yaml-cpp/ostream_wrapper.h" #include "yaml-cpp/ostream_wrapper.h"

View File

@@ -22,5 +22,5 @@ node& memory::create_node() {
void memory::merge(const memory& rhs) { void memory::merge(const memory& rhs) {
m_nodes.insert(rhs.m_nodes.begin(), rhs.m_nodes.end()); m_nodes.insert(rhs.m_nodes.begin(), rhs.m_nodes.end());
} }
} } // namespace detail
} } // namespace YAML

View File

@@ -9,4 +9,4 @@ Node Clone(const Node& node) {
events.Emit(builder); events.Emit(builder);
return builder.Root(); return builder.Root();
} }
} } // namespace YAML

View File

@@ -1,4 +1,5 @@
#include <assert.h> #include <algorithm>
#include <cassert>
#include <iterator> #include <iterator>
#include <sstream> #include <sstream>
@@ -12,6 +13,7 @@
namespace YAML { namespace YAML {
namespace detail { namespace detail {
YAML_CPP_API std::atomic<size_t> node::m_amount{0};
const std::string& node_data::empty_scalar() { const std::string& node_data::empty_scalar() {
static const std::string svalue; static const std::string svalue;
@@ -108,9 +110,9 @@ void node_data::compute_seq_size() const {
} }
void node_data::compute_map_size() const { void node_data::compute_map_size() const {
kv_pairs::iterator it = m_undefinedPairs.begin(); auto it = m_undefinedPairs.begin();
while (it != m_undefinedPairs.end()) { while (it != m_undefinedPairs.end()) {
kv_pairs::iterator jt = std::next(it); auto jt = std::next(it);
if (it->first->is_defined() && it->second->is_defined()) if (it->first->is_defined() && it->second->is_defined())
m_undefinedPairs.erase(it); m_undefinedPairs.erase(it);
it = jt; it = jt;
@@ -119,7 +121,7 @@ void node_data::compute_map_size() const {
const_node_iterator node_data::begin() const { const_node_iterator node_data::begin() const {
if (!m_isDefined) if (!m_isDefined)
return const_node_iterator(); return {};
switch (m_type) { switch (m_type) {
case NodeType::Sequence: case NodeType::Sequence:
@@ -127,13 +129,13 @@ const_node_iterator node_data::begin() const {
case NodeType::Map: case NodeType::Map:
return const_node_iterator(m_map.begin(), m_map.end()); return const_node_iterator(m_map.begin(), m_map.end());
default: default:
return const_node_iterator(); return {};
} }
} }
node_iterator node_data::begin() { node_iterator node_data::begin() {
if (!m_isDefined) if (!m_isDefined)
return node_iterator(); return {};
switch (m_type) { switch (m_type) {
case NodeType::Sequence: case NodeType::Sequence:
@@ -141,13 +143,13 @@ node_iterator node_data::begin() {
case NodeType::Map: case NodeType::Map:
return node_iterator(m_map.begin(), m_map.end()); return node_iterator(m_map.begin(), m_map.end());
default: default:
return node_iterator(); return {};
} }
} }
const_node_iterator node_data::end() const { const_node_iterator node_data::end() const {
if (!m_isDefined) if (!m_isDefined)
return const_node_iterator(); return {};
switch (m_type) { switch (m_type) {
case NodeType::Sequence: case NodeType::Sequence:
@@ -155,13 +157,13 @@ const_node_iterator node_data::end() const {
case NodeType::Map: case NodeType::Map:
return const_node_iterator(m_map.end(), m_map.end()); return const_node_iterator(m_map.end(), m_map.end());
default: default:
return const_node_iterator(); return {};
} }
} }
node_iterator node_data::end() { node_iterator node_data::end() {
if (!m_isDefined) if (!m_isDefined)
return node_iterator(); return {};
switch (m_type) { switch (m_type) {
case NodeType::Sequence: case NodeType::Sequence:
@@ -169,12 +171,13 @@ node_iterator node_data::end() {
case NodeType::Map: case NodeType::Map:
return node_iterator(m_map.end(), m_map.end()); return node_iterator(m_map.end(), m_map.end());
default: default:
return node_iterator(); return {};
} }
} }
// sequence // sequence
void node_data::push_back(node& node, shared_memory_holder /* pMemory */) { void node_data::push_back(node& node,
const shared_memory_holder& /* pMemory */) {
if (m_type == NodeType::Undefined || m_type == NodeType::Null) { if (m_type == NodeType::Undefined || m_type == NodeType::Null) {
m_type = NodeType::Sequence; m_type = NodeType::Sequence;
reset_sequence(); reset_sequence();
@@ -186,7 +189,8 @@ void node_data::push_back(node& node, shared_memory_holder /* pMemory */) {
m_sequence.push_back(&node); m_sequence.push_back(&node);
} }
void node_data::insert(node& key, node& value, shared_memory_holder pMemory) { void node_data::insert(node& key, node& value,
const shared_memory_holder& pMemory) {
switch (m_type) { switch (m_type) {
case NodeType::Map: case NodeType::Map:
break; break;
@@ -196,27 +200,28 @@ void node_data::insert(node& key, node& value, shared_memory_holder pMemory) {
convert_to_map(pMemory); convert_to_map(pMemory);
break; break;
case NodeType::Scalar: case NodeType::Scalar:
throw BadSubscript(key); throw BadSubscript(m_mark, key);
} }
insert_map_pair(key, value); insert_map_pair(key, value);
} }
// indexing // indexing
node* node_data::get(node& key, shared_memory_holder /* pMemory */) const { node* node_data::get(node& key,
const shared_memory_holder& /* pMemory */) const {
if (m_type != NodeType::Map) { if (m_type != NodeType::Map) {
return nullptr; return nullptr;
} }
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { for (const auto& it : m_map) {
if (it->first->is(key)) if (it.first->is(key))
return it->second; return it.second;
} }
return nullptr; return nullptr;
} }
node& node_data::get(node& key, shared_memory_holder pMemory) { node& node_data::get(node& key, const shared_memory_holder& pMemory) {
switch (m_type) { switch (m_type) {
case NodeType::Map: case NodeType::Map:
break; break;
@@ -226,12 +231,12 @@ node& node_data::get(node& key, shared_memory_holder pMemory) {
convert_to_map(pMemory); convert_to_map(pMemory);
break; break;
case NodeType::Scalar: case NodeType::Scalar:
throw BadSubscript(key); throw BadSubscript(m_mark, key);
} }
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { for (const auto& it : m_map) {
if (it->first->is(key)) if (it.first->is(key))
return *it->second; return *it.second;
} }
node& value = pMemory->create_node(); node& value = pMemory->create_node();
@@ -239,24 +244,27 @@ node& node_data::get(node& key, shared_memory_holder pMemory) {
return value; return value;
} }
bool node_data::remove(node& key, shared_memory_holder /* pMemory */) { bool node_data::remove(node& key, const shared_memory_holder& /* pMemory */) {
if (m_type != NodeType::Map) if (m_type != NodeType::Map)
return false; return false;
for (kv_pairs::iterator it = m_undefinedPairs.begin(); for (auto it = m_undefinedPairs.begin(); it != m_undefinedPairs.end();) {
it != m_undefinedPairs.end();) { auto jt = std::next(it);
kv_pairs::iterator jt = std::next(it);
if (it->first->is(key)) if (it->first->is(key))
m_undefinedPairs.erase(it); m_undefinedPairs.erase(it);
it = jt; it = jt;
} }
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) { auto it =
if (it->first->is(key)) { std::find_if(m_map.begin(), m_map.end(),
[&](std::pair<YAML::detail::node*, YAML::detail::node*> j) {
return (j.first->is(key));
});
if (it != m_map.end()) {
m_map.erase(it); m_map.erase(it);
return true; return true;
} }
}
return false; return false;
} }
@@ -278,7 +286,7 @@ void node_data::insert_map_pair(node& key, node& value) {
m_undefinedPairs.emplace_back(&key, &value); m_undefinedPairs.emplace_back(&key, &value);
} }
void node_data::convert_to_map(shared_memory_holder pMemory) { void node_data::convert_to_map(const shared_memory_holder& pMemory) {
switch (m_type) { switch (m_type) {
case NodeType::Undefined: case NodeType::Undefined:
case NodeType::Null: case NodeType::Null:
@@ -296,12 +304,13 @@ void node_data::convert_to_map(shared_memory_holder pMemory) {
} }
} }
void node_data::convert_sequence_to_map(shared_memory_holder pMemory) { void node_data::convert_sequence_to_map(const shared_memory_holder& pMemory) {
assert(m_type == NodeType::Sequence); assert(m_type == NodeType::Sequence);
reset_map(); reset_map();
for (std::size_t i = 0; i < m_sequence.size(); i++) { for (std::size_t i = 0; i < m_sequence.size(); i++) {
std::stringstream stream; std::stringstream stream;
stream.imbue(std::locale("C"));
stream << i; stream << i;
node& key = pMemory->create_node(); node& key = pMemory->create_node();

View File

@@ -1,4 +1,3 @@
#include <assert.h>
#include <cassert> #include <cassert>
#include "nodebuilder.h" #include "nodebuilder.h"
@@ -20,7 +19,7 @@ NodeBuilder::NodeBuilder()
m_anchors.push_back(nullptr); // since the anchors start at 1 m_anchors.push_back(nullptr); // since the anchors start at 1
} }
NodeBuilder::~NodeBuilder() {} NodeBuilder::~NodeBuilder() = default;
Node NodeBuilder::Root() { Node NodeBuilder::Root() {
if (!m_pRoot) if (!m_pRoot)
@@ -93,7 +92,7 @@ void NodeBuilder::Push(detail::node& node) {
m_stack.push_back(&node); m_stack.push_back(&node);
if (needsKey) if (needsKey)
m_keys.push_back(PushedKey(&node, false)); m_keys.emplace_back(&node, false);
} }
void NodeBuilder::Pop() { void NodeBuilder::Pop() {

View File

@@ -31,25 +31,25 @@ class NodeBuilder : public EventHandler {
NodeBuilder(NodeBuilder&&) = delete; NodeBuilder(NodeBuilder&&) = delete;
NodeBuilder& operator=(const NodeBuilder&) = delete; NodeBuilder& operator=(const NodeBuilder&) = delete;
NodeBuilder& operator=(NodeBuilder&&) = delete; NodeBuilder& operator=(NodeBuilder&&) = delete;
virtual ~NodeBuilder(); ~NodeBuilder() override;
Node Root(); Node Root();
virtual void OnDocumentStart(const Mark& mark); void OnDocumentStart(const Mark& mark) override;
virtual void OnDocumentEnd(); void OnDocumentEnd() override;
virtual void OnNull(const Mark& mark, anchor_t anchor); void OnNull(const Mark& mark, anchor_t anchor) override;
virtual void OnAlias(const Mark& mark, anchor_t anchor); void OnAlias(const Mark& mark, anchor_t anchor) override;
virtual void OnScalar(const Mark& mark, const std::string& tag, void OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value); anchor_t anchor, const std::string& value) override;
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, void OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style); anchor_t anchor, EmitterStyle::value style) override;
virtual void OnSequenceEnd(); void OnSequenceEnd() override;
virtual void OnMapStart(const Mark& mark, const std::string& tag, void OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style); anchor_t anchor, EmitterStyle::value style) override;
virtual void OnMapEnd(); void OnMapEnd() override;
private: private:
detail::node& Push(const Mark& mark, anchor_t anchor); detail::node& Push(const Mark& mark, anchor_t anchor);
@@ -61,11 +61,11 @@ class NodeBuilder : public EventHandler {
detail::shared_memory_holder m_pMemory; detail::shared_memory_holder m_pMemory;
detail::node* m_pRoot; detail::node* m_pRoot;
typedef std::vector<detail::node*> Nodes; using Nodes = std::vector<detail::node *>;
Nodes m_stack; Nodes m_stack;
Nodes m_anchors; Nodes m_anchors;
typedef std::pair<detail::node*, bool> PushedKey; using PushedKey = std::pair<detail::node*, bool>;
std::vector<PushedKey> m_keys; std::vector<PushedKey> m_keys;
std::size_t m_mapDepth; std::size_t m_mapDepth;
}; };

View File

@@ -13,7 +13,7 @@ void NodeEvents::AliasManager::RegisterReference(const detail::node& node) {
anchor_t NodeEvents::AliasManager::LookupAnchor( anchor_t NodeEvents::AliasManager::LookupAnchor(
const detail::node& node) const { const detail::node& node) const {
AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(node.ref()); auto it = m_anchorByIdentity.find(node.ref());
if (it == m_anchorByIdentity.end()) if (it == m_anchorByIdentity.end())
return 0; return 0;
return it->second; return it->second;
@@ -32,13 +32,12 @@ void NodeEvents::Setup(const detail::node& node) {
return; return;
if (node.type() == NodeType::Sequence) { if (node.type() == NodeType::Sequence) {
for (detail::const_node_iterator it = node.begin(); it != node.end(); ++it) for (auto element : node)
Setup(**it); Setup(*element);
} else if (node.type() == NodeType::Map) { } else if (node.type() == NodeType::Map) {
for (detail::const_node_iterator it = node.begin(); it != node.end(); for (auto element : node) {
++it) { Setup(*element.first);
Setup(*it->first); Setup(*element.second);
Setup(*it->second);
} }
} }
} }
@@ -77,17 +76,15 @@ void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
break; break;
case NodeType::Sequence: case NodeType::Sequence:
handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style()); handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style());
for (detail::const_node_iterator it = node.begin(); it != node.end(); for (auto element : node)
++it) Emit(*element, handler, am);
Emit(**it, handler, am);
handler.OnSequenceEnd(); handler.OnSequenceEnd();
break; break;
case NodeType::Map: case NodeType::Map:
handler.OnMapStart(Mark(), node.tag(), anchor, node.style()); handler.OnMapStart(Mark(), node.tag(), anchor, node.style());
for (detail::const_node_iterator it = node.begin(); it != node.end(); for (auto element : node) {
++it) { Emit(*element.first, handler, am);
Emit(*it->first, handler, am); Emit(*element.second, handler, am);
Emit(*it->second, handler, am);
} }
handler.OnMapEnd(); handler.OnMapEnd();
break; break;
@@ -95,7 +92,7 @@ void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
} }
bool NodeEvents::IsAliased(const detail::node& node) const { bool NodeEvents::IsAliased(const detail::node& node) const {
RefCount::const_iterator it = m_refCount.find(node.ref()); auto it = m_refCount.find(node.ref());
return it != m_refCount.end() && it->second > 1; return it != m_refCount.end() && it->second > 1;
} }
} // namespace YAML } // namespace YAML

View File

@@ -45,7 +45,7 @@ class NodeEvents {
anchor_t _CreateNewAnchor() { return ++m_curAnchor; } anchor_t _CreateNewAnchor() { return ++m_curAnchor; }
private: private:
typedef std::map<const detail::node_ref*, anchor_t> AnchorByIdentity; using AnchorByIdentity = std::map<const detail::node_ref*, anchor_t>;
AnchorByIdentity m_anchorByIdentity; AnchorByIdentity m_anchorByIdentity;
anchor_t m_curAnchor; anchor_t m_curAnchor;
@@ -60,7 +60,7 @@ class NodeEvents {
detail::shared_memory_holder m_pMemory; detail::shared_memory_holder m_pMemory;
detail::node* m_root; 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; RefCount m_refCount;
}; };
} // namespace YAML } // namespace YAML

View File

@@ -1,10 +1,17 @@
#include "yaml-cpp/null.h" #include "yaml-cpp/null.h"
#include <cstring>
namespace YAML { namespace YAML {
_Null Null; _Null Null;
bool IsNullString(const std::string& str) { template <std::size_t N>
return str.empty() || str == "~" || str == "null" || str == "Null" || static bool same(const char* str, std::size_t size, const char (&literal)[N]) {
str == "NULL"; constexpr int literalSize = N - 1; // minus null terminator
return size == literalSize && std::strncmp(str, literal, literalSize) == 0;
} }
bool IsNullString(const char* str, std::size_t size) {
return size == 0 || same(str, size, "~") || same(str, size, "null") ||
same(str, size, "Null") || same(str, size, "NULL");
} }
} // namespace YAML

View File

@@ -2,7 +2,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <iostream> #include <ostream>
namespace YAML { namespace YAML {
ostream_wrapper::ostream_wrapper() ostream_wrapper::ostream_wrapper()
@@ -21,7 +21,7 @@ ostream_wrapper::ostream_wrapper(std::ostream& stream)
m_col(0), m_col(0),
m_comment(false) {} m_comment(false) {}
ostream_wrapper::~ostream_wrapper() {} ostream_wrapper::~ostream_wrapper() = default;
void ostream_wrapper::write(const std::string& str) { void ostream_wrapper::write(const std::string& str) {
if (m_pStream) { if (m_pStream) {
@@ -31,8 +31,8 @@ void ostream_wrapper::write(const std::string& str) {
std::copy(str.begin(), str.end(), m_buffer.begin() + m_pos); std::copy(str.begin(), str.end(), m_buffer.begin() + m_pos);
} }
for (std::size_t i = 0; i < str.size(); i++) { for (char ch : str) {
update_pos(str[i]); update_pos(ch);
} }
} }

View File

@@ -3,10 +3,10 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/parser.h"
#include "nodebuilder.h" #include "nodebuilder.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/parser.h"
namespace YAML { namespace YAML {
Node Load(const std::string& input) { Node Load(const std::string& input) {
@@ -30,9 +30,9 @@ Node Load(std::istream& input) {
} }
Node LoadFile(const std::string& filename) { Node LoadFile(const std::string& filename) {
std::ifstream fin(filename.c_str()); std::ifstream fin(filename);
if (!fin) { if (!fin) {
throw BadFile(); throw BadFile(filename);
} }
return Load(fin); return Load(fin);
} }
@@ -51,9 +51,9 @@ std::vector<Node> LoadAll(std::istream& input) {
std::vector<Node> docs; std::vector<Node> docs;
Parser parser(input); Parser parser(input);
while (1) { while (true) {
NodeBuilder builder; NodeBuilder builder;
if (!parser.HandleNextDocument(builder)) { if (!parser.HandleNextDocument(builder) || builder.Root().IsNull()) {
break; break;
} }
docs.push_back(builder.Root()); docs.push_back(builder.Root());
@@ -63,9 +63,9 @@ std::vector<Node> LoadAll(std::istream& input) {
} }
std::vector<Node> LoadAllFromFile(const std::string& filename) { std::vector<Node> LoadAllFromFile(const std::string& filename) {
std::ifstream fin(filename.c_str()); std::ifstream fin(filename);
if (!fin) { if (!fin) {
throw BadFile(); throw BadFile(filename);
} }
return LoadAll(fin); return LoadAll(fin);
} }

View File

@@ -15,11 +15,9 @@ Parser::Parser() : m_pScanner{}, m_pDirectives{} {}
Parser::Parser(std::istream& in) : Parser() { Load(in); } Parser::Parser(std::istream& in) : Parser() { Load(in); }
Parser::~Parser() {} Parser::~Parser() = default;
Parser::operator bool() const { Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); }
return m_pScanner.get() && !m_pScanner->empty();
}
void Parser::Load(std::istream& in) { void Parser::Load(std::istream& in) {
m_pScanner.reset(new Scanner(in)); m_pScanner.reset(new Scanner(in));
@@ -27,7 +25,7 @@ void Parser::Load(std::istream& in) {
} }
bool Parser::HandleNextDocument(EventHandler& eventHandler) { bool Parser::HandleNextDocument(EventHandler& eventHandler) {
if (!m_pScanner.get()) if (!m_pScanner)
return false; return false;
ParseDirectives(); ParseDirectives();
@@ -43,11 +41,7 @@ bool Parser::HandleNextDocument(EventHandler& eventHandler) {
void Parser::ParseDirectives() { void Parser::ParseDirectives() {
bool readDirective = false; bool readDirective = false;
while (1) { while (!m_pScanner->empty()) {
if (m_pScanner->empty()) {
break;
}
Token& token = m_pScanner->peek(); Token& token = m_pScanner->peek();
if (token.type != Token::DIRECTIVE) { if (token.type != Token::DIRECTIVE) {
break; break;
@@ -83,6 +77,7 @@ void Parser::HandleYamlDirective(const Token& token) {
} }
std::stringstream str(token.params[0]); std::stringstream str(token.params[0]);
str.imbue(std::locale("C"));
str >> m_pDirectives->version.major; str >> m_pDirectives->version.major;
str.get(); str.get();
str >> m_pDirectives->version.minor; str >> m_pDirectives->version.minor;
@@ -113,15 +108,11 @@ void Parser::HandleTagDirective(const Token& token) {
} }
void Parser::PrintTokens(std::ostream& out) { void Parser::PrintTokens(std::ostream& out) {
if (!m_pScanner.get()) { if (!m_pScanner) {
return; return;
} }
while (1) { while (!m_pScanner->empty()) {
if (m_pScanner->empty()) {
break;
}
out << m_pScanner->peek() << "\n"; out << m_pScanner->peek() << "\n";
m_pScanner->pop(); m_pScanner->pop();
} }

View File

@@ -34,7 +34,7 @@ class YAML_CPP_API RegEx {
explicit RegEx(char ch); explicit RegEx(char ch);
RegEx(char a, char z); RegEx(char a, char z);
RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ);
~RegEx() {} ~RegEx() = default;
friend YAML_CPP_API RegEx operator!(const RegEx& ex); 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);

View File

@@ -8,8 +8,8 @@
#endif #endif
#include "stream.h" #include "stream.h"
#include "stringsource.h"
#include "streamcharsource.h" #include "streamcharsource.h"
#include "stringsource.h"
namespace YAML { namespace YAML {
// query matches // query matches
@@ -27,6 +27,10 @@ inline bool RegEx::Matches(const Stream& in) const { return Match(in) >= 0; }
template <typename Source> template <typename Source>
inline bool RegEx::Matches(const Source& source) const { inline bool RegEx::Matches(const Source& source) const {
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) || __cplusplus >= 201103L)
static_assert(!std::is_same<Source, const char*>::value,
#endif
"Must use StringCharSource instead of plain C-string");
return Match(source) >= 0; return Match(source) >= 0;
} }
@@ -106,9 +110,8 @@ inline int RegEx::MatchOpEmpty(const Source& source) const {
template <> template <>
inline int RegEx::MatchOpEmpty<StringCharSource>( inline int RegEx::MatchOpEmpty<StringCharSource>(
const StringCharSource& source) const { const StringCharSource& source) const {
return !source return !source ? 0 : -1; // the empty regex only is successful on the empty
? 0 // string
: -1; // the empty regex only is successful on the empty string
} }
// MatchOperator // MatchOperator
@@ -130,8 +133,8 @@ inline int RegEx::MatchOpRange(const Source& source) const {
// OrOperator // OrOperator
template <typename Source> template <typename Source>
inline int RegEx::MatchOpOr(const Source& source) const { inline int RegEx::MatchOpOr(const Source& source) const {
for (std::size_t i = 0; i < m_params.size(); i++) { for (const RegEx& param : m_params) {
int n = m_params[i].MatchUnchecked(source); int n = param.MatchUnchecked(source);
if (n >= 0) if (n >= 0)
return n; return n;
} }
@@ -169,8 +172,8 @@ inline int RegEx::MatchOpNot(const Source& source) const {
template <typename Source> template <typename Source>
inline int RegEx::MatchOpSeq(const Source& source) const { inline int RegEx::MatchOpSeq(const Source& source) const {
int offset = 0; int offset = 0;
for (std::size_t i = 0; i < m_params.size(); i++) { for (const RegEx& param : m_params) {
int n = m_params[i].Match(source + offset); // note Match, not int n = param.Match(source + offset); // note Match, not
// MatchUnchecked because we // MatchUnchecked because we
// need to check validity after // need to check validity after
// the offset // the offset
@@ -181,6 +184,6 @@ inline int RegEx::MatchOpSeq(const Source& source) const {
return offset; return offset;
} }
} } // namespace YAML
#endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -13,13 +13,14 @@ Scanner::Scanner(std::istream& in)
m_startedStream(false), m_startedStream(false),
m_endedStream(false), m_endedStream(false),
m_simpleKeyAllowed(false), m_simpleKeyAllowed(false),
m_scalarValueAllowed(false),
m_canBeJSONFlow(false), m_canBeJSONFlow(false),
m_simpleKeys{}, m_simpleKeys{},
m_indents{}, m_indents{},
m_indentRefs{}, m_indentRefs{},
m_flows{} {} m_flows{} {}
Scanner::~Scanner() {} Scanner::~Scanner() = default;
bool Scanner::empty() { bool Scanner::empty() {
EnsureTokensInQueue(); EnsureTokensInQueue();
@@ -51,7 +52,7 @@ Token& Scanner::peek() {
Mark Scanner::mark() const { return INPUT.mark(); } Mark Scanner::mark() const { return INPUT.mark(); }
void Scanner::EnsureTokensInQueue() { void Scanner::EnsureTokensInQueue() {
while (1) { while (true) {
if (!m_tokens.empty()) { if (!m_tokens.empty()) {
Token& token = m_tokens.front(); Token& token = m_tokens.front();
@@ -88,7 +89,7 @@ void Scanner::ScanNextToken() {
return StartStream(); return StartStream();
} }
// get rid of whitespace, etc. (in between tokens it should be irrelevent) // get rid of whitespace, etc. (in between tokens it should be irrelevant)
ScanToNextToken(); ScanToNextToken();
// maybe need to end some blocks // maybe need to end some blocks
@@ -127,6 +128,17 @@ void Scanner::ScanNextToken() {
} }
if (INPUT.peek() == Keys::FlowEntry) { if (INPUT.peek() == Keys::FlowEntry) {
// values starting with `,` are not allowed.
// eg: reject `,foo`
if (INPUT.column() == 0) {
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_FLOW);
}
// if we already parsed a quoted scalar value and we are not in a flow,
// then `,` is not a valid character.
// eg: reject `"foo",`
if (!m_scalarValueAllowed) {
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
}
return ScanFlowEntry(); return ScanFlowEntry();
} }
@@ -159,6 +171,13 @@ void Scanner::ScanNextToken() {
return ScanBlockScalar(); return ScanBlockScalar();
} }
// if we already parsed a quoted scalar value in this line,
// another scalar value is an error.
// eg: reject `"foo" "bar"`
if (!m_scalarValueAllowed) {
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
}
if (INPUT.peek() == '\'' || INPUT.peek() == '\"') { if (INPUT.peek() == '\'' || INPUT.peek() == '\"') {
return ScanQuotedScalar(); return ScanQuotedScalar();
} }
@@ -174,7 +193,7 @@ void Scanner::ScanNextToken() {
} }
void Scanner::ScanToNextToken() { void Scanner::ScanToNextToken() {
while (1) { while (true) {
// first eat whitespace // first eat whitespace
while (INPUT && IsWhitespaceToBeEaten(INPUT.peek())) { while (INPUT && IsWhitespaceToBeEaten(INPUT.peek())) {
if (InBlockContext() && Exp::Tab().Matches(INPUT)) { if (InBlockContext() && Exp::Tab().Matches(INPUT)) {
@@ -203,6 +222,9 @@ void Scanner::ScanToNextToken() {
// oh yeah, and let's get rid of that simple key // oh yeah, and let's get rid of that simple key
InvalidateSimpleKey(); InvalidateSimpleKey();
// new line - we accept a scalar value now
m_scalarValueAllowed = true;
// new line - we may be able to accept a simple key now // new line - we may be able to accept a simple key now
if (InBlockContext()) { if (InBlockContext()) {
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
@@ -245,6 +267,7 @@ const RegEx& Scanner::GetValueRegex() const {
void Scanner::StartStream() { void Scanner::StartStream() {
m_startedStream = true; m_startedStream = true;
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_scalarValueAllowed = true;
std::unique_ptr<IndentMarker> pIndent( std::unique_ptr<IndentMarker> pIndent(
new IndentMarker(-1, IndentMarker::NONE)); new IndentMarker(-1, IndentMarker::NONE));
m_indentRefs.push_back(std::move(pIndent)); m_indentRefs.push_back(std::move(pIndent));
@@ -261,6 +284,7 @@ void Scanner::EndStream() {
PopAllSimpleKeys(); PopAllSimpleKeys();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_scalarValueAllowed = false;
m_endedStream = true; m_endedStream = true;
} }

View File

@@ -9,9 +9,7 @@
#include <cstddef> #include <cstddef>
#include <ios> #include <ios>
#include <map>
#include <queue> #include <queue>
#include <set>
#include <stack> #include <stack>
#include <string> #include <string>
@@ -179,6 +177,7 @@ class Scanner {
// state info // state info
bool m_startedStream, m_endedStream; bool m_startedStream, m_endedStream;
bool m_simpleKeyAllowed; bool m_simpleKeyAllowed;
bool m_scalarValueAllowed;
bool m_canBeJSONFlow; bool m_canBeJSONFlow;
std::stack<SimpleKey> m_simpleKeys; std::stack<SimpleKey> m_simpleKeys;
std::stack<IndentMarker *> m_indents; std::stack<IndentMarker *> m_indents;

View File

@@ -47,7 +47,8 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) { if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
if (params.onDocIndicator == BREAK) { if (params.onDocIndicator == BREAK) {
break; break;
} else if (params.onDocIndicator == THROW) { }
if (params.onDocIndicator == THROW) {
throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR); throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR);
} }
} }
@@ -203,7 +204,7 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
// post-processing // post-processing
if (params.trimTrailingSpaces) { if (params.trimTrailingSpaces) {
std::size_t pos = scalar.find_last_not_of(' '); std::size_t pos = scalar.find_last_not_of(" \t");
if (lastEscapedChar != std::string::npos) { if (lastEscapedChar != std::string::npos) {
if (pos < lastEscapedChar || pos == std::string::npos) { if (pos < lastEscapedChar || pos == std::string::npos) {
pos = lastEscapedChar; pos = lastEscapedChar;
@@ -247,4 +248,4 @@ std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) {
return scalar; return scalar;
} }
} } // namespace YAML

View File

@@ -57,7 +57,7 @@ struct ScanScalarParams {
bool leadingSpaces; bool leadingSpaces;
}; };
std::string ScanScalar(Stream& INPUT, ScanScalarParams& info); std::string ScanScalar(Stream& INPUT, ScanScalarParams& params);
} }
#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -78,4 +78,4 @@ const std::string ScanTagSuffix(Stream& INPUT) {
return tag; return tag;
} }
} } // namespace YAML

View File

@@ -37,7 +37,7 @@ void Scanner::ScanDirective() {
token.value += INPUT.get(); token.value += INPUT.get();
// read parameters // read parameters
while (1) { while (true) {
// first get rid of whitespace // first get rid of whitespace
while (Exp::Blank().Matches(INPUT)) while (Exp::Blank().Matches(INPUT))
INPUT.eat(1); INPUT.eat(1);
@@ -171,7 +171,7 @@ void Scanner::ScanBlockEntry() {
// Key // Key
void Scanner::ScanKey() { void Scanner::ScanKey() {
// handle keys diffently in the block context (and manage indents) // handle keys differently in the block context (and manage indents)
if (InBlockContext()) { if (InBlockContext()) {
if (!m_simpleKeyAllowed) if (!m_simpleKeyAllowed)
throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY); throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY);
@@ -199,7 +199,7 @@ void Scanner::ScanValue() {
// seems fine) // seems fine)
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
} else { } else {
// handle values diffently in the block context (and manage indents) // handle values differently in the block context (and manage indents)
if (InBlockContext()) { if (InBlockContext()) {
if (!m_simpleKeyAllowed) if (!m_simpleKeyAllowed)
throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE);
@@ -211,6 +211,9 @@ void Scanner::ScanValue() {
m_simpleKeyAllowed = InBlockContext(); m_simpleKeyAllowed = InBlockContext();
} }
// we are parsing a `key: value` pair; scalars are always allowed
m_scalarValueAllowed = true;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
INPUT.eat(1); INPUT.eat(1);
@@ -360,6 +363,10 @@ void Scanner::ScanQuotedScalar() {
// and scan // and scan
scalar = ScanScalar(INPUT, params); scalar = ScanScalar(INPUT, params);
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
// we just scanned a quoted scalar;
// we can only have another scalar in this line
// if we are in a flow, eg: `[ "foo", "bar" ]` is ok, but `"foo", "bar"` isn't.
m_scalarValueAllowed = InFlowContext();
m_canBeJSONFlow = true; m_canBeJSONFlow = true;
Token token(Token::NON_PLAIN_SCALAR, mark); Token token(Token::NON_PLAIN_SCALAR, mark);

View File

@@ -7,12 +7,18 @@
#pragma once #pragma once
#endif #endif
#include "yaml-cpp/noexcept.h"
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
namespace YAML { namespace YAML {
class SettingChangeBase;
class SettingChangeBase {
public:
virtual ~SettingChangeBase() = default;
virtual void pop() = 0;
};
template <typename T> template <typename T>
class Setting { class Setting {
@@ -28,12 +34,6 @@ class Setting {
T m_value; T m_value;
}; };
class SettingChangeBase {
public:
virtual ~SettingChangeBase() {}
virtual void pop() = 0;
};
template <typename T> template <typename T>
class SettingChange : public SettingChangeBase { class SettingChange : public SettingChangeBase {
public: public:
@@ -46,7 +46,7 @@ class SettingChange : public SettingChangeBase {
SettingChange& operator=(const SettingChange&) = delete; SettingChange& operator=(const SettingChange&) = delete;
SettingChange& operator=(SettingChange&&) = delete; SettingChange& operator=(SettingChange&&) = delete;
virtual void pop() { m_pCurSetting->restore(m_oldSetting); } void pop() override { m_pCurSetting->restore(m_oldSetting); }
private: private:
Setting<T>* m_pCurSetting; Setting<T>* m_pCurSetting;
@@ -64,27 +64,9 @@ class SettingChanges {
public: public:
SettingChanges() : m_settingChanges{} {} SettingChanges() : m_settingChanges{} {}
SettingChanges(const SettingChanges&) = delete; SettingChanges(const SettingChanges&) = delete;
SettingChanges(SettingChanges&&) = default; SettingChanges(SettingChanges&&) YAML_CPP_NOEXCEPT = default;
SettingChanges& operator=(const SettingChanges&) = delete; SettingChanges& operator=(const SettingChanges&) = delete;
~SettingChanges() { clear(); } SettingChanges& operator=(SettingChanges&& rhs) YAML_CPP_NOEXCEPT {
void clear() {
restore();
m_settingChanges.clear();
}
void restore() {
for (setting_changes::const_iterator it = m_settingChanges.begin();
it != m_settingChanges.end(); ++it)
(*it)->pop();
}
void push(std::unique_ptr<SettingChangeBase> pSettingChange) {
m_settingChanges.push_back(std::move(pSettingChange));
}
// like std::unique_ptr - assignment is transfer of ownership
SettingChanges& operator=(SettingChanges&& rhs) {
if (this == &rhs) if (this == &rhs)
return *this; return *this;
@@ -93,9 +75,24 @@ class SettingChanges {
return *this; return *this;
} }
~SettingChanges() { clear(); }
void clear() YAML_CPP_NOEXCEPT {
restore();
m_settingChanges.clear();
}
void restore() YAML_CPP_NOEXCEPT {
for (const auto& setting : m_settingChanges)
setting->pop();
}
void push(std::unique_ptr<SettingChangeBase> pSettingChange) {
m_settingChanges.push_back(std::move(pSettingChange));
}
private: private:
typedef std::vector<std::unique_ptr<SettingChangeBase>> setting_changes; using setting_changes = std::vector<std::unique_ptr<SettingChangeBase>>;
setting_changes m_settingChanges; setting_changes m_settingChanges;
}; };
} // namespace YAML } // namespace YAML

View File

@@ -5,7 +5,11 @@ namespace YAML {
struct Mark; struct Mark;
Scanner::SimpleKey::SimpleKey(const Mark& mark_, std::size_t flowLevel_) Scanner::SimpleKey::SimpleKey(const Mark& mark_, std::size_t flowLevel_)
: mark(mark_), flowLevel(flowLevel_), pIndent(nullptr), pMapStart(nullptr), pKey(nullptr) {} : mark(mark_),
flowLevel(flowLevel_),
pIndent(nullptr),
pMapStart(nullptr),
pKey(nullptr) {}
void Scanner::SimpleKey::Validate() { void Scanner::SimpleKey::Validate() {
// Note: pIndent will *not* be garbage here; // Note: pIndent will *not* be garbage here;
@@ -125,4 +129,4 @@ void Scanner::PopAllSimpleKeys() {
while (!m_simpleKeys.empty()) while (!m_simpleKeys.empty())
m_simpleKeys.pop(); m_simpleKeys.pop();
} }
} } // namespace YAML

View File

@@ -1,4 +1,3 @@
#include <algorithm>
#include <cstdio> #include <cstdio>
#include <sstream> #include <sstream>
@@ -7,6 +6,7 @@
#include "singledocparser.h" #include "singledocparser.h"
#include "tag.h" #include "tag.h"
#include "token.h" #include "token.h"
#include "yaml-cpp/depthguard.h"
#include "yaml-cpp/emitterstyle.h" #include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/eventhandler.h" #include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep #include "yaml-cpp/exceptions.h" // IWYU pragma: keep
@@ -21,7 +21,7 @@ SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives)
m_anchors{}, m_anchors{},
m_curAnchor(0) {} m_curAnchor(0) {}
SingleDocParser::~SingleDocParser() {} SingleDocParser::~SingleDocParser() = default;
// HandleDocument // HandleDocument
// . Handles the next document // . Handles the next document
@@ -47,6 +47,8 @@ void SingleDocParser::HandleDocument(EventHandler& eventHandler) {
} }
void SingleDocParser::HandleNode(EventHandler& eventHandler) { void SingleDocParser::HandleNode(EventHandler& eventHandler) {
DepthGuard<500> depthguard(depth, m_scanner.mark(), ErrorMsg::BAD_FILE);
// an empty node *is* a possibility // an empty node *is* a possibility
if (m_scanner.empty()) { if (m_scanner.empty()) {
eventHandler.OnNull(m_scanner.mark(), NullAnchor); eventHandler.OnNull(m_scanner.mark(), NullAnchor);
@@ -79,18 +81,25 @@ void SingleDocParser::HandleNode(EventHandler& eventHandler) {
if (!anchor_name.empty()) if (!anchor_name.empty())
eventHandler.OnAnchor(mark, anchor_name); eventHandler.OnAnchor(mark, anchor_name);
const Token& token = m_scanner.peek(); // after parsing properties, an empty node is again a possibility
if (m_scanner.empty()) {
if (token.type == Token::PLAIN_SCALAR && IsNullString(token.value)) {
eventHandler.OnNull(mark, anchor); eventHandler.OnNull(mark, anchor);
m_scanner.pop();
return; return;
} }
const Token& token = m_scanner.peek();
// add non-specific tags // add non-specific tags
if (tag.empty()) if (tag.empty())
tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?"); tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?");
if (token.type == Token::PLAIN_SCALAR
&& tag.compare("?") == 0 && IsNullString(token.value.data(), token.value.size())) {
eventHandler.OnNull(mark, anchor);
m_scanner.pop();
return;
}
// now split based on what kind of node we should be // now split based on what kind of node we should be
switch (token.type) { switch (token.type) {
case Token::PLAIN_SCALAR: case Token::PLAIN_SCALAR:
@@ -157,7 +166,7 @@ void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler) {
m_scanner.pop(); m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq); m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq);
while (1) { while (true) {
if (m_scanner.empty()) if (m_scanner.empty())
throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ); throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ);
@@ -190,7 +199,7 @@ void SingleDocParser::HandleFlowSequence(EventHandler& eventHandler) {
m_scanner.pop(); m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq); m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq);
while (1) { while (true) {
if (m_scanner.empty()) if (m_scanner.empty())
throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW); throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW);
@@ -243,7 +252,7 @@ void SingleDocParser::HandleBlockMap(EventHandler& eventHandler) {
m_scanner.pop(); m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::BlockMap); m_pCollectionStack->PushCollectionType(CollectionType::BlockMap);
while (1) { while (true) {
if (m_scanner.empty()) if (m_scanner.empty())
throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP); throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP);
@@ -282,7 +291,7 @@ void SingleDocParser::HandleFlowMap(EventHandler& eventHandler) {
m_scanner.pop(); m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::FlowMap); m_pCollectionStack->PushCollectionType(CollectionType::FlowMap);
while (1) { while (true) {
if (m_scanner.empty()) if (m_scanner.empty())
throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW); throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW);
@@ -367,7 +376,7 @@ void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor,
anchor_name.clear(); anchor_name.clear();
anchor = NullAnchor; anchor = NullAnchor;
while (1) { while (true) {
if (m_scanner.empty()) if (m_scanner.empty())
return; return;
@@ -413,9 +422,12 @@ anchor_t SingleDocParser::RegisterAnchor(const std::string& name) {
anchor_t SingleDocParser::LookupAnchor(const Mark& mark, anchor_t SingleDocParser::LookupAnchor(const Mark& mark,
const std::string& name) const { const std::string& name) const {
Anchors::const_iterator it = m_anchors.find(name); auto it = m_anchors.find(name);
if (it == m_anchors.end()) if (it == m_anchors.end()) {
throw ParserException(mark, ErrorMsg::UNKNOWN_ANCHOR); std::stringstream ss;
ss << ErrorMsg::UNKNOWN_ANCHOR << name;
throw ParserException(mark, ss.str());
}
return it->second; return it->second;
} }

View File

@@ -15,6 +15,7 @@
namespace YAML { namespace YAML {
class CollectionStack; class CollectionStack;
template <int> class DepthGuard; // depthguard.h
class EventHandler; class EventHandler;
class Node; class Node;
class Scanner; class Scanner;
@@ -55,11 +56,12 @@ class SingleDocParser {
anchor_t LookupAnchor(const Mark& mark, const std::string& name) const; anchor_t LookupAnchor(const Mark& mark, const std::string& name) const;
private: private:
int depth = 0;
Scanner& m_scanner; Scanner& m_scanner;
const Directives& m_directives; const Directives& m_directives;
std::unique_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; Anchors m_anchors;
anchor_t m_curAnchor; anchor_t m_curAnchor;

View File

@@ -1,4 +1,4 @@
#include <iostream> #include <istream>
#include "stream.h" #include "stream.h"
@@ -151,7 +151,8 @@ inline UtfIntroCharType IntroCharTypeOf(std::istream::int_type ch) {
inline char Utf8Adjust(unsigned long ch, unsigned char lead_bits, inline char Utf8Adjust(unsigned long ch, unsigned char lead_bits,
unsigned char rshift) { 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)); const unsigned char mask = (0xFF >> (lead_bits + 1));
return static_cast<char>( return static_cast<char>(
static_cast<unsigned char>(header | ((ch >> rshift) & mask))); static_cast<unsigned char>(header | ((ch >> rshift) & mask)));
@@ -189,14 +190,14 @@ Stream::Stream(std::istream& input)
m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]), m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]),
m_nPrefetchedAvailable(0), m_nPrefetchedAvailable(0),
m_nPrefetchedUsed(0) { m_nPrefetchedUsed(0) {
typedef std::istream::traits_type char_traits; using char_traits = std::istream::traits_type;
if (!input) if (!input)
return; return;
// Determine (or guess) the character-set by reading the BOM, if any. See // Determine (or guess) the character-set by reading the BOM, if any. See
// the YAML specification for the determination algorithm. // the YAML specification for the determination algorithm.
char_traits::int_type intro[4]; char_traits::int_type intro[4]{};
int nIntroUsed = 0; int nIntroUsed = 0;
UtfIntroState state = uis_start; UtfIntroState state = uis_start;
for (; !s_introFinalState[state];) { for (; !s_introFinalState[state];) {
@@ -261,7 +262,24 @@ char Stream::get() {
AdvanceCurrent(); AdvanceCurrent();
m_mark.column++; m_mark.column++;
if (ch == '\n') { // if line ending symbol is unknown, set it to the first
// encountered line ending.
// if line ending '\r' set ending symbol to '\r'
// other wise set it to '\n'
if (!m_lineEndingSymbol) {
if (ch == '\n') { // line ending is '\n'
m_lineEndingSymbol = '\n';
} else if (ch == '\r') {
auto ch2 = peek();
if (ch2 == '\n') { // line ending is '\r\n'
m_lineEndingSymbol = '\n';
} else { // line ending is '\r'
m_lineEndingSymbol = '\r';
}
}
}
if (ch == m_lineEndingSymbol) {
m_mark.column = 0; m_mark.column = 0;
m_mark.line++; m_mark.line++;
} }
@@ -273,9 +291,11 @@ char Stream::get() {
// . Extracts 'n' characters from the stream and updates our position // . Extracts 'n' characters from the stream and updates our position
std::string Stream::get(int n) { std::string Stream::get(int n) {
std::string ret; std::string ret;
ret.reserve(n); if (n > 0) {
ret.reserve(static_cast<std::string::size_type>(n));
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
ret += get(); ret += get();
}
return ret; return ret;
} }
@@ -326,7 +346,7 @@ bool Stream::_ReadAheadTo(size_t i) const {
void Stream::StreamInUtf8() const { void Stream::StreamInUtf8() const {
unsigned char b = GetNextByte(); unsigned char b = GetNextByte();
if (m_input.good()) { if (m_input.good()) {
m_readahead.push_back(b); m_readahead.push_back(static_cast<char>(b));
} }
} }
@@ -347,7 +367,9 @@ void Stream::StreamInUtf16() const {
// Trailing (low) surrogate...ugh, wrong order // Trailing (low) surrogate...ugh, wrong order
QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER);
return; return;
} else if (ch >= 0xD800 && ch < 0xDC00) { }
if (ch >= 0xD800 && ch < 0xDC00) {
// ch is a leading (high) surrogate // ch is a leading (high) surrogate
// Four byte UTF-8 code point // Four byte UTF-8 code point
@@ -372,12 +394,11 @@ void Stream::StreamInUtf16() const {
// Easiest case: queue the codepoint and return // Easiest case: queue the codepoint and return
QueueUnicodeCodepoint(m_readahead, ch); QueueUnicodeCodepoint(m_readahead, ch);
return; return;
} else { }
// Start the loop over with the new high surrogate // Start the loop over with the new high surrogate
ch = chLow; ch = chLow;
continue; continue;
} }
}
// Select the payload bits from the high surrogate // Select the payload bits from the high surrogate
ch &= 0x3FF; ch &= 0x3FF;

View File

@@ -11,11 +11,14 @@
#include <cstddef> #include <cstddef>
#include <deque> #include <deque>
#include <ios> #include <ios>
#include <iostream> #include <istream>
#include <set> #include <set>
#include <string> #include <string>
namespace YAML { namespace YAML {
class StreamCharSource;
class Stream { class Stream {
public: public:
friend class StreamCharSource; friend class StreamCharSource;
@@ -50,6 +53,7 @@ class Stream {
Mark m_mark; Mark m_mark;
CharacterSet m_charSet; CharacterSet m_charSet;
char m_lineEndingSymbol{}; // 0 means it is not determined yet, must be '\n' or '\r'
mutable std::deque<char> m_readahead; mutable std::deque<char> m_readahead;
unsigned char* const m_pPrefetched; unsigned char* const m_pPrefetched;
mutable size_t m_nPrefetchedAvailable; mutable size_t m_nPrefetchedAvailable;

View File

@@ -7,18 +7,20 @@
#pragma once #pragma once
#endif #endif
#include "yaml-cpp/noexcept.h"
#include "stream.h"
#include <cstddef> #include <cstddef>
namespace YAML { namespace YAML {
class StreamCharSource { class StreamCharSource {
public: public:
StreamCharSource(const Stream& stream) : m_offset(0), m_stream(stream) {} StreamCharSource(const Stream& stream) : m_offset(0), m_stream(stream) {}
StreamCharSource(const StreamCharSource& source) StreamCharSource(const StreamCharSource& source) = default;
: m_offset(source.m_offset), m_stream(source.m_stream) {} StreamCharSource(StreamCharSource&&) YAML_CPP_NOEXCEPT = default;
StreamCharSource(StreamCharSource&&) = default;
StreamCharSource& operator=(const StreamCharSource&) = delete; StreamCharSource& operator=(const StreamCharSource&) = delete;
StreamCharSource& operator=(StreamCharSource&&) = delete; StreamCharSource& operator=(StreamCharSource&&) = delete;
~StreamCharSource() {} ~StreamCharSource() = default;
operator bool() const; operator bool() const;
char operator[](std::size_t i) const { return m_stream.CharAt(m_offset + i); } char operator[](std::size_t i) const { return m_stream.CharAt(m_offset + i); }
@@ -38,7 +40,7 @@ inline StreamCharSource::operator bool() const {
inline const StreamCharSource StreamCharSource::operator+(int i) const { inline const StreamCharSource StreamCharSource::operator+(int i) const {
StreamCharSource source(*this); StreamCharSource source(*this);
if (static_cast<int>(source.m_offset) + i >= 0) if (static_cast<int>(source.m_offset) + i >= 0)
source.m_offset += i; source.m_offset += static_cast<std::size_t>(i);
else else
source.m_offset = 0; source.m_offset = 0;
return source; return source;

View File

@@ -29,7 +29,7 @@ Tag::Tag(const Token& token)
} }
} }
const std::string Tag::Translate(const Directives& directives) { std::string Tag::Translate(const Directives& directives) {
switch (type) { switch (type) {
case VERBATIM: case VERBATIM:
return value; return value;

View File

@@ -23,7 +23,7 @@ struct Tag {
}; };
Tag(const Token& token); Tag(const Token& token);
const std::string Translate(const Directives& directives); std::string Translate(const Directives& directives);
TYPE type; TYPE type;
std::string handle, value; std::string handle, value;

Some files were not shown because too many files have changed in this diff Show More