Merge branch 'v3'

This commit is contained in:
Mark Gillard 2022-01-11 18:23:04 +02:00
commit 5c5abfd8e9
177 changed files with 29793 additions and 20075 deletions

View File

@ -4,7 +4,7 @@ jobs:
debug_clang:
docker:
- image: marzer/cpp_dev:0.1.0
- image: marzer/cpp_dev:0.2.0
resource_class: large
steps:
- checkout
@ -23,12 +23,13 @@ jobs:
- run:
name: Building and testing with clang
command: |
CXX_LD=lld CXX=clang++ meson build --buildtype=debug -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false
update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-13 130
CXX_LD=lld CXX=clang++ meson build --buildtype=debug -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false -Dasan_examples=true
cd build && meson compile -j 4 && meson test --num-processes 1 --verbose
release_clang:
docker:
- image: marzer/cpp_dev:0.1.0
- image: marzer/cpp_dev:0.2.0
resource_class: large
steps:
- checkout
@ -39,12 +40,13 @@ jobs:
- run:
name: Building and testing with clang
command: |
CXX_LD=lld CXX=clang++ meson build --buildtype=release -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false
update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-13 130
CXX_LD=lld CXX=clang++ meson build --buildtype=release -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false -Dasan_examples=true
cd build && meson compile -j 4 && meson test --num-processes 1 --verbose
debug_gcc:
docker:
- image: marzer/cpp_dev:0.1.0
- image: marzer/cpp_dev:0.2.0
resource_class: large
steps:
- checkout
@ -55,12 +57,13 @@ jobs:
- run:
name: Building and testing with gcc
command: |
update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-13 130
CXX_LD=lld CXX=g++ meson build --buildtype=debug -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false
cd build && meson compile -j 4 && meson test --num-processes 1 --verbose
release_gcc:
docker:
- image: marzer/cpp_dev:0.1.0
- image: marzer/cpp_dev:0.2.0
resource_class: large
steps:
- checkout
@ -71,12 +74,13 @@ jobs:
- run:
name: Building and testing with gcc
command: |
update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-13 130
CXX_LD=lld CXX=g++ meson build --buildtype=release -Dpedantic=true -Dbuild_tests=true -Dbuild_examples=true -Dgenerate_cmake_config=false -Db_lto=false
cd build && meson compile -j 4 && meson test --num-processes 1 --verbose
generate_dox:
docker:
- image: marzer/cpp_dev:0.1.0
- image: marzer/cpp_dev:0.2.0
resource_class: small
steps:
- checkout

View File

@ -25,8 +25,15 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- TOML_ABSTRACT_BASE
- TOML_CLOSED_ENUM
- TOML_CLOSED_FLAGS_ENUM
- TOML_EMPTY_BASES
- TOML_FLAGS_ENUM
- TOML_LIKELY_CASE
- TOML_OPEN_ENUM
- TOML_OPEN_FLAGS_ENUM
- TOML_TRIVIAL_ABI
- TOML_UNLIKELY_CASE
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
@ -96,7 +103,7 @@ IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentPPDirectives: None
IndentExternBlock: Indent
IndentRequires: false
IndentWidth: 4
@ -124,6 +131,7 @@ PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
ReferenceAlignment: Left
ReflowComments: true
SortIncludes: false
SortJavaStaticImport: Before
@ -155,13 +163,17 @@ StatementMacros:
- TOML_ALWAYS_INLINE
- TOML_API
- TOML_ATTR
- TOML_CONSTEVAL
- TOML_CONST_GETTER
- TOML_CONST_INLINE_GETTER
- TOML_EXTERN
- TOML_EXTERNAL_LINKAGE
- TOML_INTERNAL_LINKAGE
- TOML_MEMBER_ATTR
- TOML_NEVER_INLINE
- TOML_NODISCARD
- TOML_NODISCARD_CTOR
- TOML_PURE_GETTER
- TOML_PURE_INLINE_GETTER
- TOML_RETURNS_BY_THROWING
TabWidth: 4
TypenameMacros:

1
.gitattributes vendored
View File

@ -1,5 +1,6 @@
* text=auto encoding=UTF-8
*.bat text eol=lf encoding=UTF-8
*.c text eol=lf encoding=UTF-8
*.cpp text eol=lf encoding=UTF-8
*.css text eol=lf encoding=UTF-8

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "external/tloptional"]
path = external/tloptional
url = https://github.com/TartanLlama/optional.git
[submodule "external/json"]
path = external/json
url = https://github.com/nlohmann/json.git

517
CHANGELOG.md Normal file
View File

@ -0,0 +1,517 @@
# Changelog
<!--
template:
## [vX.X.X](https://github.com/marzer/tomlplusplus/releases/tag/vX.X.X) - YYYY-MM-DD
#### Fixes:
#### Additions:
#### Changes:
#### Removals:
#### Build system:
-->
## [v3.0.0](https://github.com/marzer/tomlplusplus/releases/tag/v3.0.0) - 2022-01-11
This release will be a major version bump, so it's ABI breaks all around.
Any changes that are likely to cause migration issues (API changes, build system breakage, etc.) are indicated with ⚠&#xFE0F;.
#### Fixes:
- ⚠&#xFE0F; fixed `toml::table` init-list constructor requiring double-brackets
- ⚠&#xFE0F; fixed `TOML_API` + extern templates causing linker errors in some circumstances
- ⚠&#xFE0F; fixed incorrect `noexcept` specifications on many functions
- ⚠&#xFE0F; fixed missing `TOML_API` on some interfaces
- fixed `toml::json_formatter` not formatting inf and nan incorrectly
- fixed a number of spec conformance issues (#127, #128, #129, #130, #131, #132, #135) (@moorereason)
- fixed an illegal table redefinition edge case (#112) (@python36)
- fixed documentation issues
- fixed GCC bug causing memory leak during parse failures (#123, #124) (@rsmmr, @ronalabraham)
- fixed incorrect handling of vertical whitespace in keys when printing TOML to streams
- fixed incorrect source position in redefinition error messages
- fixed missing includes `<initializer_list>`, `<utility>`
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
- fixed some incorrect unicode scalar sequence transformations (#125)
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
#### Additions:
- added value flags to array + table insert methods (#44) (@levicki)
- added support for Unicode 14.0
- added support for ref categories and cv-qualifiers in `toml::node::ref()`
- added magic `toml::value_flags` constant `toml::preserve_source_value_flags`
- added clang's enum annotation attributes to all enums
- added `TOML_ENABLE_FORMATTERS` option
- added `toml::yaml_formatter`
- added `toml::value` copy+move constructor overloads with flags override
- added `toml::table::prune()`
- added `toml::table::lower_bound()` (same semantics as `std::map::lower_bound()`)
- added `toml::table::emplace_hint()` (same semantics as `std::map::emplace_hint()`)
- added `toml::table::at()` (same semantics as `std::map::at()`)
- added `toml::node_view::operator==`
- added `toml::key` - provides a facility to access the source_regions of parsed keys (#82) (@vaartis)
- added `toml::is_key<>` and toml::is_key_or_convertible<>` metafunctions
- added `toml::format_flags::relaxed_float_precision` (#89) (@vaartis)
- added `toml::format_flags::quote_infinities_and_nans`
- added `toml::format_flags::indent_sub_tables` (#120) (@W4RH4WK)
- added `toml::format_flags::indent_array_elements` (#120) (@W4RH4WK)
- added `toml::format_flags::allow_unicode_strings`
- added `toml::format_flags::allow_real_tabs_in_strings`
- added `toml::format_flags::allow_octal_integers`
- added `toml::format_flags::allow_hexadecimal_integers`
- added `toml::format_flags::allow_binary_integers`
- added `toml::date_time` converting constructors from `toml::date` and `toml::time`
- added `toml::at_path()`, `toml::node::at_path()` and `toml::node_view::at_path()` for qualified path-based lookups (#118) (@ben-crowhurst)
- added `toml::array::resize()` param `default_init_flags`
- added `toml::array::replace()` (#109) (@LebJe)
- added `toml::array::prune()`
- added `toml::array::at()` (same semantics as `std::vector::at()`)
- added `parse_benchmark` example
- added `operator->` to `toml::value` for class types
#### Changes:
- ⚠&#xFE0F; `toml::format_flags` is now backed by `uint64_t` (was previously `uint8_t`)
- ⚠&#xFE0F; `toml::source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`)
- ⚠&#xFE0F; `toml::table` now uses `toml::key` as the key type (was previously `std::string`)
- ⚠&#xFE0F; `toml::value_flags` is now backed by `uint16_t` (was previously `uint8_t`)
- ⚠&#xFE0F; made all overloaded operators 'hidden friends' where possible
- ⚠&#xFE0F; renamed `toml::default_formatter` to `toml::toml_formatter` (`toml::default_formatter` is now an alias)
- ⚠&#xFE0F; renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated)
- ⚠&#xFE0F; renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated)
- ⚠&#xFE0F; renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated)
- applied clang-format to all the things 🎉&#xFE0F;
- exposed `TOML_NAMESPACE_START` and `TOML_NAMESPACE_END` macros to help with ADL specialization scenarios
- improved performance of parser
- made date/time constructors accept any integral types
- moved all implementation headers to `/impl`
- renamed all implementation headers to `.h` and 'source' headers to `.inl`
- updated conformance tests
#### Removals:
- ⚠&#xFE0F; removed `toml::format_flags::allow_value_format_flags`
- ⚠&#xFE0F; removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_LARGE_FILES` to `0` will invoke an `#error`)
- ⚠&#xFE0F; removed unnecessary template machinery (esp. where ostreams were involved)
- removed unnecessary uses of `final`
#### Build system:
- ⚠&#xFE0F; increased minimum required meson version to `0.54.0`
- disabled 'install' path when being used as a meson subproject (#114) (@Tachi107)
- fixed builds failing with meson 0.6.0 (#117) (@Tachi107)
- general meson improvements and fixes (#115) (@Tachi107)
- used `override_dependency` where supported (#116) (@Tachi107)
## [v2.5.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.5.0) - 2021-07-11
#### Fixes:
- fixed linkage error with windows compat mode
- fixed `TOML_CONSTEVAL` broken in MSVC (again)
- fixed minor documentation bugs
- fixed cmake project version being incorrect (#110) (@GiulioRomualdi)
#### Additions:
- added support for lowercase 't' and 'z' in datetimes (per spec)
- added natvis file to cmake install (#106) (@Ryan-rsm-McKenzie)
- added VS cpp.hint file to cmake install
- added metafunctions `is_container`, `is_chronological`, `is_value`, `is_node`, `inserted_type_of`
#### Changes:
- improved debug code size by removing unnecessary std::forwards and std::moves
- modernized the CMake build files (#102, #103, #105) (@friendlyanon)
- updated conformance tests
## [v2.4.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.4.0) - 2021-05-19
#### Fixes:
- fixed `node::value()` not retrieving inf and nan correctly
- fixed dotted kvps being unable to add subtables (#61) (@Validark)
- fixed linker error on linux ICC (#83) (@blackwer)
- fixed segfault JSON-formatting a failed `parse_result` (#96) (@proydakov)
- fixed spurious newline after JSON formatting a table
- fixed VS intellisense not detecting `TOML_COMPILER_EXCEPTIONS` correctly
- fixed crash with pathologically-nested inputs (#100) (@geeknik)
- fixed `parse_result` natvis
- fixed false-positive `char8_t` support detection on older compilers
- fixed unnecessary `#include <Windows.h>` Windows builds (@BeastLe9enD)
- fixed `TOML_CONSTEVAL` breaking on VS 16.10.0pre2
- fixed spurious warnings with MSVC /Wall
- fixed missing blank lines between consecutive empty tables/A-o-T
- fixed unnecessary `TOML_API` declarations
- fixed many small documentation issues
#### Additions:
- added proper cmake support (#85) (@ClausKlein)
- added cmake FetchContent information to documentation (#101) (@proydakov)
#### Removals:
- removed explicit `#include <fstream>` requirement for `parse_file()`
## [v2.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.3.0) - 2020-12-29
#### Fixes:
- fixed compiler errors caused by `<charconv>` with Apple-flavoured clang
- fixed array and table iterators missing `iterator_category` (#77) (@HazardyKnusperkeks)
- fixed `Wuseless-cast` warnings on GCC 10 (#75) (@HazardyKnusperkeks)
- fixed formatter not correctly line wrapping in some rare circumstances (#73) (@89z)
- fixed an unnecessary global compiler flag breaking builds when used as a meson subproject (#72) (@jamabr)
- fixed link error caused by `<charconv>` on emscripten (#71) (@suy)
- fixed ambiguity with the `toml::literals` inline namespace (#69) (@std-any-emplace)
- fixed formatter emitting superfluous newlines after printing tables (#68) (@std-any-emplace)
- fixed array and table iterators not converting between const and non-const versions of themselves (#67) (@std-any-emplace)
- fixed some parser crashes when given pathologically-malformed UTF-8 (#65) (@sneves)
## [v2.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.2.0) - 2020-08-09
#### Fixes:
- fixed some issues building with VS2017 (#55) (@sobczyk)
- fixed `_Float16` erroneously detected as supported on g++ (#57) (@sobczyk)
- fixed `<Windows.h>` causing compilation failure on mingw (#63) (@rezahousseini)
- fixed CMake and pkg-config files not being installed into architecture-agnostic directories (#59) (@tambry)
- fixed memory leak during parsing (#64) (@sneves)
- fixed ambiguous `operator==` error on MSVC (#56) (@HellsingDarge)
#### Additions:
- added additional node_view constructors
- added ability to specify serialization format of integer values
- added integer value serialization format round trip (e.g. hex in, hex out)
#### Changes:
- updated conformance tests
- TOML version bump to v1.0.0-rc.3
- refactors and cleanups based on feedback given [here](https://medium.com/@julienjorge/code-review-of-toml-f816a6071120)
#### Build system:
- renamed build options to `snake_case`
- tests, examples and cmake config now explicitly disabled when used as a subproject
- removed small_binaries (it's now implicit when building as release)
- bumped minimum meson version to 0.53
## [v2.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.1.0) - 2020-07-11
#### Fixes:
- fixed inconsistent emission of leading/trailing newlines when writing a table to an ostream (#48) (@levicki)
- fixed `Wcast-align` warning spam on ARM
- fixed `array::insert` not working correctly in some cases
- fixed `node::value_or()` not having the same semantics as `node::value()` (#50) (@whiterabbit963)
- fixed 'misleading assignment' of rvalue node_views (#52) (@Reedbeta)
- fixed some issues handling infinities and NaNs (#51) (@Reedbeta)
- fixed some minor documentation issues
#### Additions:
- added support for `__fp16`, `_Float16`, `__float128`, `__int128_t` and `__uint128_t`
- added copy construction/assignment for arrays, tables and values
- added insert, emplace, push_back etc. compatibility with node_views
- added `node::is_homogenous`
- added `table::is_homogenous`
- added `value::is_homogenous` (just for generic code's sake)
- added `is_homogenous` overload for identifying failure-causing element
- added implicit conversion operator from `node` to `node_view` (#52) (@Reedbeta)
#### Changes:
- renamed `TOML_ALL_INLINE` to `TOML_HEADER_ONLY` (the old name will still work, but is no longer documented)
- general cleanup
## [v2.0.0](https://github.com/marzer/tomlplusplus/releases/tag/v2.0.0) - 2020-07-20
This release contains a fairly significant number of 'quality of life' improvements, yay! But also necessitates an ABI
break (hence the version number bump). Changes that might block a migration are annotated with ⚠&#xFE0F;.
#### Fixes:
- fixed infinity and NaN-related code breaking when using `-ffast-math` and friends
- fixed narrowing conversion warnings when constructing int values from unsigned
- fixed Visual Studio debugger native visualizations for `date`, `time`, `time_offset`, `date_time`
- fixed some static assert messages being badly formatted on clang
- fixed internal macro `assert_or_assume` leaking out of `toml_parser.hpp`
#### Additions:
- added additional types allowed in `node::value()` and `node::value_or()` ([see `value()` dox for examples](https://marzer.github.io/tomlplusplus/classtoml_1_1node.html#ab144c1ae90338b6b03f6af0574c87993))
- added additional types allowed in `node_view::value()` and `node_view::value_or()`
- added `node::value_exact()` and `node_view::value_exact()`
- added support for interop with wide strings on Windows:
- added wide-string path arg overloads of `parse()` and `parse_file()`
- added wide-string support to all relevant `table` and `array` ops
- added wide-string support to `node::value(), node::value_or()`
- added wide-string support to `node_view::value(), node_view::value_or()`
- added wide-string support to `value<string>` constructor
- added wide-string overloads of `node_view::operator[]`
- added `source_region::wide_path()`
- added `TOML_WINDOWS_COMPAT` switch for explicitly enabling/disabling this stuff
- added emission of 'literal' strings to the TOML serializer
- added lots of minor documentation fixes and improvements
- added Visual Studio debugger native visualizations for `table`, `array`, `parse_result`, and `parse_error` (#46) (@Reedbeta)
- added non-template version of `array::is_homogeneous()`
- added explicit instantiations of more template types when `!TOML_ALL_INLINE`
#### Changes:
- ⚠&#xFE0F; deprecated `parse_result::get()` in favour of `parse_result::table()`
- ⚠&#xFE0F; deprecated `node_view::get()` in favour of `node_view::node()`
- ⚠&#xFE0F; simplified internal ABI namespaces
- improved the quality of many static_assert error messages
#### Removals:
- ⚠&#xFE0F; renamed `date_time::time_offset` to just 'offset'
- ⚠&#xFE0F; removed `TOML_CHAR_8_STRINGS` since it no longer makes sense
## [v1.3.3](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.3) - 2020-06-29
#### Fixes:
- fixed some minor TOML spec conformance bugs
- fixed BOM check causing EOF on very short iostream inputs
- fixed `std::numeric_limits::max()` getting broken by macros in some environments
- fixed 'unknown pragma' warning spam in older versions of GCC
- fixed a few minor documentation issues
#### Additions:
- added rvalue overload of `array::flatten`
- added conformance tests from `BurntSushi/toml-test` and `iarna/toml-spec-tests`
- added `toml::inserter` as a workaround for nested construction of single-element `toml::arrays` performing move-construction instead
- added license boilerplate to test files
#### Changes:
- refactored the parser to reduce binary size
## [v1.3.2](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.2) - 2020-06-19
#### Fixes:
- fixed single-digit negative integers parsing as positive
- fixed parse failure when parsing an empty file
- fixed multi-line strings being allowed in keys
- fixed overflow for very long binary integer literals
#### Changes:
- improved the performance of toml::parse_file
- improved the performance of printing to streams for deepy-nested TOML data
## [v1.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.3.0) - 2020-06-02
#### Fixes:
- fixed `formatter::print_inline()` causing compilation failures in DLL builds
- fixed BOMs occasionally causing overflow/crash in char8 mode
- fixed some spurious warnings in GCC 10
- fixed clang static analyzer warning in BOM handling code
#### Additions:
- added `table_iterator::operator ->`
- added `array::resize()` and `array::truncate()`
- added `array::capacity()`, `array::shrink_to_fit()`, `array::max_size()`
- added non-const -> const conversion for table and array iterators
#### Changes:
- renamed table iterator proxy pair members to `first` and `second` to match STL
## [v1.2.5](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.5) - 2020-04-24
#### Fixes:
- fixed some multi-line string parsing issues
- fixed pedantic warnings on gcc 10 and clang 11
- fixed `is_unicode_XXXXXX` functions being wrong in some cases
- fixed `TOML_LIKELY` not being correct on older versions of gcc and clang
- fixed minor documentation issues (#26, #38) (@prince-chrismc)
#### Additions:
- added additional error message cases to the parser
- added `error_printer` example
- added `toml_generator` example
#### Changes:
- improved unicode-related codegen
## [v1.2.3](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.3) - 2020-04-11
#### Fixes:
- fixed printing of inf and nan
- fixed parser not handling floats with leading '.' characters
- fixed pedantic vtable warnings on clang with -Weverything
- fixed a number of documentation bugs
- fixed `TOML_UNRELEASED_FEATURES` default being 1 (it should have been 0)
#### Additions:
- added `TOML_PARSER` configuration option
- added `TOML_LIB_SINGLE_HEADER` indicator
- added doxygen page for the configuration options
- added SPDX-License-Identifiers around the place
#### Changes:
- split some header files up to make future maintenance easier
- refactored and greatly simplified parser
## [v1.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.2.0) - 2020-04-07
#### Fixes:
- fixed some parsing and printing ops being locale-dependent
- fixed some parsing errors at EOF when `TOML_EXCEPTIONS = 0`
- fixed some unreferenced variable warnings on older compilers
- fixed some 'maybe-uninitialized' false-positives on GCC9
- fixed pkgconfig subdir being wrong
#### Additions:
- added support for implementations without `<charconv>`
- added cmake package config generator (#22) (@GiulioRomualdi)
- added build config feature option `GENERATE_CMAKE_CONFIG`
- added many new tests
## [v1.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v1.1.0) - 2020-04-03
#### Fixes:
- fixed some parser error paths not returning early enough `TOML_EXCEPTIONS=0`
- fixed a number of minor documentation issues
#### Additions:
- added support for [TOML 1.0.0-rc.1](https://github.com/toml-lang/toml/releases/tag/v1.0.0-rc.1) 🎉
- added `operator[]`, `begin()`, `end()` to `toml::parse_result` for `TOML_EXCEPTIONS=0`
- added additional compilation speed improvements for `TOML_ALL_INLINE=0`
- added more specific error messages for parsing errors relating to prohibited codepoints
- added a large number of additional tests
- added support for installation with meson (#16) (@ximion)
- added the array and table iterators to the `toml` namespace
## [v1.0.0](https://github.com/marzer/tomlplusplus/releases/tag/1.0.0) - 2020-03-28
#### Fixes:
- fixed minor documentation issues
#### Changes:
- refactoring of ABI-based inline namespaces
## [v0.6.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.6.0) - 2020-03-24
#### Fixes:
- fixed minor preprocessor/macro issues
- fixed minor documentation issues
#### Additions:
- added `<cassert>` include directly in 'debug' builds when `TOML_ASSERT` isn't defined
- added Clang's `[[trivial_abi]]` attribute to `date`, `time`, `time_offset`
## [v0.5.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.5.0) - 2020-03-18
#### Fixes:
- fixed crash when reaching EOF while parsing a string when exceptions are disabled
- fixed some attribute warnings in GCC
- fixed build with GCC 8.2.0 (#15) (@shdnx)
- fixed exception mode detection sometimes being incorrect on MSVC
- fixed compilation on older implementations without `std::launder`
- fixed `json_formatter` type deduction on older compilers
#### Additions:
- added support for Unicode 13.0
- added support for `\xHH` escape sequences ([toml/pull/796](https://github.com/toml-lang/toml/pull/796))
- added short-form license preamble to all source files
- added build configuration option for compiling examples
## [v0.4.3](https://github.com/marzer/tomlplusplus/releases/tag/v0.4.3) - 2020-03-10
#### Fixes:
- fixed ICE in VS2019 when using `/std:c++17` instead of `/std:c++latest
#### Additions:
- added `#error` when `TOML_EXCEPTIONS` is set to `1` but compiler exceptions were disabled
#### Changes:
- parsing performance improvements
## [v0.4.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.4.0) - 2020-03-05
#### Fixes:
- fixed `parse_file()` failing to compile with plain string literals
- fixed tests being built when used as a meson subproject (#14) (@shdnx)
#### Additions:
- added support for compiling into DLLs on windows (`TOML_API`)
- added support for explicitly setting the `TOML_EXCEPTION` mode
- added `TOML_OPTIONAL_TYPE` customization point
- added `node::ref()` and `node_view::ref()`
## [v0.3.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.3.0) - 2020-03-01
#### Fixes:
- fixed some pedantic clang warnings
- fixed some minor documentation errors
#### Additions:
- added `node::value()` and `node::value_or()`
- added `node_view::value()`
- added relops for the date/time classes
- added `TOML_ALL_INLINE` and `TOML_IMPLEMENTATION` options
- added preliminary support for ICC
#### Removals:
- removed `<cmath>` dependency
## [v0.2.1](https://github.com/marzer/tomlplusplus/releases/tag/v0.2.1) - 2020-02-26
#### Fixes:
- fixed minor printing bug in `operator<<(ostream, source_position)`
- fixed minor documentation issues
#### Additions:
- added `operator<<(ostream&, parse_error)`
#### Changes:
- improved quality of error messages for boolean and inf/nan parsing
## [v0.2.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.2.0) - 2020-02-23
#### Fixes:
- fixed truncation of floating-point values when using ostreams
- fixed missing value deduction guides for dates and times
- fixed potential ODR issues relating to exception mode handling etc.
- fixed some documentation issues
#### Additions:
- added serialization round-trip tests
- added `node::is_number()`
- added `node_view::is_number()`
- added `node_view::value_or()`
- added hexfloat parsing support for all implementations (not just `<charconv>` ones)
## [v0.1.0](https://github.com/marzer/tomlplusplus/releases/tag/v0.1.0) - 2020-02-20
- First public release, yay! 🎉&#xFE0F;

View File

@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.14)
project(
tomlplusplus
VERSION 2.6.0
DESCRIPTION "Header-only TOML config file parser and serializer for C++17 (and later!)"
VERSION 3.0.0
DESCRIPTION "Header-only TOML config file parser and serializer for C++17"
HOMEPAGE_URL "https://marzer.github.io/tomlplusplus/"
LANGUAGES CXX
)

View File

@ -3,8 +3,10 @@ Contributions are very welcome! Either by [reporting issues] or submitting pull
If you wish to submit a PR, please be aware that:
- The single-header file `toml.hpp` is generated by a script; make your changes in the files in
`include`, **not** in `toml.hpp`.
- Your changes should compile warning-free on at least one of gcc 8.3.0, clang 8.0, and MSVC 19.2X
(Visual Studio 2019). All three is a bonus.
- Your changes should compile warning-free on at least one of:
- GCC 8 or higher
- Clang 8 or higher
- MSVC 19.2X (Visual Studio 2019) or higher
- You should regenerate the single-header file as part of your PR (a CI check will fail if you don't).
<br>
@ -27,7 +29,7 @@ git submodule update --init --depth 1 external/Catch2 external/tloptional
### Testing on Windows with Visual Studio
Install [Visual Studio 2019] and [Test Adapter for Catch2], then open `vs/toml++.sln` and build the
Install [Visual Studio] and [Test Adapter for Catch2], then open `toml++.sln` and build the
projects in the `tests` solution folder. Visual Studio's Test Explorer should pick these up and
allow you to run the tests directly.
@ -62,10 +64,19 @@ cd build-gcc-debug && ninja && ninja test \
&& cd ..
```
<br>
[Visual Studio 2019]: https://visualstudio.microsoft.com/vs/
## Testing with the [toml-test] suite
As an optional extra you may wish to test against the 'official' test TOML test suite, [BurntSushi/toml-test]. See the
instructions at [toml-test/README](./toml-test/README.md). Note that the toml++ tests already consume tests from the
offical suite via a C++ code-generation script so you are not expected to take this extra step as part of contributing
to the library.
[Visual Studio]: https://visualstudio.microsoft.com/vs/
[Test Adapter for Catch2]: https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01
[reporting issues]: https://github.com/marzer/tomlplusplus/issues
[Catch2]: https://github.com/catchorg/Catch2
[meson]: https://mesonbuild.com/Getting-meson.html
[ninja]: https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages
[toml-test]: https://github.com/BurntSushi/toml-test
[BurntSushi/toml-test]: https://github.com/BurntSushi/toml-test

View File

@ -24,8 +24,8 @@
- Proper UTF-8 handling (incl. BOM)
- Works with or without exceptions
- Doesn't require RTTI
- First-class support for serializing to JSON
- Tested on Clang (6+), GCC (7+) and MSVC (VS2019)
- Support for serializing to JSON and YAML
- Tested on Clang (6+), GCC (7+) and MSVC (VS2019, VS2022)
- Tested on x64, x86 and ARM
<br>
@ -79,6 +79,8 @@ std::cout << config << "\n";
// re-serialize as JSON
std::cout << toml::json_formatter{ config } << "\n";
// re-serialize as YAML
std::cout << toml::yaml_formatter{ config } << "\n";
```
You'll find some more code examples in the `examples` directory, and plenty more as part of the [API documentation].
@ -97,13 +99,13 @@ You'll find some more code examples in the `examples` directory, and plenty more
2. `#include <toml++/toml.h>`
### Conan
Add `tomlplusplus/2.5.0` to your conanfile.
Add `tomlplusplus/3.0.0` to your conanfile.
### DDS
Add `tomlpp` to your `package.json5`, e.g.:
```
depends: [
'tomlpp^2.5.0',
'tomlpp^3.0.0',
]
```
> &#xFE0F; _[What is DDS?](https://dds.pizza/)_
@ -119,7 +121,7 @@ include(FetchContent)
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v2.5.0
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(tomlplusplus)
```
@ -130,27 +132,32 @@ FetchContent_MakeAvailable(tomlplusplus)
in the C++ ecosystem. I'm also a cmake novice, for better or worse. If there's an integration option missing be
assured that I fully support it being added, and welcome [pull requests](./CONTRIBUTING.md)!
### What about dependencies?
If you just want to consume `toml++` as a regular library then you don't have any dependencies to worry about.
There's a few test-related dependencies to be aware of if you're working on the library, though.
See [CONTRIBUTING] for information.
<br>
# Configuration
A number of configurable options are exposed in the form of preprocessor `#defines`. Most likely you
A number of configurable options are exposed in the form of preprocessor `#defines` Most likely you
won't need to mess with these at all, but if you do, set them before including toml++.
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|----------------------------------------------------------------------------------------------------------------------|
| `TOML_HEADER_ONLY` | boolean | `1` | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). |
| `TOML_API` | define | undefined | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). |
| `TOML_ASSERT(expr)` | function macro | `assert(expr)`<br>(or undefined) | Sets the assert function used by the library. |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_EXCEPTIONS` | boolean | per your compiler's settings | Sets whether the library uses exceptions. |
| `TOML_IMPLEMENTATION` | define | undefined | Define this to enable compilation of the library's implementation. Meaningless if `TOML_HEADER_ONLY` is `1`. |
| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). |
| `TOML_OPTIONAL_TYPE` | type name | undefined | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. |
| `TOML_PARSER` | boolean | `1` | Disable this to prevent inclusion of the parser-related parts of the library if you don't need them. |
| `TOML_SMALL_FLOAT_TYPE` | type name | undefined | If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
| `TOML_UNRELEASED_FEATURES` | boolean | `0` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
| `TOML_WINDOWS_COMPAT` | boolean | `1` on Windows | Enables support for transparent conversion between wide and narrow strings in some places when building for Windows. |
| Option | Type | Description | Default |
|-----------------------------------|:--------------:|----------------------------------------------------------------------------------------------------------|------------------------|
| `TOML_API` | define | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). | undefined |
| `TOML_ASSERT(expr)` | function macro | Sets the assert function used by the library. | `assert()` |
| `TOML_CONFIG_HEADER` | string literal | Includes the given header file before the rest of the library. | undefined |
| `TOML_ENABLE_FORMATTERS` | boolean | Enables the formatters. Set to `0` if you don't need them to improve compile times and binary size. | `1` |
| `TOML_ENABLE_PARSER` | boolean | Enables the parser. Set to `0` if you don't need it to improve compile times and binary size. | `1` |
| `TOML_ENABLE_UNRELEASED_FEATURES` | boolean | Enables support for [unreleased TOML language features]. | `0` |
| `TOML_ENABLE_WINDOWS_COMPAT` | boolean | Enables support for transparent conversion between wide and narrow strings. | `1` on Windows |
| `TOML_EXCEPTIONS` | boolean | Sets whether the library uses exceptions. | per compiler settings |
| `TOML_HEADER_ONLY` | boolean | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library).| `1` |
| `TOML_IMPLEMENTATION` | define | Define this to enable compilation of the library's implementation when `TOML_HEADER_ONLY` == `0`. | undefined |
| `TOML_OPTIONAL_TYPE` | type name | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. | undefined |
| `TOML_SMALL_FLOAT_TYPE` | type name | If your codebase has a custom 'small float' type (e.g. half-precision), this tells toml++ about it. | undefined |
| `TOML_SMALL_INT_TYPE` | type name | If your codebase has a custom 'small integer' type (e.g. 24-bits), this tells toml++ about it. | undefined |
> &#xFE0F; _A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally
linking incompatible combinations together._
@ -165,15 +172,15 @@ support for a number of unreleased features from the [TOML master] and some sane
The library advertises the most recent numbered language version it fully supports via the preprocessor
defines `TOML_LANG_MAJOR`, `TOML_LANG_MINOR` and `TOML_LANG_PATCH`.
### 🔸&#xFE0F; **Unreleased language features:**
### **Unreleased language features:**
- [#516]: Allow newlines and trailing commas in inline tables
- [#562]: Allow hex floating-point values
- [#644]: Support `+` in key names
- [#671]: Local time of day format should support `09:30` as opposed to `09:30:00`
- [#687]: Relax bare key restrictions to allow additional unicode characters
- [#709]: Include an \xHH escape code sequence
- [#796]: Include an \xHH escape code sequence
> &#xFE0F; _`#define TOML_UNRELEASED_FEATURES 1` to enable these features (see [Configuration](#Configuration))._
> &#xFE0F; _`#define TOML_ENABLE_UNRELEASED_FEATURES 1` to enable these features (see [Configuration](#Configuration))._
### 🔹&#xFE0F; **TOML v1.0.0:**
All features supported, including:
@ -206,6 +213,7 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[
- **[@bobfang1992](https://github.com/bobfang1992)** - Reported a bug and created a [wrapper in python](https://github.com/bobfang1992/pytomlpp)
- **[@GiulioRomualdi](https://github.com/GiulioRomualdi)** - Added cmake+meson support
- **[@levicki](https://github.com/levicki)** - Helped design some new features
- **[@moorereason](https://github.com/moorereason)** - Reported a whole bunch of bugs
- **[@mosra](https://github.com/mosra)** - Created the awesome [m.css] used to generate the API docs
- **[@ned14](https://github.com/ned14)** - Reported a bunch of bugs and helped design some new features
- **[@okureta](https://github.com/okureta)** - Reported a bug
@ -214,13 +222,13 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[
- **[@Reedbeta](https://github.com/Reedbeta)** - Fixed a bug and added additional Visual Studio debugger native visualizers
- **[@Ryan-rsm-McKenzie](https://github.com/Ryan-rsm-McKenzie)** - Add natvis file to cmake install script
- **[@shdnx](https://github.com/shdnx)** - Fixed a bug on GCC 8.2.0 and some meson config issues
- **[@sobczyk](https://github.com/sobczyk)** - Reported some bugs
- **[@sneves](https://github.com/sneves)** - Helped fix a number of parser bugs
- **[@sobczyk](https://github.com/sobczyk)** - Reported some bugs
- **[@std-any-emplace](https://github.com/std-any-emplace)** - Reported some bugs
- **[@traversaro](https://github.com/traversaro)** - Added vcpkg support and reported a bunch of bugs
- **[@ximion](https://github.com/ximion)** - Added support for installation with meson
- **[@whiterabbit963](https://github.com/whiterabbit963)** - Fixed a bug with value_or conversions
- **[@Tachi107](https://github.com/Tachi107)** - Made some tweaks to meson.build
- **[@traversaro](https://github.com/traversaro)** - Added vcpkg support and reported a bunch of bugs
- **[@whiterabbit963](https://github.com/whiterabbit963)** - Fixed a bug with value_or conversions
- **[@ximion](https://github.com/ximion)** - Added support for installation with meson
<br>
@ -236,7 +244,7 @@ though you're welcome to reach out via other means. In order of likely response
[API documentation]: https://marzer.github.io/tomlplusplus/
[homepage]: https://marzer.github.io/tomlplusplus/
[unreleased TOML language features]: #-unreleased-language-features
[unreleased TOML language features]: #unreleased-language-features
[most recently-released version]: https://github.com/toml-lang/toml/releases
[numbered version]: https://github.com/toml-lang/toml/releases
[char8_t]: https://en.cppreference.com/w/cpp/keyword/char8_t
@ -261,8 +269,7 @@ though you're welcome to reach out via other means. In order of likely response
[#665]: https://github.com/toml-lang/toml/issues/665
[#671]: https://github.com/toml-lang/toml/issues/671
[#687]: https://github.com/toml-lang/toml/issues/687
[#709]: https://github.com/toml-lang/toml/pull/709
[#796]: https://github.com/toml-lang/toml/pull/796
[#766]: https://github.com/toml-lang/toml/issues/766
[LICENSE-utf8-decoder]: ./LICENSE-utf8-decoder
[something better than std::optional]: https://github.com/TartanLlama/optional
[m.css]: https://mcss.mosra.cz/documentation/doxygen

View File

@ -1,16 +1,37 @@
#define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true)
#define TOML_ABI_NAMESPACE_END static_assert(true)
#define TOML_ABSTRACT_BASE
#define TOML_ALWAYS_INLINE inline
#define TOML_ANON_NAMESPACE_END static_assert(true)
#define TOML_ANON_NAMESPACE_START namespace
#define TOML_API
#define TOML_ATTR(...)
#define TOML_ALWAYS_INLINE inline
#define TOML_NEVER_INLINE
#define TOML_TRIVIAL_ABI
#define TOML_ABSTRACT_BASE
#define TOML_CLOSED_ENUM
#define TOML_CLOSED_FLAGS_ENUM
#define TOML_CONST_GETTER
#define TOML_CONST_INLINE_GETTER inline
#define TOML_CONSTRAINED_TEMPLATE(cond, ...) template <__VA_ARGS__>
#define TOML_EMPTY_BASES
#define TOML_MAY_THROW
#define TOML_CONSTEVAL constexpr
#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__>
#define TOML_LIKELY(...) (__VA_ARGS__)
#define TOML_UNLIKELY(...) (__VA_ARGS__)
#define TOML_EXTERN
#define TOML_EXTERN_NOEXCEPT(...)
#define TOML_EXTERNAL_LINKAGE
#define TOML_FLAGS_ENUM
#define TOML_HIDDEN_CONSTRAINT(cond, ...) template <__VA_ARGS__>
#define TOML_IMPL_NAMESPACE_END static_assert(true)
#define TOML_IMPL_NAMESPACE_START namespace toml::impl
#define TOML_INTERNAL_LINKAGE static
#define TOML_LIKELY(...) (__VA_ARGS__)
#define TOML_NAMESPACE_END static_assert(true)
#define TOML_NAMESPACE_START namespace toml
#define TOML_NEVER_INLINE
#define TOML_NODISCARD
#define TOML_NODISCARD_CTOR
#define TOML_EXTERNAL_LINKAGE
#define TOML_INTERNAL_LINKAGE
#define TOML_OPEN_ENUM
#define TOML_OPEN_FLAGS_ENUM
#define TOML_PURE_GETTER
#define TOML_PURE_INLINE_GETTER inline
#define TOML_RETURNS_BY_THROWING
#define TOML_TRIVIAL_ABI
#define TOML_UNLIKELY(...) (__VA_ARGS__)
#define TOML_LIKELY_CASE
#define TOML_UNLIKELY_CASE

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -9,7 +9,7 @@
\section mainpage-features Features
- Supports the latest [TOML](https://toml.io/) release ([v1.0.0](https://toml.io/en/v1.0.0)), plus
optional support for some unreleased TOML features
- Supports serializing to JSON
- Supports serializing to JSON and YAML
- Proper UTF-8 handling (incl. BOM)
- C++17 (plus some C++20 features where available, e.g. experimental support for char8_t strings)
- Header-only (optional!)
@ -130,7 +130,7 @@
\subsection mainpage-example-parsing-without-exceptions Handling errors without exceptions
Can't (or won't) use exceptions? That's fine too. You can disable exceptions in your compiler flags and/or
explicitly disable the library's use of them by setting the option \ref TOML_EXCEPTIONS to `0`. In either case,
explicitly disable the library's use of them by setting the option #TOML_EXCEPTIONS to `0`. In either case,
the parsing functions return a toml::parse_result instead of a toml::table:
\cpp
@ -260,6 +260,10 @@
std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
// can also be retrieved via absolute path
std::cout << "cats: " << tbl.at_path("animals.cats") << "\n";
std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n";
// ...even if the element doesn't exist
std::cout << "dinosaurs: " << tbl["animals"]["dinosaurs"] << "\n"; //no dinosaurs :(
@ -278,6 +282,8 @@
numbers: [ 2, 3, 4, 'five', 6.0, 7, [ 8, 9 ] ]
cats: [ 'tiger', 'lion', 'puma' ]
fish[1]: 'trout'
cats: [ 'tiger', 'lion', 'puma' ]
fish[1]: 'trout'
dinosaurs:
\eout
@ -290,12 +296,12 @@
\subsection mainpage-example-serialization Serializing as TOML and JSON
\subsection mainpage-example-serialization Serializing as TOML, JSON and YAML
All toml++ data types have overloaded `operator<<` for ostreams, so 'serializing' a set of TOML data to actual
TOML is done just by printing it to an ostream. Converting it to JSON is done in the same way,
but via a toml::json_formatter.
TOML is done just by printing it to an ostream. Converting it to JSON and YAML is done in much the same way,
but via a toml::json_formatter and toml::yaml_formatter.
\godbolt{MMNoW4}
\godbolt{srdfoWMq6}
\cpp
#include <iostream>
@ -303,18 +309,18 @@
int main()
{
auto tbl = toml::table{{
auto tbl = toml::table{
{ "lib", "toml++" },
{ "cpp", toml::array{ 17, 20, "and beyond" } },
{ "toml", toml::array{ "1.0.0", "and beyond" } },
{ "repo", "https://github.com/marzer/tomlplusplus/" },
{ "author", toml::table{{
{ "author", toml::table{
{ "name", "Mark Gillard" },
{ "github", "https://github.com/marzer" },
{ "twitter", "https://twitter.com/marzer8789" }
}}
}
},
}};
};
// serializing as TOML
std::cout << "###### TOML ######" << "\n\n";
@ -323,6 +329,11 @@
// serializing as JSON using toml::json_formatter:
std::cout << "###### JSON ######" << "\n\n";
std::cout << toml::json_formatter{ tbl } << "\n\n";
// serializing as YAML using toml::yaml_formatter:
std::cout << "###### YAML ######" << "\n\n";
std::cout << toml::yaml_formatter{ tbl } << "\n\n";
return 0;
}
\ecpp
@ -360,10 +371,28 @@
"and beyond"
]
}
###### YAML ######
author:
github: 'https://github.com/marzer'
name: 'Mark Gillard'
twitter: 'https://twitter.com/marzer8789'
cpp:
- 17
- 20
- 'and beyond'
lib: toml++
repo: 'https://github.com/marzer/tomlplusplus/'
toml:
- '1.0.0'
- 'and beyond'
\eout
\see
- toml::default_formatter
- toml::toml_formatter
- toml::json_formatter
- toml::yaml_formatter
@ -373,7 +402,7 @@
a large number of translation units. You can counter this by disabling header-only mode and explicitly controlling
where the library's implementation is compiled.
<strong>Step 1: Set \ref TOML_HEADER_ONLY to [code]0[/code] before including toml++</strong>
<strong>Step 1: Set #TOML_HEADER_ONLY to [code]0[/code] before including toml++</strong>
This must be the same everywhere, so either set it as a global `#define` in your build system, or
do it manually before including toml++ in some global header that's used everywhere in your project:
@ -384,7 +413,7 @@
#include <toml.hpp>
\ecpp
<strong>Step 2: Define \ref TOML_IMPLEMENTATION before including toml++ in one specific translation unit</strong>
<strong>Step 2: Define #TOML_IMPLEMENTATION before including toml++ in one specific translation unit</strong>
\cpp
// some_code_file.cpp
@ -393,10 +422,11 @@
#include "global_header_that_includes_toml++.h"
\ecpp
<strong>Bonus Step: Disable the parser if you don't need it</strong>
<strong>Bonus Step: Disable any library features you don't need</strong>
If all you need to do is serialize some code-generated TOML and don't actually need the parser at all you can
set \ref TOML_PARSER to `0` to disable the parser altogether. This can yield fairly significant compilation
Some library features can be disabled wholesale so you can avoid paying their the compilation cost if you don't need them.
For example, if all you need to do is serialize some code-generated TOML and don't actually need the parser at all you, can
set #TOML_ENABLE_PARSER to `0` to disable the parser altogether. This can yield fairly significant compilation
speedups since the parser accounts for a good chunk of the library's code.
@ -427,7 +457,7 @@
\subsection mainpage-adding-lib-conan Conan
Add `tomlplusplus/2.5.0` to your conanfile.
Add `tomlplusplus/3.0.0` to your conanfile.
@ -435,7 +465,7 @@
Add `tomlpp` to your `package.json5`, e.g.:
\bash
depends: [
'tomlpp^2.5.0',
'tomlpp^3.0.0',
]
\ebash
@ -467,7 +497,7 @@
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v2.5.0
GIT_TAG v3.0.0
)
FetchContent_MakeAvailable(tomlplusplus)
\endcode
@ -490,10 +520,12 @@
\out
Parsing data.toml 5000 times:
pytomlpp: 0.662 s
toml: 5.277 s (7.9x slower)
qtoml: 8.020 s (12.1x slower)
tomlkit: 32.898 s (49.6x slower)
pytomlpp: 0.694 s
rtoml: 0.871 s ( 1.25x)
tomli: 2.625 s ( 3.78x)
toml: 5.642 s ( 8.12x)
qtoml: 7.760 s (11.17x)
tomlkit: 32.708 s (47.09x)
\eout
Install it using `pip`:

View File

@ -80,10 +80,18 @@ string_literals = [ '_toml' ]
[autolinks]
'(?:toml::)?parse[_ ]results?' = 'classtoml_1_1parse__result.html'
'(?:toml::)?parse[_ ]errors?' = 'classtoml_1_1parse__error.html'
'(?:toml::)?node[_ ]views?' = 'classtoml_1_1node__view.html'
'(?:toml::)?json[_ ]formatters?' = 'classtoml_1_1json__formatter.html'
'(?:toml::)?date[_-]times?' = 'structtoml_1_1date__time.html'
'(?:toml::)?default[_ ]formatters?' = 'classtoml_1_1default__formatter.html'
'(?:toml::)?json[_ ]formatters?' = 'classtoml_1_1json__formatter.html'
'(?:toml::)?node[_ ]views?' = 'classtoml_1_1node__view.html'
'(?:toml::)?parse[_ ]errors?' = 'classtoml_1_1parse__error.html'
'(?:toml::)?parse[_ ]results?' = 'classtoml_1_1parse__result.html'
'(?:toml::)?source[_ ]positions?' = 'structtoml_1_1source__position.html'
'(?:toml::)?source[_ ]regions?' = 'structtoml_1_1source__region.html'
'(?:toml::)?time[_ ]offsets?' = 'structtoml_1_1time__offset.html'
'(?:toml::)?toml[_ ]formatters?' = 'classtoml_1_1toml__formatter.html'
'(?:toml::)?yaml[_ ]formatters?' = 'classtoml_1_1yaml__formatter.html'
'toml::dates?' = 'structtoml_1_1date.html'
'toml::keys?' = 'classtoml_1_1key.html'
'toml::times?' = 'structtoml_1_1time.html'
'toml::values?' = 'classtoml_1_1value.html'

View File

@ -20,6 +20,7 @@ function(add_example name)
endfunction()
add_example(error_printer)
add_example(parse_benchmark)
add_example(simple_parser ARGS "${PROJECT_SOURCE_DIR}/example.toml")
add_example(toml_generator ARGS 100)
add_example(toml_to_json_transcoder ARGS "${PROJECT_SOURCE_DIR}/example.toml")

View File

@ -0,0 +1,94 @@
addition-used = false
afraid-boiling-draconian = 1916-12-15T11:26:42+11:26
boiling-whip = 12:23:17.000000129
charming = 16771
close-unbecoming = 14:49:02
contain-terrible-neck = 1928-11-07T06:30:56
creature = 0.4857
crowded-profuse-capable = 1932-05-28
deserted-cross-creature = 1931-12-26T04:31:04
deserted-heavy = [ 2014-02-08, 1984-03-16, 1910-08-05 ]
fabulous = 0.3388
ghost-birds-legal = 1989-09-02
grandfather-weary = 10216
haircut-dreary-broken = 'unadvised rejoice lewd crime grandfather rice imperfect'
harm-snow = 0.6724
leather-aromatic-rabbit = false
license-harm = 1987-08-15T15:30:51+03:24
naughty-self-close = 1916-09-21T01:53:27-02:59
neck = 29653
neck-crime-wistful = 1998-12-07
rest-afraid = [
1912-06-23T07:00:07-07:46,
1910-11-17T13:10:34,
2014-08-03T04:37:12-06:36,
1966-11-22T18:08:23+06:10,
1985-03-01T08:11:38,
1976-09-04T20:46:46+00:29,
1964-05-18T20:13:27-01:25,
1961-10-14T11:03:51.000011555+06:23,
2005-07-13T02:57:15-01:46,
2007-02-01T17:09:54-08:45,
1952-03-06T09:15:04+01:44,
1962-12-25T23:00:11+04:28
]
rotten-best = 0.0325
run-curious = true
run-meaty = 04:40:20.000003312
scintillating-cream = 0.2604
sisters-playground = 'week spiritual pause insidious uptight'
spiritual-borrow-messy = 16:49:32
surprise-jail-babies = 2008-01-01
title-unbiased = 1958-10-08
unbecoming-scene-lewd = true
worried-spicy = 23:03:54
[contain]
ghost = 0.2471
tank-lackadaisical = 1945-02-18T22:22:27+01:41
[contain.righteous-imperfect-remarkable]
ticket = 0.2412
voyage = 'prefer silky night draconian three dreary decisive'
wilderness-draconian = 04:58:17
[contain.righteous-imperfect-remarkable.deeply-night-gold]
legal = 1981-07-04
righteous = [ false, true, false, false, true ]
wilderness = 1900-12-24
[crime]
boiling-excuse-incandescent = 31173
flat-rejoice = 0.8682
furtive = 6866
heavy-memory = 5545
lackadaisical-terrible-overjoyed = [ 'harm acceptable naughty pause', 'page anxious threatening lewd' ]
reject-aromatic = [ false, true, true, true, false, true ]
reject-naughty = 11229
scintillating-bake-harm = 0.8258
[license-bat]
adorable-blind-string = 1961-08-14
bat = 1939-10-28
blind-wilderness = 2004-07-14
[rapid]
borrow = true
jail-weary-furtive = 'room'
protective-sulky = 4737
room-decisive-unbiased = 1998-11-01T12:23:58
soap = 1985-05-06
sprout-rich = 0.6026
[rapid.clean-leather]
blood-snow-mark = true
equable = 0.2923
fabulous = 1979-07-24T00:53:39+06:22
glorious-threatening = true
lewd-dull = 02:40:53.000027288
[run-overjoyed]
creature-cheerful = 11071
respect-history-anxious = 0.4637
vessel = 'curious'

View File

@ -8,28 +8,30 @@
#include "examples.h"
#define TOML_EXCEPTIONS 0
#define TOML_UNRELEASED_FEATURES 0
#define TOML_EXCEPTIONS 0
#define TOML_ENABLE_UNRELEASED_FEATURES 0
#include <toml++/toml.h>
using namespace std::string_view_literals;
namespace
{
inline constexpr auto invalid_parses = std::array
{
"########## comments"sv,
inline constexpr auto invalid_parses = std::array{
"########## comments and whitespace"sv,
"# bar\rkek"sv,
"# bar\bkek"sv,
"# \xf1\x63"sv,
"# val1 = 1\fval2 = 2"sv,
"foo = 1\n\u2000\nbar = 2"sv,
"########## inline tables"sv,
"val = {,}"sv,
"val = {a='b',}"sv, // allowed when TOML_UNRELEASED_FEATURES == 1
"val = {a='b',}"sv, // allowed when TOML_ENABLE_UNRELEASED_FEATURES == 1
"val = {a='b',,}"sv,
"val = {a='b',"sv,
"val = {a='b',\n c='d'}"sv, // allowed when TOML_UNRELEASED_FEATURES == 1
"val = {a='b',\n c='d'}"sv, // allowed when TOML_ENABLE_UNRELEASED_FEATURES == 1
"val = {?='b'}"sv,
"foo = {} \n [foo.bar]"sv,
"########## tables"sv,
"[]"sv,
@ -69,7 +71,7 @@ namespace
"val = \" \r \""sv,
R"(val = ")"sv,
R"(val = "\g")"sv,
R"(val = "\x20")"sv, // allowed when TOML_UNRELEASED_FEATURES == 1
R"(val = "\x20")"sv, // allowed when TOML_ENABLE_UNRELEASED_FEATURES == 1
R"(val = "\uFFF")"sv,
R"(val = "\uFFFG")"sv,
R"(val = "\UFFFFFFF")"sv,
@ -92,12 +94,14 @@ namespace
R"(val = -+1)"sv,
R"(val = 1_0_)"sv,
R"(val = 1_0_ )"sv,
R"(val = 999999999999999999999999999999999999 )"sv,
R"(val = 9223372036854775808 )"sv,
R"(val = 01 )"sv,
R"(val = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 )"sv,
R"(val = 0o1000000000000000000000 )"sv,
R"(val = 9223372036854775808 )"sv,
R"(val = 0x8000000000000000 )"sv,
"########## floats"sv,
R"(val = 9999999999999999999999999999999999999999999999999999999999999995.0)"sv,
R"(val = 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0)"sv,
};
inline constexpr auto divider =
@ -106,8 +110,6 @@ namespace
int main()
{
examples::init();
for (auto str : invalid_parses)
{
if (str.empty())

View File

@ -19,13 +19,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>

View File

@ -6,14 +6,14 @@
// this file is for boilerplate unrelated to the toml++ example learning outcomes.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#elif defined (__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#elif defined(_MSC_VER)
#pragma warning(push, 0)
#pragma warning(push, 0)
#endif
#include <cstdlib>
@ -24,29 +24,37 @@
#include <string_view>
#include <vector>
#include <array>
#include <chrono>
#ifdef _WIN32
#include <windows.h>
#ifdef _MSC_VER
extern "C" __declspec(dllimport) int __stdcall SetConsoleOutputCP(unsigned int);
#pragma comment(lib, "Kernel32.lib")
#else
#include <Windows.h>
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
namespace examples
namespace
{
inline void init() noexcept
static const auto initialize_environment_automagically = []() noexcept
{
#ifdef _WIN32
SetConsoleOutputCP(65001); //CP_UTF8
#endif
#ifdef _WIN32
SetConsoleOutputCP(65001); // CP_UTF8
#endif
std::ios_base::sync_with_stdio(false);
std::cout << std::boolalpha;
srand(static_cast<unsigned int>(time(nullptr)));
}
return true;
}();
}
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@ -1,22 +1,50 @@
example_args = []
example_args += additional_arguments
example_overrides = []
example_overrides += overrides
if is_gcc or is_clang
example_args += [ '-Wno-switch', '-Wno-switch-default', '-Wno-switch-enum' ]
endif
if is_clang and get_option('asan_examples')
example_args += [ '-g3' ]
example_overrides += 'b_sanitize=address'
endif
examples = [
'simple_parser',
'toml_to_json_transcoder',
'toml_generator',
'error_printer'
'error_printer',
'parse_benchmark',
]
example_executables = []
foreach example : examples
executable(
example_executables += [[
example,
[ example+'.cpp' ],
include_directories: include_dirs,
cpp_args: example_args,
override_options: overrides
)
executable(
example,
[ example+'.cpp' ],
include_directories: include_dirs,
cpp_args: example_args,
override_options: example_overrides
)
]]
endforeach
if is_clang and get_option('asan_examples')
foreach executable : example_executables
# skip the transcoder (it waits on stdin) and the benchmark (might be slow and cause CI to fail)
if executable[0].contains('transcoder') or executable[0].contains('benchmark')
continue
endif
test(
executable[0], # name
executable[1], # executable object
workdir: meson.source_root()/'examples'
)
endforeach
endif

View File

@ -0,0 +1,81 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
// This example is just a short-n-shiny benchmark.
#include "examples.h"
#include <toml++/toml.h>
using namespace std::string_view_literals;
static constexpr size_t iterations = 10000;
int main(int argc, char** argv)
{
const auto file_path = std::string(argc > 1 ? std::string_view{ argv[1] } : "benchmark_data.toml"sv);
// read the file into a string first to remove file I/O from the benchmark
std::string file_content;
{
std::ifstream file(file_path, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
if (!file)
{
std::cerr << "File '"sv << file_path << "'could not be opened for reading\n"sv;
return -1;
}
const auto file_size = file.tellg();
if (file_size == -1)
{
std::cerr << "File '"sv << file_path << "' could not be opened for reading\n"sv;
return -1;
}
file.seekg(0, std::ifstream::beg);
file_content.resize(static_cast<size_t>(file_size));
file.read(file_content.data(), static_cast<std::streamsize>(file_size));
if (!file.eof() && !file)
{
std::cerr << "Failed to read contents of file '"sv << file_path << "'\n"sv;
return -1;
}
}
// parse once to make sure it isn't garbage
{
#if TOML_EXCEPTIONS
try
{
const auto result = toml::parse(file_content, file_path);
}
catch (const toml::parse_error& err)
{
std::cerr << err << "\n";
return 1;
}
#else
const auto result = toml::parse(file_content, file_path);
if (!result)
{
std::cerr << result.error() << "\n";
return 1;
}
#endif
}
// run the benchmark
std::cout << "Parsing '"sv << file_path << "' "sv << iterations << " times...\n"sv;
const auto start = std::chrono::steady_clock::now();
for (size_t i = 0; i < iterations; i++)
std::ignore = toml::parse(file_content, file_path);
const auto cumulative_sec =
std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - start).count();
const auto mean_sec = cumulative_sec / static_cast<double>(iterations);
std::cout << " total: "sv << cumulative_sec << " s\n"sv
<< " mean: "sv << mean_sec << " s\n"sv;
return 0;
}

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{407FCAA8-FC2C-424D-B44B-C6A1AFAD757A}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="..\toml++.props" />
<ItemDefinitionGroup>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\examples</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<Natvis Include="..\toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="parse_benchmark.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="benchmark_data.toml" />
<None Include="meson.build" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="examples.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -3,29 +3,36 @@
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
// This example demonstrates how to parse TOML from a file and re-serialize it (print it out) to stdout.
// This example demonstrates how to parse TOML from a file or stdin and re-serialize it (print it out) to stdout.
#include "examples.h"
#define TOML_UNRELEASED_FEATURES 1
#define TOML_ENABLE_UNRELEASED_FEATURES 1
#include <toml++/toml.h>
using namespace std::string_view_literals;
int main(int argc, char** argv)
{
examples::init();
const auto path = argc > 1 ? std::string_view{ argv[1] } : "example.toml"sv;
toml::table tbl;
try
{
const auto table = toml::parse_file(path);
std::cout << table << "\n";
// read directly from stdin
if (path == "-"sv || path.empty())
tbl = toml::parse(std::cin, "stdin"sv);
// read from a file
else
tbl = toml::parse_file(path);
}
catch (const toml::parse_error& err)
{
std::cerr << err << "\n";
return 1;
}
std::cout << tbl << "\n";
return 0;
}

View File

@ -19,13 +19,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>

View File

@ -7,84 +7,75 @@
#include "examples.h"
#define TOML_PARSER 0
#define TOML_ENABLE_PARSER 0
#include <toml++/toml.h>
using namespace std::string_view_literals;
namespace
{
inline constexpr auto words = std::array
{
"acceptable"sv, "contain"sv, "ghost"sv, "mark"sv, "respect"sv, "taboo"sv,
"actually"sv, "cream"sv, "gleaming"sv, "meaty"sv, "rest"sv, "tacky"sv,
"addition"sv, "creature"sv, "glorious"sv, "memory"sv, "rice"sv, "tank"sv,
"adhesive"sv, "crime"sv, "gold"sv, "messy"sv, "rich"sv, "tent"sv,
"adorable"sv, "cross"sv, "grandfather"sv, "miss"sv, "righteous"sv, "terrible"sv,
"advise"sv, "crowded"sv, "gusty"sv, "modern"sv, "room"sv, "threatening"sv,
"afraid"sv, "crown"sv, "haircut"sv, "morning"sv, "rotten"sv, "three"sv,
"ancient"sv, "cure"sv, "hard-to-find"sv, "naughty"sv, "royal"sv, "ticket"sv,
"anxious"sv, "curious"sv, "harm"sv, "neck"sv, "run"sv, "title"sv,
"aromatic"sv, "curtain"sv, "heavy"sv, "night"sv, "satisfy"sv, "torpid"sv,
"attempt"sv, "cycle"sv, "helpless"sv, "nondescript"sv, "scary"sv, "train"sv,
"babies"sv, "deadpan"sv, "high-pitched"sv, "overjoyed"sv, "scatter"sv, "umbrella"sv,
"bake"sv, "decisive"sv, "hilarious"sv, "page"sv, "scene"sv, "unadvised"sv,
"ball"sv, "deeply"sv, "history"sv, "partner"sv, "scintillating"sv, "unbecoming"sv,
"bat"sv, "delightful"sv, "hook"sv, "party"sv, "self"sv, "unbiased"sv,
"behave"sv, "deserted"sv, "ignore"sv, "pause"sv, "selfish"sv, "unite"sv,
"best"sv, "draconian"sv, "imperfect"sv, "pear"sv, "silky"sv, "uptight"sv,
"birds"sv, "dreary"sv, "impossible"sv, "picture"sv, "sisters"sv, "used"sv,
"blind"sv, "dull"sv, "incandescent"sv, "place"sv, "ski"sv, "vengeful"sv,
"blood"sv, "enthusiastic"sv, "influence"sv, "playground"sv, "skip"sv, "versed"sv,
"blue-eyed"sv, "equable"sv, "innocent"sv, "popcorn"sv, "snow"sv, "vessel"sv,
"boiling"sv, "excuse"sv, "insidious"sv, "prefer"sv, "soap"sv, "view"sv,
"bore"sv, "experience"sv, "itch"sv, "productive"sv, "spare"sv, "voyage"sv,
"borrow"sv, "fabulous"sv, "jail"sv, "profuse"sv, "spicy"sv, "wall"sv,
"broken"sv, "familiar"sv, "kindhearted"sv, "protective"sv, "spiritual"sv, "want"sv,
"capable"sv, "finger"sv, "lackadaisical"sv, "pumped"sv, "sprout"sv, "weary"sv,
"charming"sv, "finicky"sv, "laughable"sv, "rabbit"sv, "squirrel"sv, "week"sv,
"cheerful"sv, "fix"sv, "leather"sv, "rapid"sv, "stale"sv, "whip"sv,
"chubby"sv, "flagrant"sv, "legal"sv, "regret"sv, "step"sv, "wilderness"sv,
"clean"sv, "flat"sv, "lewd"sv, "reject"sv, "stingy"sv, "wistful"sv,
"close"sv, "flimsy"sv, "license"sv, "rejoice"sv, "string"sv, "worried"sv,
"cobweb"sv, "fuel"sv, "light"sv, "relation"sv, "sulky"sv, "wretched"sv,
"complex"sv, "furtive"sv, "march"sv, "remarkable"sv, "surprise"sv, "zealous"sv,
"consist"sv, "geese"sv
inline constexpr auto words = std::array{
"acceptable"sv, "contain"sv, "ghost"sv, "mark"sv, "respect"sv, "taboo"sv,
"actually"sv, "cream"sv, "gleaming"sv, "meaty"sv, "rest"sv, "tacky"sv,
"addition"sv, "creature"sv, "glorious"sv, "memory"sv, "rice"sv, "tank"sv,
"adhesive"sv, "crime"sv, "gold"sv, "messy"sv, "rich"sv, "tent"sv,
"adorable"sv, "cross"sv, "grandfather"sv, "miss"sv, "righteous"sv, "terrible"sv,
"advise"sv, "crowded"sv, "gusty"sv, "modern"sv, "room"sv, "threatening"sv,
"afraid"sv, "crown"sv, "haircut"sv, "morning"sv, "rotten"sv, "three"sv,
"ancient"sv, "cure"sv, "hard-to-find"sv, "naughty"sv, "royal"sv, "ticket"sv,
"anxious"sv, "curious"sv, "harm"sv, "neck"sv, "run"sv, "title"sv,
"aromatic"sv, "curtain"sv, "heavy"sv, "night"sv, "satisfy"sv, "torpid"sv,
"attempt"sv, "cycle"sv, "helpless"sv, "nondescript"sv, "scary"sv, "train"sv,
"babies"sv, "deadpan"sv, "high-pitched"sv, "overjoyed"sv, "scatter"sv, "umbrella"sv,
"bake"sv, "decisive"sv, "hilarious"sv, "page"sv, "scene"sv, "unadvised"sv,
"ball"sv, "deeply"sv, "history"sv, "partner"sv, "scintillating"sv, "unbecoming"sv,
"bat"sv, "delightful"sv, "hook"sv, "party"sv, "self"sv, "unbiased"sv,
"behave"sv, "deserted"sv, "ignore"sv, "pause"sv, "selfish"sv, "unite"sv,
"best"sv, "draconian"sv, "imperfect"sv, "pear"sv, "silky"sv, "uptight"sv,
"birds"sv, "dreary"sv, "impossible"sv, "picture"sv, "sisters"sv, "used"sv,
"blind"sv, "dull"sv, "incandescent"sv, "place"sv, "ski"sv, "vengeful"sv,
"blood"sv, "enthusiastic"sv, "influence"sv, "playground"sv, "skip"sv, "versed"sv,
"blue-eyed"sv, "equable"sv, "innocent"sv, "popcorn"sv, "snow"sv, "vessel"sv,
"boiling"sv, "excuse"sv, "insidious"sv, "prefer"sv, "soap"sv, "view"sv,
"bore"sv, "experience"sv, "itch"sv, "productive"sv, "spare"sv, "voyage"sv,
"borrow"sv, "fabulous"sv, "jail"sv, "profuse"sv, "spicy"sv, "wall"sv,
"broken"sv, "familiar"sv, "kindhearted"sv, "protective"sv, "spiritual"sv, "want"sv,
"capable"sv, "finger"sv, "lackadaisical"sv, "pumped"sv, "sprout"sv, "weary"sv,
"charming"sv, "finicky"sv, "laughable"sv, "rabbit"sv, "squirrel"sv, "week"sv,
"cheerful"sv, "fix"sv, "leather"sv, "rapid"sv, "stale"sv, "whip"sv,
"chubby"sv, "flagrant"sv, "legal"sv, "regret"sv, "step"sv, "wilderness"sv,
"clean"sv, "flat"sv, "lewd"sv, "reject"sv, "stingy"sv, "wistful"sv,
"close"sv, "flimsy"sv, "license"sv, "rejoice"sv, "string"sv, "worried"sv,
"cobweb"sv, "fuel"sv, "light"sv, "relation"sv, "sulky"sv, "wretched"sv,
"complex"sv, "furtive"sv, "march"sv, "remarkable"sv, "surprise"sv, "zealous"sv,
"consist"sv, "geese"sv
};
template <typename T>
[[nodiscard]]
static T rand(T excl_max) noexcept
[[nodiscard]] static T rand(T excl_max) noexcept
{
return static_cast<T>(static_cast<T>(std::rand()) % excl_max);
}
template <typename T>
[[nodiscard]]
static T rand(T incl_min, T excl_max) noexcept
[[nodiscard]] static T rand(T incl_min, T excl_max) noexcept
{
return static_cast<T>(incl_min + rand(excl_max - incl_min));
}
static auto rand_date() noexcept
{
return toml::date
{
rand(uint16_t{ 1900 }, uint16_t{ 2021 }),
rand(uint8_t{ 1 }, uint8_t{ 13 }),
rand(uint8_t{ 1 }, uint8_t{ 29 })
};
return toml::date{ rand(uint16_t{ 1900 }, uint16_t{ 2021 }),
rand(uint8_t{ 1 }, uint8_t{ 13 }),
rand(uint8_t{ 1 }, uint8_t{ 29 }) };
}
static auto rand_time() noexcept
{
return toml::time
{
rand(uint8_t{ 24 }),
rand(uint8_t{ 60 }),
rand(uint8_t{ 60 }),
rand(100) > 80 ? rand(1000000000u) : 0u
};
return toml::time{ rand(uint8_t{ 24 }),
rand(uint8_t{ 60 }),
rand(uint8_t{ 60 }),
rand(100) > 80 ? rand(1000000000u) : 0u };
}
static auto rand_string(size_t word_count, char sep = ' ') noexcept
@ -102,8 +93,6 @@ namespace
int main(int argc, char** argv)
{
examples::init();
int node_budget{};
for (int i = 1; i < argc; i++)
{
@ -119,14 +108,14 @@ int main(int argc, char** argv)
std::vector<toml::node*> tree;
tree.push_back(&root);
constexpr size_t max_depth = 10u;
int container_min_values = 10;
bool in_arr = false;
int container_min_values = 10;
bool in_arr = false;
const auto add = [&](auto&& val) noexcept -> auto&
{
using value_ref = decltype(val);
using value_ref = decltype(val);
using value_type = std::remove_reference_t<value_ref>;
using node_type = toml::inserted_type_of<value_type>;
using node_type = toml::inserted_type_of<value_type>;
toml::node* new_node{};
@ -142,10 +131,8 @@ int main(int argc, char** argv)
{
auto& table = tree.back()->ref<toml::table>();
const auto it = table.insert_or_assign(
rand_string(rand<size_t>(1u, 4u), '-'),
std::forward<value_ref>(val)
);
const auto it =
table.insert_or_assign(rand_string(rand<size_t>(1u, 4u), '-'), std::forward<value_ref>(val));
new_node = &it.first->second;
}
@ -155,7 +142,7 @@ int main(int argc, char** argv)
{
tree.push_back(new_node);
container_min_values = rand(1, 4);
in_arr = toml::is_array<value_type>;
in_arr = toml::is_array<value_type>;
if constexpr (toml::is_array<value_type>)
tree.back()->as_array()->reserve(static_cast<size_t>(container_min_values));
}
@ -183,41 +170,30 @@ int main(int argc, char** argv)
switch (new_node_type)
{
case toml::node_type::array:
if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::array{});
break;
case toml::node_type::array:
if (container_min_values <= 0 && tree.size() < max_depth)
add(toml::array{});
break;
case toml::node_type::string:
add(rand_string(rand<size_t>(8u)));
break;
case toml::node_type::string: add(rand_string(rand<size_t>(8u))); break;
case toml::node_type::integer:
add(rand());
break;
case toml::node_type::integer: add(rand()); break;
case toml::node_type::floating_point:
add(rand(10001u) / 10000.0);
break;
case toml::node_type::floating_point: add(rand(10001u) / 10000.0); break;
case toml::node_type::boolean:
add(!rand(2u));
break;
case toml::node_type::boolean: add(!rand(2u)); break;
case toml::node_type::date:
add(rand_date());
break;
case toml::node_type::date: add(rand_date()); break;
case toml::node_type::time:
add(rand_time());
break;
case toml::node_type::time: add(rand_time()); break;
case toml::node_type::date_time:
add(rand(100) >= 75
? toml::date_time{ rand_date(), rand_time() }
: toml::date_time{ rand_date(), rand_time(), toml::time_offset{ rand<int8_t>(-11, 12), rand<int8_t>(-45, +46) } }
);
break;
case toml::node_type::date_time:
add(rand(100) >= 75
? toml::date_time{ rand_date(), rand_time() }
: toml::date_time{ rand_date(),
rand_time(),
toml::time_offset{ rand<int8_t>(-11, 12), rand<int8_t>(-45, +46) } });
break;
}
if (container_min_values <= 0 && tree.size() >= 2u && rand(100) >= 85)
{

View File

@ -20,13 +20,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>

View File

@ -7,28 +7,25 @@
#include "examples.h"
#define TOML_UNRELEASED_FEATURES 1
#define TOML_ENABLE_UNRELEASED_FEATURES 1
#include <toml++/toml.h>
using namespace std::string_view_literals;
int main(int argc, char** argv)
{
examples::init();
const auto path = argc > 1 ? std::string_view{ argv[1] } : ""sv;
toml::table table;
try
{
// read from a file if a path argument is given
if (argc > 1)
table = toml::parse_file(argv[1]);
// otherwise read directly from stdin
else
// read directly from stdin
if (path == "-"sv || path.empty())
table = toml::parse(std::cin, "stdin"sv);
std::cout << toml::json_formatter{ table } << "\n";
// read from a file
else
table = toml::parse_file(argv[1]);
}
catch (const toml::parse_error& err)
{

View File

@ -20,13 +20,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>

1
external/json vendored Submodule

@ -0,0 +1 @@
Subproject commit cc59ab122f75448c17ac623d10306cbe19cde970

2
external/toml-test vendored

@ -1 +1 @@
Subproject commit f2f2280c83f74212860fe0f12ee84581836c066c
Subproject commit 442dea55c5173bc89c2afa1b023ecbf0e042ceac

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,362 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
TOML_ASSERT_ASSUME(b);
TOML_ASSERT_ASSUME(e);
TOML_ASSERT_ASSUME(b <= e);
if TOML_UNLIKELY(b == e)
return;
size_t cap{};
for (auto it = b; it != e; it++)
{
if (it->value)
cap++;
}
if TOML_UNLIKELY(!cap)
return;
elems_.reserve(cap);
for (; b != e; b++)
{
if (b->value)
elems_.push_back(std::move(b->value));
}
}
TOML_EXTERNAL_LINKAGE
array::array(const array& other) //
: node(other)
{
elems_.reserve(other.elems_.size());
for (const auto& elem : other)
elems_.emplace_back(impl::make_node(elem));
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::array(array && other) noexcept //
: node(std::move(other)),
elems_(std::move(other.elems_))
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array& array::operator=(const array& rhs)
{
if (&rhs != this)
{
node::operator=(rhs);
elems_.clear();
elems_.reserve(rhs.elems_.size());
for (const auto& elem : rhs)
elems_.emplace_back(impl::make_node(elem));
}
return *this;
}
TOML_EXTERNAL_LINKAGE
array& array::operator=(array&& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(std::move(rhs));
elems_ = std::move(rhs.elems_);
}
return *this;
}
TOML_EXTERNAL_LINKAGE
void array::preinsertion_resize(size_t idx, size_t count)
{
TOML_ASSERT(idx <= elems_.size());
TOML_ASSERT_ASSUME(count >= 1u);
const auto old_size = elems_.size();
const auto new_size = old_size + count;
const auto inserting_at_end = idx == old_size;
elems_.resize(new_size);
if (!inserting_at_end)
{
for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
elems_[right] = std::move(elems_[left]);
}
}
TOML_EXTERNAL_LINKAGE
void array::insert_at_back(impl::node_ptr && elem)
{
elems_.push_back(std::move(elem));
}
TOML_API
array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
{
return elems_.insert(pos, std::move(elem));
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype) const noexcept
{
if (elems_.empty())
return false;
if (ntype == node_type::none)
ntype = elems_[0]->type();
for (const auto& val : elems_)
if (val->type() != ntype)
return false;
return true;
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
{
if (elems_.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = elems_[0]->type();
for (const auto& val : elems_)
{
if (val->type() != ntype)
{
first_nonmatch = val.get();
return false;
}
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
{
node* fnm = nullptr;
const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
first_nonmatch = fnm;
return result;
}
TOML_EXTERNAL_LINKAGE
node& array::at(size_t index)
{
#if TOML_COMPILER_EXCEPTIONS
return *elems_.at(index);
#else
auto n = get(index);
TOML_ASSERT_ASSUME(n && "element index not found in array!");
return *n;
#endif
}
TOML_EXTERNAL_LINKAGE
void array::reserve(size_t new_capacity)
{
elems_.reserve(new_capacity);
}
TOML_EXTERNAL_LINKAGE
void array::shrink_to_fit()
{
elems_.shrink_to_fit();
}
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
if (new_size < elems_.size())
elems_.resize(new_size);
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator pos) noexcept
{
return iterator{ elems_.erase(const_vector_iterator{ pos }) };
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
{
return iterator{ elems_.erase(const_vector_iterator{ first }, const_vector_iterator{ last }) };
}
TOML_EXTERNAL_LINKAGE
size_t array::total_leaf_count() const noexcept
{
size_t leaves{};
for (size_t i = 0, e = elems_.size(); i < e; i++)
{
auto arr = elems_[i]->as_array();
leaves += arr ? arr->total_leaf_count() : size_t{ 1 };
}
return leaves;
}
TOML_EXTERNAL_LINKAGE
void array::flatten_child(array && child, size_t & dest_index) noexcept
{
for (size_t i = 0, e = child.size(); i < e; i++)
{
auto type = child.elems_[i]->type();
if (type == node_type::array)
{
array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
if (!arr.empty())
flatten_child(std::move(arr), dest_index);
}
else
elems_[dest_index++] = std::move(child.elems_[i]);
}
}
TOML_EXTERNAL_LINKAGE
array& array::flatten()&
{
if (elems_.empty())
return *this;
bool requires_flattening = false;
size_t size_after_flattening = elems_.size();
for (size_t i = elems_.size(); i-- > 0u;)
{
auto arr = elems_[i]->as_array();
if (!arr)
continue;
size_after_flattening--; // discount the array itself
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 0u)
{
requires_flattening = true;
size_after_flattening += leaf_count;
}
else
elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
}
if (!requires_flattening)
return *this;
elems_.reserve(size_after_flattening);
size_t i = 0;
while (i < elems_.size())
{
auto arr = elems_[i]->as_array();
if (!arr)
{
i++;
continue;
}
impl::node_ptr arr_storage = std::move(elems_[i]);
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 1u)
preinsertion_resize(i + 1u, leaf_count - 1u);
flatten_child(std::move(*arr), i); // increments i
}
return *this;
}
TOML_EXTERNAL_LINKAGE
array& array::prune(bool recursive)& noexcept
{
if (elems_.empty())
return *this;
for (size_t i = elems_.size(); i-- > 0u;)
{
if (auto arr = elems_[i]->as_array())
{
if (recursive)
arr->prune(true);
if (arr->empty())
elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
}
else if (auto tbl = elems_[i]->as_table())
{
if (recursive)
tbl->prune(true);
if (tbl->empty())
elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
}
}
return *this;
}
TOML_EXTERNAL_LINKAGE
void array::pop_back() noexcept
{
elems_.pop_back();
}
TOML_EXTERNAL_LINKAGE
void array::clear() noexcept
{
elems_.clear();
}
TOML_EXTERNAL_LINKAGE
bool array::equal(const array& lhs, const array& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.elems_.size() != rhs.elems_.size())
return false;
for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
{
const auto lhs_type = lhs.elems_[i]->type();
const node& rhs_ = *rhs.elems_[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = lhs.elems_[i]->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -1,283 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "array.h"
/// \cond
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
array::array() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::array(const array& other) noexcept //
: node(other)
{
elements.reserve(other.elements.size());
for (const auto& elem : other)
elements.emplace_back(impl::make_node(elem));
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::array(array && other) noexcept //
: node(std::move(other)),
elements{ std::move(other.elements) }
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array& array::operator=(const array& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(rhs);
elements.clear();
elements.reserve(rhs.elements.size());
for (const auto& elem : rhs)
elements.emplace_back(impl::make_node(elem));
}
return *this;
}
TOML_EXTERNAL_LINKAGE
array& array::operator=(array&& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(std::move(rhs));
elements = std::move(rhs.elements);
}
return *this;
}
TOML_EXTERNAL_LINKAGE
void array::preinsertion_resize(size_t idx, size_t count) noexcept
{
TOML_ASSERT(idx <= elements.size());
TOML_ASSERT(count >= 1_sz);
const auto old_size = elements.size();
const auto new_size = old_size + count;
const auto inserting_at_end = idx == old_size;
elements.resize(new_size);
if (!inserting_at_end)
{
for (size_t left = old_size, right = new_size - 1_sz; left-- > idx; right--)
elements[right] = std::move(elements[left]);
}
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
const node& array::operator[](size_t index) const noexcept
{
return *elements[index];
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
node& array::operator[](size_t index) noexcept
{
return *elements[index];
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype) const noexcept
{
if (elements.empty())
return false;
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
if (val->type() != ntype)
return false;
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept
{
if (elements.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
{
if (val->type() != ntype)
{
first_nonmatch = val.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, toml::node * &first_nonmatch) noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
node* array::get(size_t index) noexcept
{
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
const node* array::get(size_t index) const noexcept
{
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_EXTERNAL_LINKAGE
bool operator==(const array& lhs, const array& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.elements.size() != rhs.elements.size())
return false;
for (size_t i = 0, e = lhs.elements.size(); i < e; i++)
{
const auto lhs_type = lhs.elements[i]->type();
const node& rhs_ = *rhs.elements[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = lhs.elements[i]->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool operator!=(const array& lhs, const array& rhs) noexcept
{
return !(lhs == rhs);
}
TOML_EXTERNAL_LINKAGE
size_t array::total_leaf_count() const noexcept
{
size_t leaves{};
for (size_t i = 0, e = elements.size(); i < e; i++)
{
auto arr = elements[i]->as_array();
leaves += arr ? arr->total_leaf_count() : 1_sz;
}
return leaves;
}
TOML_EXTERNAL_LINKAGE
void array::flatten_child(array && child, size_t & dest_index) noexcept
{
for (size_t i = 0, e = child.size(); i < e; i++)
{
auto type = child.elements[i]->type();
if (type == node_type::array)
{
array& arr = *reinterpret_cast<array*>(child.elements[i].get());
if (!arr.empty())
flatten_child(std::move(arr), dest_index);
}
else
elements[dest_index++] = std::move(child.elements[i]);
}
}
TOML_EXTERNAL_LINKAGE
array& array::flatten()&
{
if (elements.empty())
return *this;
bool requires_flattening = false;
size_t size_after_flattening = elements.size();
for (size_t i = elements.size(); i-- > 0_sz;)
{
auto arr = elements[i]->as_array();
if (!arr)
continue;
size_after_flattening--; // discount the array itself
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 0_sz)
{
requires_flattening = true;
size_after_flattening += leaf_count;
}
else
elements.erase(elements.cbegin() + static_cast<ptrdiff_t>(i));
}
if (!requires_flattening)
return *this;
elements.reserve(size_after_flattening);
size_t i = 0;
while (i < elements.size())
{
auto arr = elements[i]->as_array();
if (!arr)
{
i++;
continue;
}
std::unique_ptr<node> arr_storage = std::move(elements[i]);
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 1_sz)
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
flatten_child(std::move(*arr), i); // increments i
}
return *this;
}
}
TOML_NAMESPACE_END;
/// \endcond

View File

@ -0,0 +1,82 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "forward_declarations.h"
TOML_NAMESPACE_START
{
/// \brief Returns a view of the node matching a fully-qualified "TOML path".
///
/// \detail \cpp
/// auto config = R"(
///
/// [foo]
/// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ]
///
/// )"_toml;
///
/// std::cout << toml::at_path(config, "foo.bar[2]") << "\n";
/// std::cout << toml::at_path(config, "foo.bar[3][0]") << "\n";
/// std::cout << toml::at_path(config, "foo.bar[4].kek") << "\n";
/// \ecpp
///
/// \out
/// 2
/// 3
/// 4
/// \eout
///
///
/// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters:
/// \cpp
/// toml::at_path(config, "foo.bar") // same as config["foo"]["bar"]
/// toml::at_path(config, "foo. bar") // same as config["foo"][" bar"]
/// toml::at_path(config, "foo..bar") // same as config["foo"][""]["bar"]
/// toml::at_path(config, ".foo.bar") // same as config[""]["foo"]["bar"]
/// \ecpp
/// <br>
/// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings.
/// This function makes no allowance for this, instead treating all period characters as sub-table delimiters.
/// If you have periods in your table keys, first consider:
/// 1. Not doing that
/// 2. Using node_view::operator[] instead.
///
/// \param root The root node from which the path will be traversed.
/// \param path The "TOML path" to traverse.
TOML_NODISCARD
TOML_API
node_view<node> at_path(node & root, std::string_view path) noexcept;
/// \brief Returns a const view of the node matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<const node> at_path(const node& root, std::string_view path) noexcept;
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the node matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<node> at_path(node & root, std::wstring_view path);
/// \brief Returns a const view of the node matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<const node> at_path(const node& root, std::wstring_view path);
#endif
}
TOML_NAMESPACE_END;

View File

@ -0,0 +1,228 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "at_path.h"
#include "array.h"
#include "table.h"
TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
#include <charconv>
#else
#include <sstream>
#endif
TOML_ENABLE_WARNINGS;
#include "header_start.h"
TOML_ANON_NAMESPACE_START
{
TOML_INTERNAL_LINKAGE
node* get_at_path(node & root, std::string_view path) noexcept
{
if (root.is_value()) // values don't have child nodes
return nullptr;
size_t pos = 0;
const auto end = path.length();
node* current = &root;
bool prev_was_array_indexer = false;
bool prev_was_dot = root.is_table(); // implicit '.' at the start for tables
do
{
// start of an array indexer
if (path[pos] == '[')
{
const auto current_array = current->as<array>();
if (!current_array)
return nullptr;
// get array index substring
const auto index_start = pos + 1u; // first position after '['
const auto index_end = path.find(']', index_start); // position of ']'
if (index_end == std::string_view::npos || index_end == index_start)
return nullptr;
auto index_str = path.substr(index_start, index_end - index_start);
// trim whitespace from either side of the index
const auto first_non_ws = index_str.find_first_not_of(" \t"sv);
const auto last_non_ws = index_str.find_last_not_of(" \t"sv);
if (first_non_ws == std::string_view::npos)
return nullptr;
TOML_ASSERT_ASSUME(last_non_ws != std::string_view::npos);
index_str = index_str.substr(first_non_ws, (last_non_ws - first_non_ws) + 1u);
// parse the actual array index
size_t index;
if (index_str.length() == 1u && index_str[0] >= '0' && index_str[0] <= '9')
index = static_cast<size_t>(index_str[0] - '0');
else
{
#if TOML_INT_CHARCONV
auto fc_result = std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
if (fc_result.ec != std::errc{})
return nullptr;
#else
std::stringstream ss;
ss.imbue(std::locale::classic());
ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
if (!(ss >> index))
return nullptr;
#endif
}
current = current_array->get(index);
pos = index_end + 1u;
prev_was_dot = false;
prev_was_array_indexer = true;
}
// start of a new table child
else if (path[pos] == '.')
{
const auto current_table = current->as<table>();
if (!current_table)
return nullptr;
// a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
// for an empty child in between, e.g.
//
// foo..bar
//
// is equivalent to
//
// "foo".""."bar"
//
if (prev_was_dot)
current = current_table->get(""sv);
pos++;
prev_was_dot = true;
prev_was_array_indexer = false;
}
// some regular subkey
else
{
// get subkey text
const auto subkey_start = pos;
const auto subkey_len =
impl::min(path.find_first_of(".["sv, subkey_start + 1u), path.length()) - subkey_start;
const auto subkey = path.substr(subkey_start, subkey_len);
// a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
//
// "foo[0] .bar"
// ^^ skip this
//
// otherwise its an error (since it would have to be preceeded by a dot)
if (prev_was_array_indexer)
{
auto non_ws = subkey.find_first_not_of(" \t");
if (non_ws == std::string_view::npos)
{
pos += subkey_len;
prev_was_dot = false;
prev_was_array_indexer = false;
continue;
}
else
return nullptr;
}
const auto current_table = current->as<table>();
if (!current_table)
return nullptr;
current = current_table->get(subkey);
pos += subkey_len;
prev_was_dot = false;
prev_was_array_indexer = false;
}
}
while (pos < end && current);
// a dot at the end is as if we'd asked for an empty child at the end, e.g.
//
// foo.bar.
//
// is equivalent to
//
// "foo"."bar".""
//
if (current && prev_was_dot)
{
const auto current_table = current->as<table>();
if (!current_table)
return nullptr;
current = current_table->get(""sv);
}
return current;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_INTERNAL_LINKAGE
node* get_at_path(node & root, std::wstring_view path) noexcept
{
if (auto tbl = root.as_table(); tbl && tbl->empty())
return {};
if (auto arr = root.as_array(); arr && arr->empty())
return {};
return get_at_path(root, impl::narrow(path));
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
}
TOML_ANON_NAMESPACE_END;
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
node_view<node> at_path(node & root, std::string_view path) noexcept
{
return node_view<node>{ TOML_ANON_NAMESPACE::get_at_path(root, path) };
}
TOML_EXTERNAL_LINKAGE
node_view<const node> at_path(const node& root, std::string_view path) noexcept
{
return node_view<const node>{ TOML_ANON_NAMESPACE::get_at_path(const_cast<node&>(root), path) };
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node_view<node> at_path(node & root, std::wstring_view path)
{
return node_view<node>{ TOML_ANON_NAMESPACE::get_at_path(root, path) };
}
TOML_EXTERNAL_LINKAGE
node_view<const node> at_path(const node& root, std::wstring_view path)
{
return node_view<const node>{ TOML_ANON_NAMESPACE::get_at_path(const_cast<node&>(root), path) };
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -2,9 +2,11 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "common.h"
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
@ -13,98 +15,132 @@ TOML_NAMESPACE_START
{
/// \brief The year component.
uint16_t year;
/// \brief The month component, from 1 - 12.
uint8_t month;
/// \brief The day component, from 1 - 31.
uint8_t day;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
date() noexcept = default;
/// \brief Constructs a date from individual date component values.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<Y, M, D>), typename Y, typename M, typename D)
TOML_NODISCARD_CTOR
constexpr date(Y y, M m, D d) noexcept //
: year{ static_cast<uint16_t>(y) },
month{ static_cast<uint8_t>(m) },
day{ static_cast<uint8_t>(d) }
{}
/// \brief Equality operator.
TOML_NODISCARD
friend constexpr bool operator==(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept
{
return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day;
}
/// \brief Inequality operator.
TOML_NODISCARD
friend constexpr bool operator!=(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept
{
return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day;
}
private:
TOML_NODISCARD
TOML_ALWAYS_INLINE
/// \cond
TOML_PURE_GETTER
static constexpr uint32_t pack(const date& d) noexcept
{
return (static_cast<uint32_t>(d.year) << 16) | (static_cast<uint32_t>(d.month) << 8)
| static_cast<uint32_t>(d.day);
}
/// \endcond
public:
/// \brief Less-than operator.
TOML_NODISCARD
friend constexpr bool operator<(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) < pack(rhs);
}
/// \brief Less-than-or-equal-to operator.
TOML_NODISCARD
friend constexpr bool operator<=(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) <= pack(rhs);
}
/// \brief Greater-than operator.
TOML_NODISCARD
friend constexpr bool operator>(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) > pack(rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_NODISCARD
friend constexpr bool operator>=(date lhs, date rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
///
/// \detail \cpp
/// std::cout << toml::date{ 1987, 3, 16 } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const date& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::date{ 1987, 3, 16 } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16
/// \eout
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const date& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const date&);
#endif
/// \brief A local time-of-day.
struct TOML_TRIVIAL_ABI time
{
/// \brief The hour component, from 0 - 23.
uint8_t hour;
/// \brief The minute component, from 0 - 59.
uint8_t minute;
/// \brief The second component, from 0 - 59.
uint8_t second;
/// \brief The fractional nanoseconds component, from 0 - 999999999.
uint32_t nanosecond;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
time() noexcept = default;
/// \brief Constructs a time from individual time component values.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M, S, NS>),
typename H,
typename M,
typename S = uint8_t,
typename NS = uint32_t)
TOML_NODISCARD_CTOR
constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
: hour{ static_cast<uint8_t>(h) },
minute{ static_cast<uint8_t>(m) },
second{ static_cast<uint8_t>(s) },
nanosecond{ static_cast<uint32_t>(ns) }
{}
/// \brief Equality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator==(const time& lhs, const time& rhs) noexcept
{
return lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second
@ -112,93 +148,87 @@ TOML_NAMESPACE_START
}
/// \brief Inequality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept
{
return !(lhs == rhs);
}
private:
TOML_NODISCARD
TOML_ALWAYS_INLINE
static constexpr uint64_t pack(time t) noexcept
/// \cond
TOML_PURE_GETTER
static constexpr uint64_t pack(const time& t) noexcept
{
return static_cast<uint64_t>(t.hour) << 48 | static_cast<uint64_t>(t.minute) << 40
| static_cast<uint64_t>(t.second) << 32 | static_cast<uint64_t>(t.nanosecond);
}
/// \endcond
public:
/// \brief Less-than operator.
TOML_NODISCARD
friend constexpr bool operator<(time lhs, time rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) < pack(rhs);
}
/// \brief Less-than-or-equal-to operator.
TOML_NODISCARD
friend constexpr bool operator<=(time lhs, time rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) <= pack(rhs);
}
/// \brief Greater-than operator.
TOML_NODISCARD
friend constexpr bool operator>(time lhs, time rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) > pack(rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_NODISCARD
friend constexpr bool operator>=(time lhs, time rhs) noexcept
TOML_PURE_GETTER
friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time{ 10, 20, 34 } << "\n";
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << "\n";
/// \ecpp
///
/// \out
/// 10:20:34
/// 10:20:34.5
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const time& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time{ 10, 20, 34 } << "\n";
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << "\n";
/// \ecpp
///
/// \out
/// 10:20:34
/// 10:20:34.5
/// \eout
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const time& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const time&);
#endif
/// \brief A timezone offset.
struct TOML_TRIVIAL_ABI time_offset
{
/// \brief Offset from UTC+0, in minutes.
int16_t minutes;
/// \brief Default-constructs a zero time-offset.
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
constexpr time_offset() noexcept //
: minutes{}
{}
time_offset() noexcept = default;
/// \brief Constructs a timezone offset from separate hour and minute totals.
/// \brief Constructs a timezone offset from individual hour and minute totals.
///
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// std::cout << toml::time_offset{ 0, 0 } << "\n";
///
/// \ecpp
///
/// \out
@ -208,84 +238,84 @@ TOML_NAMESPACE_START
/// Z
/// \eout
///
/// \tparam H An integral type.
/// \tparam M An integral type.
///
/// \param h The total hours.
/// \param m The total minutes.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M>), typename H, typename M)
TOML_NODISCARD_CTOR
constexpr time_offset(int8_t h, int8_t m) noexcept //
: minutes{ static_cast<int16_t>(h * 60 + m) }
constexpr time_offset(H h, M m) noexcept //
: minutes{ static_cast<int16_t>(static_cast<impl::common_signed_type<H, M>>(h)
* impl::common_signed_type<H, M>{ 60 }
+ static_cast<impl::common_signed_type<H, M>>(m)) }
{}
/// \brief Equality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes == rhs.minutes;
}
/// \brief Inequality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes != rhs.minutes;
}
/// \brief Less-than operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes < rhs.minutes;
}
/// \brief Less-than-or-equal-to operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes <= rhs.minutes;
}
/// \brief Greater-than operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes > rhs.minutes;
}
/// \brief Greater-than-or-equal-to operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes >= rhs.minutes;
}
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
/// std::cout << toml::time_offset{ 2, -30 } << "\n";
/// std::cout << toml::time_offset{} << "\n";
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// \ecpp
///
/// \out
/// +02:30
/// +01:30
/// Z
/// -01:30
/// -02:30
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const time_offset& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
/// std::cout << toml::time_offset{ 2, -30 } << "\n";
/// std::cout << toml::time_offset{} << "\n";
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// \ecpp
///
/// \out
/// +02:30
/// +01:30
/// Z
/// -01:30
/// -02:30
/// \eout
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const time_offset& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const time_offset&);
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt);
/// \brief A date-time.
@ -293,67 +323,85 @@ TOML_NAMESPACE_START
{
/// \brief The date component.
toml::date date;
/// \brief The time component.
toml::time time;
/// \brief The timezone offset component.
///
/// \remarks The date_time is said to be 'local' if the offset is empty.
optional<toml::time_offset> offset;
/// \brief Default-constructs a zero date-time.
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
constexpr date_time() noexcept //
: date{},
time{},
offset{} // TINAE - icc bugfix
{}
date_time() noexcept = default;
/// \brief Constructs a local date-time.
///
/// \param d The date component.
/// \param t The time component.
TOML_NODISCARD_CTOR
constexpr date_time(toml::date d, toml::time t) noexcept //
constexpr date_time(const toml::date& d, const toml::time& t) noexcept //
: date{ d },
time{ t },
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs a local date-time.
///
/// \param d The date component.
TOML_NODISCARD_CTOR
explicit constexpr date_time(const toml::date& d) noexcept //
: date{ d },
time{},
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs a local date-time.
///
/// \param t The time component.
TOML_NODISCARD_CTOR
explicit constexpr date_time(const toml::time& t) noexcept //
: date{},
time{ t },
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs an offset date-time.
///
/// \param d The date component.
/// \param t The time component.
/// \param off The timezone offset.
TOML_NODISCARD_CTOR
constexpr date_time(toml::date d, toml::time t, toml::time_offset off) noexcept
constexpr date_time(const toml::date& d, const toml::time& t, const toml::time_offset& off) noexcept
: date{ d },
time{ t },
offset{ off }
{}
/// \brief Returns true if this date_time does not contain timezone offset information.
TOML_NODISCARD
TOML_PURE_GETTER
constexpr bool is_local() const noexcept
{
return !offset.has_value();
}
/// \brief Equality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator==(const date_time& lhs, const date_time& rhs) noexcept
{
return lhs.date == rhs.date && lhs.time == rhs.time && lhs.offset == rhs.offset;
}
/// \brief Inequality operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs == rhs);
}
/// \brief Less-than operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator<(const date_time& lhs, const date_time& rhs) noexcept
{
if (lhs.date != rhs.date)
@ -364,7 +412,7 @@ TOML_NAMESPACE_START
}
/// \brief Less-than-or-equal-to operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator<=(const date_time& lhs, const date_time& rhs) noexcept
{
if (lhs.date != rhs.date)
@ -375,44 +423,40 @@ TOML_NAMESPACE_START
}
/// \brief Greater-than operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs <= rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_NODISCARD
TOML_PURE_GETTER
friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs < rhs);
}
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16T10:20:34
/// 1987-03-16T10:20:34-02:30
/// 1987-03-16T10:20:34Z
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const date_time& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16T10:20:34
/// 1987-03-16T10:20:34-02:30
/// 1987-03-16T10:20:34Z
/// \eout
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const date_time& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const date_time&);
#endif
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -1,459 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "formatter.h"
#include "table.h"
#include "array.h"
#include "utf8.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
/// \cond
TOML_IMPL_NAMESPACE_START
{
TOML_NODISCARD
TOML_API
std::string default_formatter_make_key_segment(const std::string&) noexcept;
TOML_NODISCARD
TOML_API
size_t default_formatter_inline_columns(const node&) noexcept;
TOML_NODISCARD
TOML_API
bool default_formatter_forces_multiline(const node&, size_t = 0) noexcept;
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
/// operators of the TOML node types already print themselves out using this formatter.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "description", "This is some TOML, yo." },
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
/// { "table", toml::table{{ { "foo", "bar" } }} }
/// }};
///
/// // these two lines are equivalent:
/// std::cout << toml::default_formatter{ tbl } << "\n";
/// std::cout << tbl << "\n";
///
/// \ecpp
///
/// \out
/// description = "This is some TOML, yo."
/// fruit = ["apple", "orange", "pear"]
/// numbers = [1, 2, 3, 4, 5]
///
/// [table]
/// foo = "bar"
/// \eout
///
/// \tparam Char The underlying character type of the output stream. Must be 1 byte in size.
template <typename Char = char>
class TOML_API default_formatter final : impl::formatter<Char>
{
private:
/// \cond
using base = impl::formatter<Char>;
std::vector<std::string> key_path;
bool pending_table_separator_ = false;
void print_pending_table_separator()
{
if (pending_table_separator_)
{
base::print_newline(true);
base::print_newline(true);
pending_table_separator_ = false;
}
}
void print_key_segment(const std::string& str)
{
if (str.empty())
impl::print_to_stream("''"sv, base::stream());
else
{
bool requiresQuotes = false;
{
impl::utf8_decoder decoder;
for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
requiresQuotes = true;
else if (decoder.has_code_point())
requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
}
}
if (requiresQuotes)
{
impl::print_to_stream('"', base::stream());
impl::print_to_stream_with_escapes(str, base::stream());
impl::print_to_stream('"', base::stream());
}
else
impl::print_to_stream(str, base::stream());
}
base::clear_naked_newline();
}
void print_key_path()
{
for (const auto& segment : key_path)
{
if (std::addressof(segment) > key_path.data())
impl::print_to_stream('.', base::stream());
impl::print_to_stream(segment, base::stream());
}
base::clear_naked_newline();
}
void print_inline(const table& /*tbl*/);
void print(const array& arr)
{
if (arr.empty())
impl::print_to_stream("[]"sv, base::stream());
else
{
const auto original_indent = base::indent();
const auto multiline = impl::default_formatter_forces_multiline(
arr,
base::indent_columns * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
impl::print_to_stream("["sv, base::stream());
if (multiline)
{
if (original_indent < 0)
base::indent(0);
base::increase_indent();
}
else
impl::print_to_stream(' ', base::stream());
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0_sz)
{
impl::print_to_stream(',', base::stream());
if (!multiline)
impl::print_to_stream(' ', base::stream());
}
if (multiline)
{
base::print_newline(true);
base::print_indent();
}
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
if (multiline)
{
base::indent(original_indent);
base::print_newline(true);
base::print_indent();
}
else
impl::print_to_stream(' ', base::stream());
impl::print_to_stream("]"sv, base::stream());
}
base::clear_naked_newline();
}
void print(const table& tbl)
{
static constexpr auto is_non_inline_array_of_tables = [](auto&& nde) noexcept
{
auto arr = nde.as_array();
return arr && arr->is_array_of_tables() && !arr->template get_as<table>(0_sz)->is_inline();
};
// values, arrays, and inline tables/table arrays
for (auto&& [k, v] : tbl)
{
const auto type = v.type();
if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
|| (type == node_type::array && is_non_inline_array_of_tables(v)))
continue;
pending_table_separator_ = true;
base::print_newline();
base::print_indent();
print_key_segment(k);
impl::print_to_stream(" = "sv, base::stream());
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
// non-inline tables
for (auto&& [k, v] : tbl)
{
const auto type = v.type();
if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
continue;
auto& child_tbl = *reinterpret_cast<const table*>(&v);
// we can skip indenting and emitting the headers for tables that only contain other tables
// (so we don't over-nest)
size_t child_value_count{}; // includes inline tables and non-table arrays
size_t child_table_count{};
size_t child_table_array_count{};
for (auto&& [child_k, child_v] : child_tbl)
{
(void)child_k;
const auto child_type = child_v.type();
TOML_ASSUME(child_type != node_type::none);
switch (child_type)
{
case node_type::table:
if (reinterpret_cast<const table*>(&child_v)->is_inline())
child_value_count++;
else
child_table_count++;
break;
case node_type::array:
if (is_non_inline_array_of_tables(child_v))
child_table_array_count++;
else
child_value_count++;
break;
default: child_value_count++;
}
}
bool skip_self = false;
if (child_value_count == 0_sz && (child_table_count > 0_sz || child_table_array_count > 0_sz))
skip_self = true;
key_path.push_back(impl::default_formatter_make_key_segment(k));
if (!skip_self)
{
print_pending_table_separator();
base::increase_indent();
base::print_indent();
impl::print_to_stream("["sv, base::stream());
print_key_path();
impl::print_to_stream("]"sv, base::stream());
pending_table_separator_ = true;
}
print(child_tbl);
key_path.pop_back();
if (!skip_self)
base::decrease_indent();
}
// table arrays
for (auto&& [k, v] : tbl)
{
if (!is_non_inline_array_of_tables(v))
continue;
auto& arr = *reinterpret_cast<const array*>(&v);
base::increase_indent();
key_path.push_back(impl::default_formatter_make_key_segment(k));
for (size_t i = 0; i < arr.size(); i++)
{
print_pending_table_separator();
base::print_indent();
impl::print_to_stream("[["sv, base::stream());
print_key_path();
impl::print_to_stream("]]"sv, base::stream());
pending_table_separator_ = true;
print(*reinterpret_cast<const table*>(&arr[i]));
}
key_path.pop_back();
base::decrease_indent();
}
}
void print()
{
if (base::dump_failed_parse_result())
return;
switch (auto source_type = base::source().type())
{
case node_type::table:
{
auto& tbl = *reinterpret_cast<const table*>(&base::source());
if (tbl.is_inline())
print_inline(tbl);
else
{
base::decrease_indent(); // so root kvps and tables have the same indent
print(tbl);
}
break;
}
case node_type::array: print(*reinterpret_cast<const array*>(&base::source())); break;
default: base::print_value(base::source(), source_type);
}
}
/// \endcond
public:
/// \brief The default flags for a default_formatter.
static constexpr format_flags default_flags = format_flags::allow_literal_strings
| format_flags::allow_multi_line_strings
| format_flags::allow_value_format_flags;
/// \brief Constructs a default formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, flags }
{}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a default TOML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid TOML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::default_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::default_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a = 'b'
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit default_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, flags }
{}
#endif
template <typename T, typename U>
friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>&, default_formatter<U>&);
template <typename T, typename U>
friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>&, default_formatter<U>&&);
};
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template class TOML_API default_formatter<char>;
#endif
default_formatter(const table&)->default_formatter<char>;
default_formatter(const array&)->default_formatter<char>;
template <typename T>
default_formatter(const value<T>&) -> default_formatter<char>;
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
template <typename T, typename U>
inline std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, default_formatter<U>& rhs)
{
rhs.attach(lhs);
rhs.key_path.clear();
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
template <typename T, typename U>
inline std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, default_formatter<U>&& rhs)
{
return lhs << rhs; // as lvalue
}
#ifndef DOXYGEN
#if !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, default_formatter<char>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, default_formatter<char>&&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const table&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const array&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<std::string>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<int64_t>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<double>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<bool>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<toml::date>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<toml::time>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const value<toml::date_time>&);
#endif
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const table& rhs)
{
return lhs << default_formatter<Char>{ rhs };
}
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const array& rhs)
{
return lhs << default_formatter<Char>{ rhs };
}
template <typename Char, typename T>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const value<T>& rhs)
{
return lhs << default_formatter<Char>{ rhs };
}
#endif // !DOXYGEN
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS

View File

@ -1,287 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "default_formatter.h"
/// \cond
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_IMPL_NAMESPACE_START
{
inline constexpr size_t default_formatter_line_wrap = 120_sz;
TOML_EXTERNAL_LINKAGE
std::string default_formatter_make_key_segment(const std::string& str) noexcept
{
if (str.empty())
return "''"s;
else
{
bool requires_quotes = false;
{
utf8_decoder decoder;
for (size_t i = 0; i < str.length() && !requires_quotes; i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
requires_quotes = true;
else if (decoder.has_code_point())
requires_quotes = !is_bare_key_character(decoder.codepoint);
}
}
if (requires_quotes)
{
std::string s;
s.reserve(str.length() + 2_sz);
s += '"';
for (auto c : str)
{
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
s.append(low_character_escape_table[c]);
else if TOML_UNLIKELY(c == '\x7F')
s.append("\\u007F"sv);
else if TOML_UNLIKELY(c == '"')
s.append("\\\""sv);
else
s += c;
}
s += '"';
return s;
}
else
return str;
}
}
TOML_EXTERNAL_LINKAGE
size_t default_formatter_inline_columns(const node& node) noexcept
{
switch (node.type())
{
case node_type::table:
{
auto& n = *reinterpret_cast<const table*>(&node);
if (n.empty())
return 2_sz; // "{}"
size_t weight = 3_sz; // "{ }"
for (auto&& [k, v] : n)
{
weight += k.length() + default_formatter_inline_columns(v) + 2_sz; // + ", "
if (weight >= default_formatter_line_wrap)
break;
}
return weight;
}
case node_type::array:
{
auto& n = *reinterpret_cast<const array*>(&node);
if (n.empty())
return 2_sz; // "[]"
size_t weight = 3_sz; // "[ ]"
for (auto& elem : n)
{
weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
if (weight >= default_formatter_line_wrap)
break;
}
return weight;
}
case node_type::string:
{
auto& n = *reinterpret_cast<const value<std::string>*>(&node);
return n.get().length() + 2_sz; // + ""
}
case node_type::integer:
{
auto& n = *reinterpret_cast<const value<int64_t>*>(&node);
auto v = n.get();
if (!v)
return 1_sz;
size_t weight = {};
if (v < 0)
{
weight += 1;
v *= -1;
}
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
}
case node_type::floating_point:
{
auto& n = *reinterpret_cast<const value<double>*>(&node);
auto v = n.get();
if (v == 0.0)
return 3_sz; // "0.0"
size_t weight = 2_sz; // ".0"
if (v < 0.0)
{
weight += 1;
v *= -1.0;
}
return weight + static_cast<size_t>(log10(v)) + 1_sz;
break;
}
case node_type::boolean: return 5_sz;
case node_type::date: [[fallthrough]];
case node_type::time: return 10_sz;
case node_type::date_time: return 30_sz;
case node_type::none: TOML_UNREACHABLE;
default: TOML_UNREACHABLE;
}
TOML_UNREACHABLE;
}
TOML_EXTERNAL_LINKAGE
bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias) noexcept
{
return (default_formatter_inline_columns(node) + starting_column_bias) >= default_formatter_line_wrap;
}
}
TOML_IMPL_NAMESPACE_END;
TOML_NAMESPACE_START
{
template <typename Char>
inline void default_formatter<Char>::print_inline(const toml::table& tbl)
{
if (tbl.empty())
impl::print_to_stream("{}"sv, base::stream());
else
{
impl::print_to_stream("{ "sv, base::stream());
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
impl::print_to_stream(", "sv, base::stream());
first = true;
print_key_segment(k);
impl::print_to_stream(" = "sv, base::stream());
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
impl::print_to_stream(" }"sv, base::stream());
}
base::clear_naked_newline();
}
}
TOML_NAMESPACE_END;
// implementations of windows wide string nonsense
#if TOML_WINDOWS_COMPAT
#ifndef _WINDOWS_
#if TOML_INCLUDE_WINDOWS_H
#include <Windows.h>
#else
extern "C" {
__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int CodePage,
unsigned long dwFlags,
const wchar_t* lpWideCharStr,
int cchWideChar,
char* lpMultiByteStr,
int cbMultiByte,
const char* lpDefaultChar,
int* lpUsedDefaultChar);
__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage,
unsigned long dwFlags,
const char* lpMultiByteStr,
int cbMultiByte,
wchar_t* lpWideCharStr,
int cchWideChar);
}
#endif
#endif // _WINDOWS_
TOML_IMPL_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
std::string narrow(std::wstring_view str) noexcept
{
if (str.empty())
return {};
std::string s;
const auto len =
::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (len)
{
s.resize(static_cast<size_t>(len));
::WideCharToMultiByte(65001,
0,
str.data(),
static_cast<int>(str.length()),
s.data(),
len,
nullptr,
nullptr);
}
return s;
}
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::string_view str) noexcept
{
if (str.empty())
return {};
std::wstring s;
const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (len)
{
s.resize(static_cast<size_t>(len));
::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
}
return s;
}
#if TOML_HAS_CHAR8
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::u8string_view str) noexcept
{
if (str.empty())
return {};
return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
}
#endif // TOML_HAS_CHAR8
}
TOML_IMPL_NAMESPACE_END;
#endif // TOML_WINDOWS_COMPAT
TOML_POP_WARNINGS;
/// \endcond

View File

@ -2,48 +2,66 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/// \cond
#pragma once
#include "print_to_stream.h"
#if TOML_PARSER && !TOML_EXCEPTIONS
#include "parse_result.h"
#endif
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
template <typename Char = char>
class TOML_API formatter
struct formatter_constants
{
format_flags mandatory_flags;
format_flags ignored_flags;
std::string_view float_pos_inf;
std::string_view float_neg_inf;
std::string_view float_nan;
std::string_view bool_true;
std::string_view bool_false;
};
struct formatter_config
{
format_flags flags;
std::string_view indent;
};
class formatter
{
private:
const toml::node* source_;
std::basic_ostream<Char>* stream_ = {};
format_flags flags_;
int indent_;
bool naked_newline_;
#if TOML_PARSER && !TOML_EXCEPTIONS
const parse_result* result_ = {};
const node* source_;
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
const parse_result* result_;
#endif
const formatter_constants* constants_;
formatter_config config_;
size_t indent_columns_;
format_flags int_format_mask_;
std::ostream* stream_; //
int indent_; // these are set in attach()
bool naked_newline_; //
protected:
TOML_NODISCARD
const toml::node& source() const noexcept
TOML_PURE_INLINE_GETTER
const node& source() const noexcept
{
return *source_;
}
TOML_NODISCARD
std::basic_ostream<Char>& stream() const noexcept
TOML_PURE_INLINE_GETTER
std::ostream& stream() const noexcept
{
return *stream_;
}
static constexpr size_t indent_columns = 4;
static constexpr std::string_view indent_string = " "sv;
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
int indent() const noexcept
{
return indent_;
@ -64,232 +82,104 @@ TOML_IMPL_NAMESPACE_START
indent_--;
}
TOML_NODISCARD
bool quote_dates_and_times() const noexcept
TOML_PURE_INLINE_GETTER
size_t indent_columns() const noexcept
{
return (flags_ & format_flags::quote_dates_and_times) != format_flags::none;
return indent_columns_;
}
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
bool indent_array_elements() const noexcept
{
return !!(config_.flags & format_flags::indent_array_elements);
}
TOML_PURE_INLINE_GETTER
bool indent_sub_tables() const noexcept
{
return !!(config_.flags & format_flags::indent_sub_tables);
}
TOML_PURE_INLINE_GETTER
bool literal_strings_allowed() const noexcept
{
return (flags_ & format_flags::allow_literal_strings) != format_flags::none;
return !!(config_.flags & format_flags::allow_literal_strings);
}
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
bool multi_line_strings_allowed() const noexcept
{
return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
return !!(config_.flags & format_flags::allow_multi_line_strings);
}
TOML_PURE_INLINE_GETTER
bool real_tabs_in_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
}
TOML_PURE_INLINE_GETTER
bool unicode_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_unicode_strings);
}
TOML_API
void attach(std::ostream& stream) noexcept;
TOML_API
void detach() noexcept;
TOML_API
void print_newline(bool force = false);
TOML_API
void print_indent();
TOML_API
void print_unformatted(char);
TOML_API
void print_unformatted(std::string_view);
TOML_API
void print_string(std::string_view str, bool allow_multi_line = true, bool allow_bare = false);
TOML_API
void print(const value<std::string>&);
TOML_API
void print(const value<int64_t>&);
TOML_API
void print(const value<double>&);
TOML_API
void print(const value<bool>&);
TOML_API
void print(const value<date>&);
TOML_API
void print(const value<time>&);
TOML_API
void print(const value<date_time>&);
TOML_API
void print_value(const node&, node_type);
TOML_NODISCARD
bool value_format_flags_allowed() const noexcept
{
return (flags_ & format_flags::allow_value_format_flags) != format_flags::none;
}
TOML_API
bool dump_failed_parse_result();
TOML_NODISCARD
bool naked_newline() const noexcept
{
return naked_newline_;
}
void clear_naked_newline() noexcept
{
naked_newline_ = false;
}
void attach(std::basic_ostream<Char>& stream) noexcept
{
indent_ = {};
naked_newline_ = true;
stream_ = &stream;
}
void detach() noexcept
{
stream_ = nullptr;
}
void print_newline(bool force = false)
{
if (!naked_newline_ || force)
{
print_to_stream('\n', *stream_);
naked_newline_ = true;
}
}
void print_indent()
{
for (int i = 0; i < indent_; i++)
{
print_to_stream(indent_string, *stream_);
naked_newline_ = false;
}
}
void print_quoted_string(std::string_view str, bool allow_multi_line = true)
{
auto literals = literal_strings_allowed();
if (str.empty())
{
print_to_stream(literals ? "''"sv : "\"\""sv, *stream_);
clear_naked_newline();
return;
}
auto multi_line = allow_multi_line && multi_line_strings_allowed();
if (multi_line || literals)
{
utf8_decoder decoder;
bool has_line_breaks = false;
bool has_control_chars = false;
bool has_single_quotes = false;
for (size_t i = 0; i < str.length() && !(has_line_breaks && has_control_chars && has_single_quotes);
i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
{
has_line_breaks = false;
has_control_chars = true; // force ""
has_single_quotes = true;
break;
}
else if (decoder.has_code_point())
{
if (is_line_break(decoder.codepoint))
has_line_breaks = true;
else if (is_nontab_control_character(decoder.codepoint))
has_control_chars = true;
else if (decoder.codepoint == U'\'')
has_single_quotes = true;
}
}
multi_line = multi_line && has_line_breaks;
literals = literals && !has_control_chars && !(!multi_line && has_single_quotes);
}
if (literals)
{
const auto quot = multi_line ? "'''"sv : "'"sv;
print_to_stream(quot, *stream_);
print_to_stream(str, *stream_);
print_to_stream(quot, *stream_);
}
else
{
const auto quot = multi_line ? R"(""")"sv : R"(")"sv;
print_to_stream(quot, *stream_);
print_to_stream_with_escapes(str, *stream_);
print_to_stream(quot, *stream_);
}
clear_naked_newline();
}
template <typename T>
void print(const value<T>& val)
{
if constexpr (std::is_same_v<T, std::string>)
{
print_quoted_string(val.get());
}
else
{
if constexpr (is_one_of<T, date, time, date_time>)
{
if (quote_dates_and_times())
{
const auto quot = literal_strings_allowed() ? '\'' : '"';
print_to_stream(quot, *stream_);
print_to_stream(*val, *stream_);
print_to_stream(quot, *stream_);
}
else
print_to_stream(*val, *stream_);
}
else if constexpr (is_one_of<T, int64_t /*, double*/>)
{
if (value_format_flags_allowed() && *val >= 0)
{
const auto fmt = val.flags() & value_flags::format_as_hexadecimal;
if (fmt != value_flags::none)
{
switch (fmt)
{
case value_flags::format_as_binary: print_to_stream("0b"sv, *stream_); break;
case value_flags::format_as_octal: print_to_stream("0o"sv, *stream_); break;
case value_flags::format_as_hexadecimal: print_to_stream("0x"sv, *stream_); break;
default: TOML_UNREACHABLE;
}
print_to_stream(*val, *stream_, fmt);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
naked_newline_ = false;
}
}
void print_value(const node& val_node, node_type type)
{
TOML_ASSUME(type > node_type::array);
switch (type)
{
case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
default: TOML_UNREACHABLE;
}
}
TOML_NODISCARD
bool dump_failed_parse_result()
{
#if TOML_PARSER && !TOML_EXCEPTIONS
if (result_ && !(*result_))
{
stream() << result_->error();
return true;
}
#endif
return false;
}
formatter(const toml::node& source, format_flags flags) noexcept //
: source_{ &source },
flags_{ flags }
{}
#if TOML_PARSER && !TOML_EXCEPTIONS
formatter(const parse_result& result, format_flags flags) noexcept //
: source_{ result ? &result.table() : nullptr },
flags_{ flags },
result_{ &result }
{}
#endif
TOML_NODISCARD_CTOR
TOML_API
formatter(const node*, const parse_result*, const formatter_constants&, const formatter_config&) noexcept;
};
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template class TOML_API formatter<char>;
#endif
}
TOML_IMPL_NAMESPACE_END;
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
/// \endcond
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,513 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "print_to_stream.h"
#include "value.h"
#include "table.h"
#include "array.h"
#include "unicode.h"
#include "parse_result.h"
#include "header_start.h"
TOML_IMPL_NAMESPACE_START
{
enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
{
none,
line_breaks = 1u << 0, // \n
tabs = 1u << 1, // \t
control_chars = 1u << 2, // also includes non-ascii vertical whitespace
single_quotes = 1u << 3,
non_bare = 1u << 4, // anything not satisfying "is bare key character"
non_ascii = 1u << 5, // any codepoint >= 128
all = (non_ascii << 1u) - 1u
};
TOML_MAKE_FLAGS(formatted_string_traits);
TOML_EXTERNAL_LINKAGE
formatter::formatter(const node* source_node,
const parse_result* source_pr,
const formatter_constants& constants,
const formatter_config& config) noexcept //
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
: source_{ source_pr && *source_pr ? &source_pr->table() : source_node },
result_{ source_pr },
#else
: source_{ source_pr ? source_pr : source_node },
#endif
constants_{ &constants },
config_{ config }
{
TOML_ASSERT_ASSUME(source_);
config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
indent_columns_ = {};
for (auto c : config_.indent)
indent_columns_ += c == '\t' ? 4u : 1u;
int_format_mask_ = config_.flags
& (format_flags::allow_binary_integers | format_flags::allow_octal_integers
| format_flags::allow_hexadecimal_integers);
}
TOML_EXTERNAL_LINKAGE
void formatter::attach(std::ostream & stream) noexcept
{
indent_ = {};
naked_newline_ = true;
stream_ = &stream;
}
TOML_EXTERNAL_LINKAGE
void formatter::detach() noexcept
{
stream_ = nullptr;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_newline(bool force)
{
if (!naked_newline_ || force)
{
print_to_stream(*stream_, '\n');
naked_newline_ = true;
}
}
TOML_EXTERNAL_LINKAGE
void formatter::print_indent()
{
for (int i = 0; i < indent_; i++)
{
print_to_stream(*stream_, config_.indent);
naked_newline_ = false;
}
}
TOML_EXTERNAL_LINKAGE
void formatter::print_unformatted(char c)
{
print_to_stream(*stream_, c);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_unformatted(std::string_view str)
{
print_to_stream(*stream_, str);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
{
if (str.empty())
{
print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
return;
}
// pre-scan the string to determine how we should output it
formatted_string_traits traits = {};
if (!allow_bare)
traits |= formatted_string_traits::non_bare;
bool unicode_allowed = unicode_strings_allowed();
// ascii fast path
if (is_ascii(str.data(), str.length()))
{
for (auto c : str)
{
switch (c)
{
case '\n': traits |= formatted_string_traits::line_breaks; break;
case '\t': traits |= formatted_string_traits::tabs; break;
case '\'': traits |= formatted_string_traits::single_quotes; break;
default:
{
if TOML_UNLIKELY(is_control_character(c))
traits |= formatted_string_traits::control_chars;
if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
traits |= formatted_string_traits::non_bare;
break;
}
}
static constexpr auto all_ascii_traits =
formatted_string_traits::all & ~formatted_string_traits::non_ascii;
if (traits == all_ascii_traits)
break;
}
}
// unicode slow path
else
{
traits |= formatted_string_traits::non_ascii;
utf8_decoder decoder;
// if the unicode is malformed just treat the string as a single-line non-literal and
// escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
const auto bad_unicode = [&]() noexcept
{
traits &= ~formatted_string_traits::line_breaks;
traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
unicode_allowed = false;
};
for (auto c : str)
{
decoder(c);
if TOML_UNLIKELY(decoder.error())
{
bad_unicode();
break;
}
if (!decoder.has_code_point())
continue;
switch (decoder.codepoint)
{
case U'\n': traits |= formatted_string_traits::line_breaks; break;
case U'\t': traits |= formatted_string_traits::tabs; break;
case U'\'': traits |= formatted_string_traits::single_quotes; break;
default:
{
if TOML_UNLIKELY(is_control_character(decoder.codepoint)
|| is_non_ascii_vertical_whitespace(decoder.codepoint))
traits |= formatted_string_traits::control_chars;
if (!is_bare_key_character(decoder.codepoint))
traits |= formatted_string_traits::non_bare;
break;
}
}
}
if (decoder.needs_more_input())
bad_unicode();
}
// if the string meets the requirements of being 'bare' we can emit a bare string
// (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
if (!(traits & formatted_string_traits::non_bare)
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
{
print_unformatted(str);
return;
}
// determine if this should be a multi-line string (triple-quotes)
const auto multi_line = allow_multi_line //
&& multi_line_strings_allowed() //
&& !!(traits & formatted_string_traits::line_breaks);
// determine if this should be a literal string (single-quotes with no escaping)
const auto literal = literal_strings_allowed() //
&& !(traits & formatted_string_traits::control_chars) //
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
&& (!(traits & formatted_string_traits::tabs) || real_tabs_in_strings_allowed()) //
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
// literal strings (single quotes, no escape codes)
if (literal)
{
const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
print_unformatted(quot);
print_unformatted(str);
print_unformatted(quot);
return;
}
// anything from here down is a non-literal string, so requires iteration and escaping.
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
const auto real_tabs_allowed = real_tabs_in_strings_allowed();
// ascii fast path
if (!(traits & formatted_string_traits::non_ascii))
{
for (auto c : str)
{
switch (c)
{
case '"': print_to_stream(*stream_, R"(\")"sv); break;
case '\\': print_to_stream(*stream_, R"(\\)"sv); break;
case '\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
case '\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
case '\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
default:
{
// control characters from lookup table
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
print_to_stream(*stream_, control_char_escapes[c]);
// regular characters
else
print_to_stream(*stream_, c);
}
}
}
}
// unicode slow path
else
{
utf8_decoder decoder;
const char* cp_start = str.data();
const char* cp_end = cp_start;
for (auto c : str)
{
decoder(c);
cp_end++;
// if the decoder encounters malformed unicode just emit raw bytes and
if (decoder.error())
{
while (cp_start != cp_end)
{
print_to_stream(*stream_, R"(\u00)"sv);
print_to_stream(*stream_,
static_cast<uint8_t>(*cp_start),
value_flags::format_as_hexadecimal,
2);
cp_start++;
}
decoder.reset();
continue;
}
if (!decoder.has_code_point())
continue;
switch (decoder.codepoint)
{
case U'"': print_to_stream(*stream_, R"(\")"sv); break;
case U'\\': print_to_stream(*stream_, R"(\\)"sv); break;
case U'\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
case U'\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
case U'\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
default:
{
// control characters from lookup table
if TOML_UNLIKELY(decoder.codepoint <= U'\x1F')
print_to_stream(*stream_,
control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
// escaped unicode characters
else if (decoder.codepoint > U'\x7F'
&& (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint)))
{
if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
{
print_to_stream(*stream_, R"(\U)"sv);
print_to_stream(*stream_,
static_cast<uint_least32_t>(decoder.codepoint),
value_flags::format_as_hexadecimal,
8);
}
else
{
print_to_stream(*stream_, R"(\u)"sv);
print_to_stream(*stream_,
static_cast<uint_least32_t>(decoder.codepoint),
value_flags::format_as_hexadecimal,
4);
}
}
// regular characters
else
print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
}
}
cp_start = cp_end;
}
}
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<std::string>& val)
{
print_string(val.get());
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<int64_t>& val)
{
naked_newline_ = false;
if (*val >= 0 && !!int_format_mask_)
{
static constexpr auto value_flags_mask =
value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
const auto fmt = val.flags() & value_flags_mask;
switch (fmt)
{
case value_flags::format_as_binary:
if (!!(int_format_mask_ & format_flags::allow_binary_integers))
{
print_to_stream(*stream_, "0b"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
case value_flags::format_as_octal:
if (!!(int_format_mask_ & format_flags::allow_octal_integers))
{
print_to_stream(*stream_, "0o"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
case value_flags::format_as_hexadecimal:
if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
{
print_to_stream(*stream_, "0x"sv);
print_to_stream(*stream_, *val, fmt);
return;
}
break;
default: break;
}
}
// fallback to decimal
print_to_stream(*stream_, *val);
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<double>& val)
{
const std::string_view* inf_nan = nullptr;
switch (fpclassify(*val))
{
case fp_class::neg_inf: inf_nan = &constants_->float_neg_inf; break;
case fp_class::pos_inf: inf_nan = &constants_->float_pos_inf; break;
case fp_class::nan: inf_nan = &constants_->float_nan; break;
case fp_class::ok:
print_to_stream(*stream_,
*val,
value_flags::none,
!!(config_.flags & format_flags::relaxed_float_precision));
break;
default: TOML_UNREACHABLE;
}
if (inf_nan)
{
if (!!(config_.flags & format_flags::quote_infinities_and_nans))
print_to_stream_bookended(*stream_, *inf_nan, '"');
else
print_to_stream(*stream_, *inf_nan);
}
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<bool>& val)
{
print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<date>& val)
{
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<time>& val)
{
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print(const value<date_time>& val)
{
if (!!(config_.flags & format_flags::quote_dates_and_times))
print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
else
print_to_stream(*stream_, *val);
naked_newline_ = false;
}
TOML_EXTERNAL_LINKAGE
void formatter::print_value(const node& val_node, node_type type)
{
TOML_ASSUME(type > node_type::array);
switch (type)
{
case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
default: TOML_UNREACHABLE;
}
}
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
bool formatter::dump_failed_parse_result()
{
if (result_ && !(*result_))
{
stream() << result_->error();
return true;
}
return false;
}
#else
TOML_EXTERNAL_LINKAGE
TOML_ATTR(const)
bool formatter::dump_failed_parse_result()
{
return false;
}
#endif
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,10 @@
//# {{
#ifdef __INTELLISENSE__
#include "preprocessor.h"
#endif
//# }}
#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#endif
TOML_POP_WARNINGS;

View File

@ -0,0 +1,12 @@
//# {{
#ifdef __INTELLISENSE__
#include "preprocessor.h"
#endif
//# }}
TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

View File

@ -2,19 +2,20 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "formatter.h"
#include "table.h"
#include "array.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
@ -25,7 +26,6 @@ TOML_NAMESPACE_START
/// smooth = true
/// )"sv);
/// std::cout << toml::json_formatter{ some_toml } << "\n";
///
/// \ecpp
///
/// \out
@ -43,71 +43,40 @@ TOML_NAMESPACE_START
/// }
/// }
/// \eout
///
/// \tparam Char The underlying character type of the output stream. Must be 1 byte in size.
template <typename Char = char>
class TOML_API json_formatter final : impl::formatter<Char>
class json_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter<Char>;
using base = impl::formatter;
void print(const toml::table& tbl);
TOML_API
void print(const toml::table&);
void print(const array& arr)
{
if (arr.empty())
impl::print_to_stream("[]"sv, base::stream());
else
{
impl::print_to_stream('[', base::stream());
base::increase_indent();
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0_sz)
impl::print_to_stream(',', base::stream());
base::print_newline(true);
base::print_indent();
TOML_API
void print(const toml::array&);
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::decrease_indent();
base::print_newline(true);
base::print_indent();
impl::print_to_stream(']', base::stream());
}
base::clear_naked_newline();
}
TOML_API
void print();
void print()
{
if (base::dump_failed_parse_result())
return;
switch (auto source_type = base::source().type())
{
case node_type::table: print(*reinterpret_cast<const table*>(&base::source())); break;
case node_type::array: print(*reinterpret_cast<const array*>(&base::source())); break;
default: base::print_value(base::source(), source_type);
}
}
static constexpr impl::formatter_constants constants = {
format_flags::quote_dates_and_times, // mandatory
format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
"Infinity"sv,
"-Infinity"sv,
"NaN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a json_formatter.
static constexpr format_flags default_flags = format_flags::quote_dates_and_times;
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::quote_infinities_and_nans //
| format_flags::allow_unicode_strings //
| format_flags::indentation;
/// \brief Constructs a JSON formatter and binds it to a TOML object.
///
@ -115,10 +84,10 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, flags }
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a JSON formatter and binds it to a toml::parse_result.
///
@ -146,50 +115,28 @@ TOML_NAMESPACE_START
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ result, flags }
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
template <typename T, typename U>
friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>&, json_formatter<U>&);
template <typename T, typename U>
friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>&, json_formatter<U>&&);
/// \brief Prints the bound TOML object out to the stream as JSON.
friend std::ostream& operator<<(std::ostream& lhs, json_formatter& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, json_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template class TOML_API json_formatter<char>;
#endif
json_formatter(const table&)->json_formatter<char>;
json_formatter(const array&)->json_formatter<char>;
template <typename T>
json_formatter(const value<T>&) -> json_formatter<char>;
/// \brief Prints the bound TOML object out to the stream as JSON.
template <typename T, typename U>
inline std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, json_formatter<U>& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
template <typename T, typename U>
inline std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, json_formatter<U>&& rhs)
{
return lhs << rhs; // as lvalue
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, json_formatter<char>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, json_formatter<char>&&);
#endif
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,118 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "json_formatter.h"
#include "print_to_stream.h"
#include "table.h"
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void json_formatter::print(const toml::table& tbl)
{
if (tbl.empty())
{
print_unformatted("{}"sv);
return;
}
print_unformatted('{');
if (indent_sub_tables())
increase_indent();
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
print_unformatted(',');
first = true;
print_newline(true);
print_indent();
print_string(k.str(), false);
print_unformatted(" : "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: print_value(v, type);
}
}
if (indent_sub_tables())
decrease_indent();
print_newline(true);
print_indent();
print_unformatted('}');
}
TOML_EXTERNAL_LINKAGE
void json_formatter::print(const toml::array& arr)
{
if (arr.empty())
{
print_unformatted("[]"sv);
return;
}
print_unformatted('[');
if (indent_array_elements())
increase_indent();
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
print_unformatted(',');
print_newline(true);
print_indent();
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: print_value(v, type);
}
}
if (indent_array_elements())
decrease_indent();
print_newline(true);
print_indent();
print_unformatted(']');
}
TOML_EXTERNAL_LINKAGE
void json_formatter::print()
{
if (dump_failed_parse_result())
return;
switch (auto source_type = source().type())
{
case node_type::table: print(*reinterpret_cast<const table*>(&source())); break;
case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
default: print_value(source(), source_type);
}
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -1,65 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "json_formatter.h"
/// \cond
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_NAMESPACE_START
{
template <typename Char>
inline void json_formatter<Char>::print(const toml::table& tbl)
{
if (tbl.empty())
impl::print_to_stream("{}"sv, base::stream());
else
{
impl::print_to_stream('{', base::stream());
base::increase_indent();
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
impl::print_to_stream(", "sv, base::stream());
first = true;
base::print_newline(true);
base::print_indent();
base::print_quoted_string(k, false);
impl::print_to_stream(" : "sv, base::stream());
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: base::print_value(v, type);
}
}
base::decrease_indent();
base::print_newline(true);
base::print_indent();
impl::print_to_stream('}', base::stream());
}
base::clear_naked_newline();
}
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS;
/// \endcond

335
include/toml++/impl/key.h Normal file
View File

@ -0,0 +1,335 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "source_region.h"
#include "std_utility.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A key parsed from a TOML document.
///
/// \detail These are used as the internal keys for a toml::table: \cpp
/// const toml::table tbl = R"(
/// a = 1
/// b = 2
/// c = 3
/// )"_toml;
///
/// for (auto&& [k, v] : tbl)
/// std::cout << "key '"sv << k << "' defined at "sv << k.source() << "\n";
/// \ecpp
/// \out
/// key 'a' defined at line 2, column 5
/// key 'b' defined at line 3, column 7
/// key 'c' defined at line 4, column 9
/// \eout
class key
{
private:
std::string key_;
source_region source_;
public:
/// A const iterator for iterating over the characters in the key.
using const_iterator = const char*;
/// A const iterator for iterating over the characters in the key.
using iterator = const_iterator;
/// \brief Default constructor.
TOML_NODISCARD_CTOR
key() noexcept = default;
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, const source_region& src) //
: key_{ k },
source_{ src }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, source_region&& src = {}) noexcept //
: key_{ std::move(k) },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, const source_region& src) noexcept //
: key_{ std::move(k) },
source_{ src }
{}
/// \brief Constructs a key from a c-string and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a c-string view and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, const source_region& src) //
: key_{ k },
source_{ src }
{}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Constructs a key from a wide string view and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, source_region&& src = {}) //
: key_{ impl::narrow(k) },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a wide string and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, const source_region& src) //
: key_{ impl::narrow(k) },
source_{ src }
{}
#endif
/// \name String operations
/// @{
/// \brief Returns a view of the key's underlying string.
TOML_PURE_INLINE_GETTER
std::string_view str() const noexcept
{
return std::string_view{ key_ };
}
/// \brief Returns a view of the key's underlying string.
TOML_PURE_INLINE_GETTER
/*implicit*/ operator std::string_view() const noexcept
{
return str();
}
/// \brief Returns true if the key's underlying string is empty.
TOML_PURE_INLINE_GETTER
bool empty() const noexcept
{
return key_.empty();
}
/// \brief Returns a pointer to the start of the key's underlying string.
TOML_PURE_INLINE_GETTER
const char* data() const noexcept
{
return key_.data();
}
/// \brief Returns the length of the key's underlying string.
TOML_PURE_INLINE_GETTER
size_t length() const noexcept
{
return key_.length();
}
/// @}
/// \name Metadata
/// @{
/// \brief Returns the source region responsible for specifying this key during parsing.
TOML_PURE_INLINE_GETTER
const source_region& source() const noexcept
{
return source_;
}
/// @}
/// \name Equality and Comparison
/// \attention These operations only compare the underlying strings; source regions are ignored for the purposes of all comparison!
/// @{
/// \brief Returns true if `lhs.str() == rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator==(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ == rhs.key_;
}
/// \brief Returns true if `lhs.str() != rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ != rhs.key_;
}
/// \brief Returns true if `lhs.str() < rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ < rhs.key_;
}
/// \brief Returns true if `lhs.str() <= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ <= rhs.key_;
}
/// \brief Returns true if `lhs.str() > rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ > rhs.key_;
}
/// \brief Returns true if `lhs.str() >= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ >= rhs.key_;
}
/// \brief Returns true if `lhs.str() == rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator==(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ == rhs;
}
/// \brief Returns true if `lhs.str() != rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ != rhs;
}
/// \brief Returns true if `lhs.str() < rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator<(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ < rhs;
}
/// \brief Returns true if `lhs.str() <= rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ <= rhs;
}
/// \brief Returns true if `lhs.str() > rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator>(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ > rhs;
}
/// \brief Returns true if `lhs.str() >= rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ >= rhs;
}
/// \brief Returns true if `lhs == rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator==(std::string_view lhs, const key& rhs) noexcept
{
return lhs == rhs.key_;
}
/// \brief Returns true if `lhs != rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(std::string_view lhs, const key& rhs) noexcept
{
return lhs != rhs.key_;
}
/// \brief Returns true if `lhs < rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<(std::string_view lhs, const key& rhs) noexcept
{
return lhs < rhs.key_;
}
/// \brief Returns true if `lhs <= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(std::string_view lhs, const key& rhs) noexcept
{
return lhs <= rhs.key_;
}
/// \brief Returns true if `lhs > rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>(std::string_view lhs, const key& rhs) noexcept
{
return lhs > rhs.key_;
}
/// \brief Returns true if `lhs >= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(std::string_view lhs, const key& rhs) noexcept
{
return lhs >= rhs.key_;
}
/// @}
/// \name Iterators
/// @{
/// \brief Returns an iterator to the first character in the key's backing string.
TOML_PURE_INLINE_GETTER
const_iterator begin() const noexcept
{
return key_.data();
}
/// \brief Returns an iterator to one-past-the-last character in the key's backing string.
TOML_PURE_INLINE_GETTER
const_iterator end() const noexcept
{
return key_.data() + key_.length();
}
/// @}
/// \brief Prints the key's underlying string out to the stream.
friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
{
impl::print_to_stream(lhs, rhs.key_);
return lhs;
}
};
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::key.
template <typename T>
inline constexpr bool is_key = std::is_same_v<impl::remove_cvref<T>, toml::key>;
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::key,
/// or is implicitly or explicitly convertible to one.
template <typename T>
inline constexpr bool is_key_or_convertible =
is_key<T> || std::is_constructible_v<toml::key, T> || std::is_convertible_v<T, toml::key>;
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,159 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "forward_declarations.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
template <typename T>
TOML_NODISCARD
TOML_ATTR(returns_nonnull)
auto* make_node_impl_specialized(T && val, [[maybe_unused]] value_flags flags)
{
using unwrapped_type = unwrap_node<remove_cvref<T>>;
static_assert(!std::is_same_v<unwrapped_type, node>);
static_assert(!is_node_view<unwrapped_type>);
// arrays + tables - invoke copy/move ctor
if constexpr (is_one_of<unwrapped_type, array, table>)
{
return new unwrapped_type(static_cast<T&&>(val));
}
// values
else
{
using native_type = native_type_of<unwrapped_type>;
using value_type = value<native_type>;
value_type* out;
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{
out = new value_type{ static_cast<T&&>(val) };
}
// creating from raw value
else
{
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Instantiating values from wide-character strings is only "
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>)
{
if constexpr (std::is_same_v<native_type, int64_t>)
static_assert(dependent_false<T>,
"Integral value initializers must be losslessly convertible to int64_t");
else if constexpr (std::is_same_v<native_type, double>)
static_assert(dependent_false<T>,
"Floating-point value initializers must be losslessly convertible to double");
else
static_assert(
dependent_false<T>,
"Value initializers must be losslessly convertible to one of the TOML value types");
}
if constexpr (is_wide_string<T>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
out = new value_type{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
out = new value_type{ static_cast<T&&>(val) };
}
if (flags != preserve_source_value_flags)
out->flags(flags);
return out;
}
}
template <typename T>
TOML_NODISCARD
auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags)
{
using unwrapped_type = unwrap_node<remove_cvref<T>>;
if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
{
if constexpr (is_node_view<unwrapped_type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit(
[flags](auto&& concrete) {
return static_cast<toml::node*>(
make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
});
}
else
return make_node_impl_specialized(static_cast<T&&>(val), flags);
}
template <typename T>
TOML_NODISCARD
auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags)
{
return make_node_impl(static_cast<T&&>(val.value), flags);
}
template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
struct inserted_type_of_
{
using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
};
template <typename T>
struct inserted_type_of_<inserter<T>, false>
{
using type = typename inserted_type_of_<T>::type;
};
template <typename T>
struct inserted_type_of_<T, false>
{
using type = void;
};
template <typename T>
TOML_NODISCARD
node_ptr make_node(T && val, value_flags flags = preserve_source_value_flags)
{
return node_ptr{ make_node_impl(static_cast<T&&>(val), flags) };
}
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
TOML_NAMESPACE_START
{
/// \brief Metafunction for determining which node type would be constructed
/// if an object of this type was inserted into a toml::table or toml::array.
///
/// \detail \cpp
/// static_assert(std::is_same_v<toml::inserted_type_of<const char*>, toml::value<std::string>);
/// static_assert(std::is_same_v<toml::inserted_type_of<int>, toml::value<int64_t>);
/// static_assert(std::is_same_v<toml::inserted_type_of<float>, toml::value<double>);
/// static_assert(std::is_same_v<toml::inserted_type_of<bool>, toml::value<bool>);
/// \ecpp
///
/// \note This will return toml::node for nodes and node_views, even though a more specific node subclass
/// would actually be inserted. There is no way around this in a compile-time metafunction.
template <typename T>
using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -2,9 +2,12 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "common.h"
#include "std_utility.h"
#include "forward_declarations.h"
#include "source_region.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
@ -12,209 +15,129 @@ TOML_NAMESPACE_START
///
/// \detail A parsed TOML document forms a tree made up of tables, arrays and values.
/// This type is the base of each of those, providing a lot of the polymorphic plumbing.
class TOML_ABSTRACT_BASE TOML_API node
class TOML_ABSTRACT_BASE node
{
private:
/// \cond
friend class TOML_PARSER_TYPENAME;
source_region source_{};
/// \cond
template <typename T>
TOML_NODISCARD
decltype(auto) get_value_exact() const noexcept;
decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
template <typename T, typename N>
TOML_NODISCARD
TOML_ATTR(pure)
static decltype(auto) do_ref(N&& n) noexcept
using ref_type_ = std::conditional_t< //
std::is_reference_v<T>, //
impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
impl::copy_cvref<impl::unwrap_node<T>, N> //
>;
template <typename T, typename N>
using ref_type = std::conditional_t< //
std::is_reference_v<N>, //
ref_type_<T, N>, //
ref_type_<T, std::add_lvalue_reference_t<N>> //
>;
template <typename T, typename N>
TOML_PURE_GETTER
static ref_type<T, N&&> do_ref(N&& n) noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<T>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
TOML_ASSERT(
n.template is<T>()
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type");
if constexpr (impl::is_native<type>)
return static_cast<N&&>(n).template ref_cast<type>().get();
TOML_ASSERT_ASSUME(
n.template is<unwrapped_type>()
&& "template type argument provided to toml::node::ref() didn't match the node's actual type");
using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
using val_type = std::remove_volatile_t<unwrapped_type>;
using out_ref = ref_type<T, N&&>;
static_assert(std::is_reference_v<out_ref>);
if constexpr (toml::is_value<unwrapped_type>)
return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
else
return static_cast<N&&>(n).template ref_cast<type>();
return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
}
protected:
node() noexcept = default;
TOML_API
node(const node&) noexcept;
TOML_API
node(node&&) noexcept;
TOML_API
node& operator=(const node&) noexcept;
TOML_API
node& operator=(node&&) noexcept;
template <typename T, typename N>
using ref_cast_type_ = std::conditional_t< //
std::is_reference_v<T>, //
impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
impl::copy_cvref<impl::wrap_node<T>, N> //
>;
template <typename T, typename N>
using ref_cast_type = std::conditional_t< //
std::is_reference_v<N>, //
ref_cast_type_<T, N>, //
ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
>;
template <typename T>
TOML_PURE_INLINE_GETTER
ref_cast_type<T, node&> ref_cast() & noexcept
{
using out_ref = ref_cast_type<T, node&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename T>
TOML_PURE_INLINE_GETTER
ref_cast_type<T, node&&> ref_cast() && noexcept
{
using out_ref = ref_cast_type<T, node&&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename T>
TOML_PURE_INLINE_GETTER
ref_cast_type<T, const node&> ref_cast() const& noexcept
{
using out_ref = ref_cast_type<T, const node&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename T>
TOML_PURE_INLINE_GETTER
ref_cast_type<T, const node&&> ref_cast() const&& noexcept
{
using out_ref = ref_cast_type<T, const node&&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
/// \endcond
protected:
node() noexcept = default;
node(const node&) noexcept;
node(node&&) noexcept;
node& operator=(const node&) noexcept;
node& operator=(node&&) noexcept;
template <typename T>
TOML_NODISCARD
TOML_ALWAYS_INLINE
TOML_ATTR(pure)
impl::wrap_node<T>& ref_cast() & noexcept
{
return *reinterpret_cast<impl::wrap_node<T>*>(this);
}
template <typename T>
TOML_NODISCARD
TOML_ALWAYS_INLINE
TOML_ATTR(pure)
impl::wrap_node<T>&& ref_cast() && noexcept
{
return std::move(*reinterpret_cast<impl::wrap_node<T>*>(this));
}
template <typename T>
TOML_NODISCARD
TOML_ALWAYS_INLINE
TOML_ATTR(pure)
const impl::wrap_node<T>& ref_cast() const& noexcept
{
return *reinterpret_cast<const impl::wrap_node<T>*>(this);
}
template <typename N, typename T>
using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
public:
virtual ~node() noexcept = default;
TOML_API
virtual ~node() noexcept;
/// \name Type checks
/// @{
#if defined(DOXYGEN) || !TOML_ICC || TOML_ICC_CL
/// \brief Returns the node's type identifier.
TOML_NODISCARD
virtual node_type type() const noexcept = 0;
#else
TOML_NODISCARD
virtual node_type type() const noexcept
{
// Q: "what the fuck?"
// A: https://github.com/marzer/tomlplusplus/issues/83
// tl,dr: go home ICC, you're drunk.
return type();
}
#endif
/// \brief Returns true if this node is a table.
TOML_NODISCARD
virtual bool is_table() const noexcept = 0;
/// \brief Returns true if this node is an array.
TOML_NODISCARD
virtual bool is_array() const noexcept = 0;
/// \brief Returns true if this node is a value.
TOML_NODISCARD
virtual bool is_value() const noexcept = 0;
/// \brief Returns true if this node is a string value.
TOML_NODISCARD
virtual bool is_string() const noexcept
{
return false;
}
/// \brief Returns true if this node is an integer value.
TOML_NODISCARD
virtual bool is_integer() const noexcept
{
return false;
}
/// \brief Returns true if this node is an floating-point value.
TOML_NODISCARD
virtual bool is_floating_point() const noexcept
{
return false;
}
/// \brief Returns true if this node is an integer or floating-point value.
TOML_NODISCARD
virtual bool is_number() const noexcept
{
return false;
}
/// \brief Returns true if this node is a boolean value.
TOML_NODISCARD
virtual bool is_boolean() const noexcept
{
return false;
}
/// \brief Returns true if this node is a local date value.
TOML_NODISCARD
virtual bool is_date() const noexcept
{
return false;
}
/// \brief Returns true if this node is a local time value.
TOML_NODISCARD
virtual bool is_time() const noexcept
{
return false;
}
/// \brief Returns true if this node is a date-time value.
TOML_NODISCARD
virtual bool is_date_time() const noexcept
{
return false;
}
/// \brief Returns true if this node is an array containing only tables.
TOML_NODISCARD
virtual bool is_array_of_tables() const noexcept
{
return false;
}
/// \brief Checks if a node is a specific type.
///
/// \tparam T A TOML node or value type.
///
/// \returns Returns true if this node is an instance of the specified type.
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
bool is() const noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
"The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
return is_table();
else if constexpr (std::is_same_v<type, array>)
return is_array();
else if constexpr (std::is_same_v<type, std::string>)
return is_string();
else if constexpr (std::is_same_v<type, int64_t>)
return is_integer();
else if constexpr (std::is_same_v<type, double>)
return is_floating_point();
else if constexpr (std::is_same_v<type, bool>)
return is_boolean();
else if constexpr (std::is_same_v<type, date>)
return is_date();
else if constexpr (std::is_same_v<type, time>)
return is_time();
else if constexpr (std::is_same_v<type, date_time>)
return is_date_time();
}
/// \brief Checks if a node contains values/elements of only one type.
///
/// \detail \cpp
@ -246,11 +169,11 @@ TOML_NAMESPACE_START
/// \returns True if the node was homogeneous.
///
/// \remarks Always returns `false` for empty tables and arrays.
TOML_NODISCARD
TOML_PURE_GETTER
virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
/// \brief Checks if a node contains values/elements of only one type (const overload).
TOML_NODISCARD
TOML_PURE_GETTER
virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
/// \brief Checks if the node contains values/elements of only one type.
@ -261,7 +184,6 @@ TOML_NAMESPACE_START
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
@ -280,7 +202,7 @@ TOML_NAMESPACE_START
/// \returns True if the node was homogeneous.
///
/// \remarks Always returns `false` for empty tables and arrays.
TOML_NODISCARD
TOML_PURE_GETTER
virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
/// \brief Checks if the node contains values/elements of only one type.
@ -291,7 +213,6 @@ TOML_NAMESPACE_START
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
@ -311,17 +232,101 @@ TOML_NAMESPACE_START
///
/// \remarks Always returns `false` for empty tables and arrays.
template <typename ElemType = void>
TOML_NODISCARD
TOML_ATTR(pure)
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<ElemType>;
static_assert(
std::is_void_v<
type> || ((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
"The template type argument of node::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<type>);
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<ElemType>>;
static_assert(std::is_void_v<unwrapped_type> //
|| (toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>),
"The template type argument of node::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<unwrapped_type>);
}
/// \brief Returns the node's type identifier.
TOML_PURE_GETTER
virtual node_type type() const noexcept = 0;
/// \brief Returns true if this node is a table.
TOML_PURE_GETTER
virtual bool is_table() const noexcept = 0;
/// \brief Returns true if this node is an array.
TOML_PURE_GETTER
virtual bool is_array() const noexcept = 0;
/// \brief Returns true if this node is an array containing only tables.
TOML_PURE_GETTER
virtual bool is_array_of_tables() const noexcept = 0;
/// \brief Returns true if this node is a value.
TOML_PURE_GETTER
virtual bool is_value() const noexcept = 0;
/// \brief Returns true if this node is a string value.
TOML_PURE_GETTER
virtual bool is_string() const noexcept = 0;
/// \brief Returns true if this node is an integer value.
TOML_PURE_GETTER
virtual bool is_integer() const noexcept = 0;
/// \brief Returns true if this node is an floating-point value.
TOML_PURE_GETTER
virtual bool is_floating_point() const noexcept = 0;
/// \brief Returns true if this node is an integer or floating-point value.
TOML_PURE_GETTER
virtual bool is_number() const noexcept = 0;
/// \brief Returns true if this node is a boolean value.
TOML_PURE_GETTER
virtual bool is_boolean() const noexcept = 0;
/// \brief Returns true if this node is a local date value.
TOML_PURE_GETTER
virtual bool is_date() const noexcept = 0;
/// \brief Returns true if this node is a local time value.
TOML_PURE_GETTER
virtual bool is_time() const noexcept = 0;
/// \brief Returns true if this node is a date-time value.
TOML_PURE_GETTER
virtual bool is_date_time() const noexcept = 0;
/// \brief Checks if a node is a specific type.
///
/// \tparam T A TOML node or value type.
///
/// \returns Returns true if this node is an instance of the specified type.
template <typename T>
TOML_PURE_INLINE_GETTER
bool is() const noexcept
{
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<unwrapped_type, table>)
return is_table();
else if constexpr (std::is_same_v<unwrapped_type, array>)
return is_array();
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return is_string();
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return is_integer();
else if constexpr (std::is_same_v<unwrapped_type, double>)
return is_floating_point();
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return is_boolean();
else if constexpr (std::is_same_v<unwrapped_type, date>)
return is_date();
else if constexpr (std::is_same_v<unwrapped_type, time>)
return is_time();
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return is_date_time();
}
/// @}
@ -330,121 +335,76 @@ TOML_NAMESPACE_START
/// @{
/// \brief Returns a pointer to the node as a toml::table, if it is one.
TOML_NODISCARD
virtual table* as_table() noexcept
{
return nullptr;
}
TOML_PURE_GETTER
virtual table* as_table() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::array, if it is one.
TOML_NODISCARD
virtual array* as_array() noexcept
{
return nullptr;
}
TOML_PURE_GETTER
virtual array* as_array() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<string>, if it is one.
TOML_NODISCARD
virtual toml::value<std::string>* as_string() noexcept
{
return nullptr;
}
/// \brief Returns a pointer to the node as a toml::value<std::string>, if it is one.
TOML_PURE_GETTER
virtual toml::value<std::string>* as_string() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one.
TOML_NODISCARD
virtual toml::value<int64_t>* as_integer() noexcept
{
return nullptr;
}
TOML_PURE_GETTER
virtual toml::value<int64_t>* as_integer() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<double>, if it is one.
TOML_NODISCARD
virtual toml::value<double>* as_floating_point() noexcept
{
return nullptr;
}
TOML_PURE_GETTER
virtual toml::value<double>* as_floating_point() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<bool>, if it is one.
TOML_NODISCARD
virtual toml::value<bool>* as_boolean() noexcept
{
return nullptr;
}
TOML_PURE_GETTER
virtual toml::value<bool>* as_boolean() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<date>, if it is one.
TOML_NODISCARD
virtual toml::value<date>* as_date() noexcept
{
return nullptr;
}
/// \brief Returns a pointer to the node as a toml::value<toml::date>, if it is one.
TOML_PURE_GETTER
virtual toml::value<date>* as_date() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<time>, if it is one.
TOML_NODISCARD
virtual toml::value<time>* as_time() noexcept
{
return nullptr;
}
/// \brief Returns a pointer to the node as a toml::value<toml::time>, if it is one.
TOML_PURE_GETTER
virtual toml::value<time>* as_time() noexcept = 0;
/// \brief Returns a pointer to the node as a toml::value<date_time>, if it is one.
TOML_NODISCARD
virtual toml::value<date_time>* as_date_time() noexcept
{
return nullptr;
}
/// \brief Returns a pointer to the node as a toml::value<toml::date_time>, if it is one.
TOML_PURE_GETTER
virtual toml::value<date_time>* as_date_time() noexcept = 0;
TOML_NODISCARD
virtual const table* as_table() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::table, if it is one.
TOML_PURE_GETTER
virtual const table* as_table() const noexcept = 0;
TOML_NODISCARD
virtual const array* as_array() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::array, if it is one.
TOML_PURE_GETTER
virtual const array* as_array() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<std::string>* as_string() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<std::string>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<std::string>* as_string() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<int64_t>* as_integer() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<int64_t>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<int64_t>* as_integer() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<double>* as_floating_point() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<double>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<double>* as_floating_point() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<bool>* as_boolean() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<bool>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<bool>* as_boolean() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<date>* as_date() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<date>* as_date() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<time>* as_time() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<toml::time>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<time>* as_time() const noexcept = 0;
TOML_NODISCARD
virtual const toml::value<date_time>* as_date_time() const noexcept
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date_time>, if it is one.
TOML_PURE_GETTER
virtual const toml::value<date_time>* as_date_time() const noexcept = 0;
/// \brief Gets a pointer to the node as a more specific node type.
///
@ -461,68 +421,65 @@ TOML_NAMESPACE_START
/// toml::value<int64_t>* int_value2 = node->as<toml::value<int64_t>>();
/// if (int_value2)
/// std::cout << "Node is a value<int64_t>\n";
///
/// \ecpp
///
/// \tparam T The node type or TOML value type to cast to.
///
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
TOML_PURE_INLINE_GETTER
impl::wrap_node<T>* as() noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
if constexpr (std::is_same_v<unwrapped_type, table>)
return as_table();
else if constexpr (std::is_same_v<type, array>)
else if constexpr (std::is_same_v<unwrapped_type, array>)
return as_array();
else if constexpr (std::is_same_v<type, std::string>)
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return as_string();
else if constexpr (std::is_same_v<type, int64_t>)
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return as_integer();
else if constexpr (std::is_same_v<type, double>)
else if constexpr (std::is_same_v<unwrapped_type, double>)
return as_floating_point();
else if constexpr (std::is_same_v<type, bool>)
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return as_boolean();
else if constexpr (std::is_same_v<type, date>)
else if constexpr (std::is_same_v<unwrapped_type, date>)
return as_date();
else if constexpr (std::is_same_v<type, time>)
else if constexpr (std::is_same_v<unwrapped_type, time>)
return as_time();
else if constexpr (std::is_same_v<type, date_time>)
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return as_date_time();
}
/// \brief Gets a pointer to the node as a more specific node type (const overload).
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
TOML_PURE_INLINE_GETTER
const impl::wrap_node<T>* as() const noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
if constexpr (std::is_same_v<unwrapped_type, table>)
return as_table();
else if constexpr (std::is_same_v<type, array>)
else if constexpr (std::is_same_v<unwrapped_type, array>)
return as_array();
else if constexpr (std::is_same_v<type, std::string>)
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return as_string();
else if constexpr (std::is_same_v<type, int64_t>)
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return as_integer();
else if constexpr (std::is_same_v<type, double>)
else if constexpr (std::is_same_v<unwrapped_type, double>)
return as_floating_point();
else if constexpr (std::is_same_v<type, bool>)
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return as_boolean();
else if constexpr (std::is_same_v<type, date>)
else if constexpr (std::is_same_v<unwrapped_type, date>)
return as_date();
else if constexpr (std::is_same_v<type, time>)
else if constexpr (std::is_same_v<unwrapped_type, time>)
return as_time();
else if constexpr (std::is_same_v<type, date_time>)
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return as_date_time();
}
@ -545,7 +502,7 @@ TOML_NAMESPACE_START
/// \see node::value()
template <typename T>
TOML_NODISCARD
optional<T> value_exact() const noexcept;
optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
/// \brief Gets the value contained by this node.
///
@ -675,7 +632,7 @@ TOML_NAMESPACE_START
/// \see node::value_exact()
template <typename T>
TOML_NODISCARD
optional<T> value() const noexcept;
optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>);
/// \brief Gets the raw value contained by this node, or a default.
///
@ -696,17 +653,9 @@ TOML_NAMESPACE_START
/// - node::value_exact()
template <typename T>
TOML_NODISCARD
auto value_or(T&& default_value) const noexcept;
auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>);
// template <typename T>
// TOML_NODISCARD
// std::vector<T> select_exact() const noexcept;
// template <typename T>
// TOML_NODISCARD
// std::vector<T> select() const noexcept;
/// \brief Gets a raw reference to a value node's underlying data.
/// \brief Gets a raw reference to a node's underlying data.
///
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
/// chosen value type doesn't match the node's actual type. In debug builds an assertion
@ -717,47 +666,61 @@ TOML_NAMESPACE_START
/// max = 45
/// )"sv);
///
/// int64_t& min_ref = tbl.get("min")->ref<int64_t>(); // matching type
/// double& max_ref = tbl.get("max")->ref<double>(); // mismatched type, hits assert()
///
/// int64_t& min_ref = tbl.at("min").ref<int64_t>(); // matching type
/// double& max_ref = tbl.at("max").ref<double>(); // mismatched type, hits assert()
/// \ecpp
///
/// \tparam T One of the TOML value types.
/// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast,
/// whereas specifying explicit cv-ref qualifiers merges them with whatever
/// the cv qualification of the node is (to ensure cv-correctness is propagated), e.g.:
/// | node | T | return type |
/// |-------------|------------------------|------------------------------|
/// | node& | std::string | std::string& |
/// | node& | std::string&& | std::string&& |
/// | const node& | volatile std::string | const volatile std::string& |
/// | const node& | volatile std::string&& | const volatile std::string&& |
///
/// \tparam T toml::table, toml::array, or one of the TOML value types.
///
/// \returns A reference to the underlying data.
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
impl::unwrap_node<T>& ref() & noexcept
TOML_PURE_GETTER
decltype(auto) ref() & noexcept
{
return do_ref<T>(*this);
}
/// \brief Gets a raw reference to a value node's underlying data (rvalue overload).
/// \brief Gets a raw reference to a node's underlying data (rvalue overload).
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
impl::unwrap_node<T>&& ref() && noexcept
TOML_PURE_GETTER
decltype(auto) ref() && noexcept
{
return do_ref<T>(std::move(*this));
}
/// \brief Gets a raw reference to a value node's underlying data (const lvalue overload).
/// \brief Gets a raw reference to a node's underlying data (const lvalue overload).
template <typename T>
TOML_NODISCARD
TOML_ATTR(pure)
const impl::unwrap_node<T>& ref() const& noexcept
TOML_PURE_GETTER
decltype(auto) ref() const& noexcept
{
return do_ref<T>(*this);
}
/// \brief Gets a raw reference to a node's underlying data (const rvalue overload).
template <typename T>
TOML_PURE_GETTER
decltype(auto) ref() const&& noexcept
{
return do_ref<T>(std::move(*this));
}
/// @}
/// \name Metadata
/// @{
/// \brief Returns the source region responsible for generating this node during parsing.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
const source_region& source() const noexcept
{
return source_;
@ -771,7 +734,7 @@ TOML_NAMESPACE_START
// clang-format off
template <typename Func, typename N, typename T>
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, N>>;
template <typename Func, typename N>
static constexpr bool can_visit_any =
@ -800,7 +763,7 @@ TOML_NAMESPACE_START
template <typename Func, typename N, typename T>
static constexpr bool visit_is_nothrow_one =
!can_visit<Func, N, T>
|| std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
|| std::is_nothrow_invocable_v<Func, ref_cast_type<T, N>>;
template <typename Func, typename N>
static constexpr bool visit_is_nothrow =
@ -819,7 +782,7 @@ TOML_NAMESPACE_START
template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
struct visit_return_type_
{
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, N>>()));
};
template <typename Func, typename N, typename T>
struct visit_return_type_<Func, N, T, false>
@ -946,7 +909,6 @@ TOML_NAMESPACE_START
/// else
/// throw std::exception{ "Expected string or integer" };
/// });
///
/// \ecpp
///
/// \tparam Func A callable type invocable with one or more of the
@ -978,6 +940,13 @@ TOML_NAMESPACE_START
return do_visit(*this, static_cast<Func&&>(visitor));
}
/// \brief Invokes a visitor on the node based on the node's concrete type (const rvalue overload).
template <typename Func>
decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>)
{
return do_visit(static_cast<const node&&>(*this), static_cast<Func&&>(visitor));
}
/// @}
/// \name Node views
@ -991,7 +960,55 @@ TOML_NAMESPACE_START
TOML_NODISCARD
explicit operator node_view<const node>() const noexcept;
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<node> at_path(std::string_view path) noexcept;
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<const node> at_path(std::string_view path) const noexcept;
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<node> at_path(std::wstring_view path);
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_API
node_view<const node> at_path(std::wstring_view path) const;
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// @}
};
}
TOML_NAMESPACE_END;
/// \cond
TOML_IMPL_NAMESPACE_START
{
TOML_PURE_GETTER
TOML_API
bool node_deep_equality(const node*, const node*) noexcept;
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,116 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "node.h"
#include "node_view.h"
#include "at_path.h"
#include "table.h"
#include "array.h"
#include "value.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
node::node(node && other) noexcept //
: source_{ std::exchange(other.source_, {}) }
{}
TOML_EXTERNAL_LINKAGE
node::node(const node& /*other*/) noexcept
{
// does not copy source information - this is not an error
//
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
}
TOML_EXTERNAL_LINKAGE
node& node::operator=(const node& /*rhs*/) noexcept
{
// does not copy source information - this is not an error
//
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
source_ = {};
return *this;
}
TOML_EXTERNAL_LINKAGE
node& node::operator=(node&& rhs) noexcept
{
if (&rhs != this)
source_ = std::exchange(rhs.source_, {});
return *this;
}
TOML_EXTERNAL_LINKAGE
node::~node() noexcept = default;
TOML_EXTERNAL_LINKAGE
node_view<node> node::at_path(std::string_view path) noexcept
{
return toml::at_path(*this, path);
}
TOML_EXTERNAL_LINKAGE
node_view<const node> node::at_path(std::string_view path) const noexcept
{
return toml::at_path(*this, path);
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node_view<node> node::at_path(std::wstring_view path)
{
return toml::at_path(*this, path);
}
TOML_EXTERNAL_LINKAGE
node_view<const node> node::at_path(std::wstring_view path) const
{
return toml::at_path(*this, path);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
}
TOML_NAMESPACE_END;
TOML_IMPL_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
bool node_deep_equality(const node* lhs, const node* rhs) noexcept
{
// both same or both null
if (lhs == rhs)
return true;
// lhs null != rhs null or different types
if ((!lhs != !rhs) || lhs->type() != rhs->type())
return false;
bool same;
lhs->visit(
[=, &same](auto& l) noexcept
{
using concrete_type = remove_cvref<decltype(l)>;
same = (l == *(rhs->as<concrete_type>()));
});
return same;
}
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

View File

@ -1,62 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "node.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
node::node(node && other) noexcept //
: source_{ std::exchange(other.source_, {}) }
{}
TOML_EXTERNAL_LINKAGE
node::node(const node& /*other*/) noexcept
{
// does not copy source information - this is not an error
//
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
}
TOML_EXTERNAL_LINKAGE
node& node::operator=(const node& /*rhs*/) noexcept
{
// does not copy source information - this is not an error
//
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
source_ = {};
return *this;
}
TOML_EXTERNAL_LINKAGE
node& node::operator=(node&& rhs) noexcept
{
if (&rhs != this)
source_ = std::exchange(rhs.source_, {});
return *this;
}
TOML_EXTERNAL_LINKAGE
node::operator node_view<node>() noexcept
{
return node_view<node>(this);
}
TOML_EXTERNAL_LINKAGE
node::operator node_view<const node>() const noexcept
{
return node_view<const node>(this);
}
}
TOML_NAMESPACE_END;

View File

@ -2,13 +2,13 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "table.h"
#include "array.h"
#include "value.h"
TOML_PUSH_WARNINGS;
#include "std_vector.h"
#include "std_initializer_list.h"
#include "print_to_stream.h"
#include "node.h"
#include "header_start.h"
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_NAMESPACE_START
@ -57,17 +57,18 @@ TOML_NAMESPACE_START
/// product[2]:
/// \eout
template <typename ViewedType>
class TOML_API TOML_TRIVIAL_ABI node_view
class TOML_TRIVIAL_ABI node_view
{
static_assert(impl::is_one_of<ViewedType, toml::node, const toml::node>,
"A toml::node_view<> must wrap toml::node or const toml::node.");
public:
/// \brief The node type being viewed - either `node` or `const node`.
using viewed_type = ViewedType;
private:
template <typename T>
friend class TOML_NAMESPACE::node_view;
friend class node_view;
mutable viewed_type* node_ = nullptr;
@ -95,25 +96,25 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
node_view(const node_view&) noexcept = default;
/// \brief Copy-assignment operator.
node_view& operator=(const node_view&) & noexcept = default;
/// \brief Move constructor.
TOML_NODISCARD_CTOR
node_view(node_view&&) noexcept = default;
/// \brief Copy-assignment operator.
node_view& operator=(const node_view&) & noexcept = default;
/// \brief Move-assignment operator.
node_view& operator=(node_view&&) & noexcept = default;
/// \brief Returns true if the view references a node.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator bool() const noexcept
{
return node_ != nullptr;
}
/// \brief Returns the node that's being referenced by the view.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
viewed_type* node() const noexcept
{
return node_;
@ -123,91 +124,91 @@ TOML_NAMESPACE_START
/// @{
/// \brief Returns the type identifier for the viewed node.
TOML_NODISCARD
TOML_PURE_GETTER
node_type type() const noexcept
{
return node_ ? node_->type() : node_type::none;
}
/// \brief Returns true if the viewed node is a toml::table.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_table() const noexcept
{
return node_ && node_->is_table();
}
/// \brief Returns true if the viewed node is a toml::array.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_array() const noexcept
{
return node_ && node_->is_array();
}
/// \brief Returns true if the viewed node is a toml::value<>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_value() const noexcept
{
return node_ && node_->is_value();
}
/// \brief Returns true if the viewed node is a toml::value<string>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_string() const noexcept
{
return node_ && node_->is_string();
}
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_integer() const noexcept
{
return node_ && node_->is_integer();
}
/// \brief Returns true if the viewed node is a toml::value<double>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_floating_point() const noexcept
{
return node_ && node_->is_floating_point();
}
/// \brief Returns true if the viewed node is a toml::value<int64_t> or toml::value<double>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_number() const noexcept
{
return node_ && node_->is_number();
}
/// \brief Returns true if the viewed node is a toml::value<bool>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_boolean() const noexcept
{
return node_ && node_->is_boolean();
}
/// \brief Returns true if the viewed node is a toml::value<date>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_date() const noexcept
{
return node_ && node_->is_date();
}
/// \brief Returns true if the viewed node is a toml::value<time>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_time() const noexcept
{
return node_ && node_->is_time();
}
/// \brief Returns true if the viewed node is a toml::value<date_time>.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_date_time() const noexcept
{
return node_ && node_->is_date_time();
}
/// \brief Returns true if the viewed node is a toml::array that contains only tables.
TOML_NODISCARD
TOML_PURE_GETTER
bool is_array_of_tables() const noexcept
{
return node_ && node_->is_array_of_tables();
@ -221,10 +222,10 @@ TOML_NAMESPACE_START
///
/// \see toml::node::is()
template <typename T>
TOML_NODISCARD
TOML_PURE_GETTER
bool is() const noexcept
{
return node_ ? node_->template is<T>() : false;
return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
}
/// \brief Checks if the viewed node contains values/elements of only one type.
@ -275,7 +276,6 @@ TOML_NAMESPACE_START
/// std::cout << "all floats: "sv << cfg["arr"].is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << cfg["arr"].is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
@ -307,7 +307,6 @@ TOML_NAMESPACE_START
/// std::cout << "all doubles: "sv << cfg["arr"].is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << cfg["arr"].is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
@ -326,10 +325,10 @@ TOML_NAMESPACE_START
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
template <typename ElemType = void>
TOML_NODISCARD
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>() : false;
return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
}
/// @}
@ -337,69 +336,6 @@ TOML_NAMESPACE_START
/// \name Type casts
/// @{
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
TOML_NODISCARD
auto as_table() const noexcept
{
return as<table>();
}
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
TOML_NODISCARD
auto as_array() const noexcept
{
return as<array>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
TOML_NODISCARD
auto as_string() const noexcept
{
return as<std::string>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
TOML_NODISCARD
auto as_integer() const noexcept
{
return as<int64_t>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
TOML_NODISCARD
auto as_floating_point() const noexcept
{
return as<double>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
TOML_NODISCARD
auto as_boolean() const noexcept
{
return as<bool>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
TOML_NODISCARD
auto as_date() const noexcept
{
return as<date>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
TOML_NODISCARD
auto as_time() const noexcept
{
return as<time>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
TOML_NODISCARD
auto as_date_time() const noexcept
{
return as<date_time>();
}
/// \brief Gets a pointer to the viewed node as a more specific node type.
///
/// \tparam T The node type or TOML value type to cast to.
@ -408,12 +344,75 @@ TOML_NAMESPACE_START
///
/// \see toml::node::as()
template <typename T>
TOML_NODISCARD
auto as() const noexcept
TOML_PURE_GETTER
auto* as() const noexcept
{
return node_ ? node_->template as<T>() : nullptr;
}
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
TOML_PURE_GETTER
auto* as_table() const noexcept
{
return as<table>();
}
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
TOML_PURE_GETTER
auto* as_array() const noexcept
{
return as<array>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
TOML_PURE_GETTER
auto* as_string() const noexcept
{
return as<std::string>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
TOML_PURE_GETTER
auto* as_integer() const noexcept
{
return as<int64_t>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
TOML_PURE_GETTER
auto* as_floating_point() const noexcept
{
return as<double>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
TOML_PURE_GETTER
auto* as_boolean() const noexcept
{
return as<bool>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
TOML_PURE_GETTER
auto* as_date() const noexcept
{
return as<date>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
TOML_PURE_GETTER
auto* as_time() const noexcept
{
return as<time>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
TOML_PURE_GETTER
auto* as_date_time() const noexcept
{
return as<date_time>();
}
/// @}
/// \name Value retrieval
@ -433,16 +432,13 @@ TOML_NAMESPACE_START
/// \see node_view::value()
template <typename T>
TOML_NODISCARD
optional<T> value_exact() const noexcept
optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
if (node_)
return node_->template value_exact<T>();
return {};
}
TOML_PUSH_WARNINGS;
TOML_DISABLE_INIT_WARNINGS;
/// \brief Gets the value contained by the referenced node.
///
/// \detail This function has 'permissive' retrieval semantics; some value types are allowed
@ -464,15 +460,13 @@ TOML_NAMESPACE_START
/// - node_view::value_exact()
template <typename T>
TOML_NODISCARD
optional<T> value() const noexcept
optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
if (node_)
return node_->template value<T>();
return {};
}
TOML_POP_WARNINGS;
/// \brief Gets the raw value contained by the referenced node, or a default.
///
/// \tparam T Default value type. Must be one of the native TOML value types,
@ -492,17 +486,17 @@ TOML_NAMESPACE_START
/// - node_view::value_exact()
template <typename T>
TOML_NODISCARD
auto value_or(T&& default_value) const noexcept
auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace ::toml::impl;
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieving values as wide-character strings is only "
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
if (node_)
return node_->value_or(static_cast<T&&>(default_value));
@ -544,18 +538,28 @@ TOML_NAMESPACE_START
/// int64_t& min_ref = tbl["min"].ref<int64_t>(); // matching type
/// double& max_ref = tbl["max"].ref<double>(); // mismatched type, hits assert()
/// int64_t& foo_ref = tbl["foo"].ref<int64_t>(); // nonexistent key, hits assert()
///
/// \ecpp
///
/// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast,
/// whereas specifying explicit cv-ref qualifiers merges them with whatever
/// the cv qualification of the viewed node is (to ensure cv-correctness is propagated), e.g.:
/// | node_view | T | return type |
/// |-----------------------|------------------------|------------------------------|
/// | node_view<node> | std::string | std::string& |
/// | node_view<node> | std::string&& | std::string&& |
/// | node_view<const node> | volatile std::string | const volatile std::string& |
/// | node_view<const node> | volatile std::string&& | const volatile std::string&& |
///
///
/// \tparam T One of the TOML value types.
///
/// \returns A reference to the underlying data.
template <typename T>
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
decltype(auto) ref() const noexcept
{
TOML_ASSERT(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
return node_->template ref<impl::unwrap_node<T>>();
TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
return node_->template ref<T>();
}
/// @}
@ -583,6 +587,23 @@ TOML_NAMESPACE_START
/// \name Equality
/// @{
public:
/// \brief Returns true if the two views refer to nodes of the same type and value.
template <typename T>
TOML_PURE_GETTER
friend bool operator==(const node_view& lhs, const node_view<T>& rhs) noexcept
{
return impl::node_deep_equality(lhs.node_, rhs.node_);
}
/// \brief Returns true if the two views do not refer to nodes of the same type and value.
template <typename T>
TOML_PURE_GETTER
friend bool operator!=(const node_view& lhs, const node_view<T>& rhs) noexcept
{
return !impl::node_deep_equality(lhs.node_, rhs.node_);
}
/// \brief Returns true if the viewed node is a table with the same contents as RHS.
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const table& rhs) noexcept
@ -618,17 +639,17 @@ TOML_NAMESPACE_START
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>);
/// \brief Returns true if the viewed node is a value with the same value as RHS.
TOML_CONSTRAINED_TEMPLATE((impl::is_native<T> || impl::is_losslessly_convertible_to_native<T>), typename T)
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const T& rhs) noexcept
friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>)
{
static_assert(!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
static_assert(!impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Comparison with wide-character strings is only "
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (impl::is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
return lhs == impl::narrow(rhs);
#else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
@ -640,16 +661,16 @@ TOML_NAMESPACE_START
return val && *val == rhs;
}
}
TOML_ASYMMETRICAL_EQUALITY_OPS(
const node_view&,
const T&,
TOML_CONSTRAINED_TEMPLATE((impl::is_native<T> || impl::is_losslessly_convertible_to_native<T>),
typename T));
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&,
const T&,
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>,
typename T));
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
template <typename T>
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const std::initializer_list<T>& rhs) noexcept
friend bool operator==(const node_view& lhs,
const std::initializer_list<T>& rhs) noexcept(!impl::is_wide_string<T>)
{
const auto arr = lhs.as<array>();
return arr && *arr == rhs;
@ -659,7 +680,7 @@ TOML_NAMESPACE_START
/// \brief Returns true if the viewed node is an array with the same contents as the RHS vector.
template <typename T>
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept
friend bool operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept(!impl::is_wide_string<T>)
{
const auto arr = lhs.as<array>();
return arr && *arr == rhs;
@ -682,28 +703,48 @@ TOML_NAMESPACE_START
{
if (auto tbl = this->as_table())
return node_view{ tbl->get(key) };
return node_view{ nullptr };
return {};
}
#if TOML_WINDOWS_COMPAT
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
node_view at_path(std::string_view path) const noexcept
{
return node_ ? node_->at_path(path) : node_view{};
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key of the node to retrieve
///
/// \returns A view of the selected node if this node represented a table and it contained a
/// value at the given key, or an empty view.
TOML_NODISCARD
node_view operator[](std::wstring_view key) const noexcept
node_view operator[](std::wstring_view key) const
{
if (auto tbl = this->as_table())
return node_view{ tbl->get(key) };
return node_view{ nullptr };
return {};
}
#endif // TOML_WINDOWS_COMPAT
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
node_view at_path(std::wstring_view path) const
{
return node_ ? node_->at_path(path) : node_view{};
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
@ -716,100 +757,62 @@ TOML_NAMESPACE_START
{
if (auto arr = this->as_array())
return node_view{ arr->get(index) };
return node_view{ nullptr };
return {};
}
/// @}
template <typename Char, typename T>
friend std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>&, const node_view<T>&);
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the viewed node out to a stream.
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const node_view& nv)
{
if (nv.node_)
nv.node_->visit([&os](const auto& n) { os << n; });
return os;
}
#endif
};
/// \cond
template <typename T>
node_view(const value<T>&) -> node_view<const node>;
node_view(const table&)->node_view<const node>;
node_view(const array&)->node_view<const node>;
template <typename T>
node_view(value<T>&) -> node_view<node>;
node_view(table&)->node_view<node>;
node_view(array&)->node_view<node>;
node_view(const T&) -> node_view<const node>;
template <typename T>
node_view(const T*) -> node_view<const node>;
template <typename T>
node_view(T&) -> node_view<node>;
template <typename T>
node_view(T*) -> node_view<node>;
/// \brief Prints the viewed node out to a stream.
template <typename Char, typename T>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, const node_view<T>& nv)
{
if (nv.node_)
{
nv.node_->visit([&os](const auto& n) { os << n; });
}
return os;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template class TOML_API node_view<node>;
extern template class TOML_API node_view<const node>;
extern template TOML_API
std::ostream& operator<<(std::ostream&, const node_view<node>&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const node_view<const node>&);
#define TOML_EXTERN(name, T) \
extern template TOML_API \
optional<T> node_view<node>::name<T>() const noexcept; \
extern template TOML_API \
optional<T> node_view<const node>::name<T>() const noexcept
TOML_EXTERN(value_exact, std::string_view);
TOML_EXTERN(value_exact, std::string);
TOML_EXTERN(value_exact, const char*);
TOML_EXTERN(value_exact, int64_t);
TOML_EXTERN(value_exact, double);
TOML_EXTERN(value_exact, date);
TOML_EXTERN(value_exact, time);
TOML_EXTERN(value_exact, date_time);
TOML_EXTERN(value_exact, bool);
TOML_EXTERN(value, std::string_view);
TOML_EXTERN(value, std::string);
TOML_EXTERN(value, const char*);
TOML_EXTERN(value, signed char);
TOML_EXTERN(value, signed short);
TOML_EXTERN(value, signed int);
TOML_EXTERN(value, signed long);
TOML_EXTERN(value, signed long long);
TOML_EXTERN(value, unsigned char);
TOML_EXTERN(value, unsigned short);
TOML_EXTERN(value, unsigned int);
TOML_EXTERN(value, unsigned long);
TOML_EXTERN(value, unsigned long long);
TOML_EXTERN(value, double);
TOML_EXTERN(value, float);
TOML_EXTERN(value, date);
TOML_EXTERN(value, time);
TOML_EXTERN(value, date_time);
TOML_EXTERN(value, bool);
#if TOML_HAS_CHAR8
TOML_EXTERN(value_exact, std::u8string_view);
TOML_EXTERN(value_exact, std::u8string);
TOML_EXTERN(value_exact, const char8_t*);
TOML_EXTERN(value, std::u8string_view);
TOML_EXTERN(value, std::u8string);
TOML_EXTERN(value, const char8_t*);
#endif
#if TOML_WINDOWS_COMPAT
TOML_EXTERN(value_exact, std::wstring);
TOML_EXTERN(value, std::wstring);
#endif
#undef TOML_EXTERN
#endif // !TOML_HEADER_ONLY
/// \endcond
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS; // TOML_DISABLE_ARITHMETIC_WARNINGS
/// \cond
#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
#include "node_view_extern.inl"
#endif
TOML_NAMESPACE_START
{
inline node::operator node_view<node>() noexcept
{
return node_view<node>{ this };
}
inline node::operator node_view<const node>() const noexcept
{
return node_view<const node>{ this };
}
}
TOML_NAMESPACE_END;
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,21 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "node_view.h"
#include "header_start.h"
#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
#include "node_view_extern.inl"
#endif // TOML_EXTERN_TEMPLATES
#include "header_end.h"

View File

@ -0,0 +1,71 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/// \cond
#include "node_view.h"
TOML_NAMESPACE_START
{
TOML_EXTERN
template class TOML_API node_view<node>;
TOML_EXTERN
template class TOML_API node_view<const node>;
#define TOML_EXTERN_FUNC(name, T) \
TOML_EXTERN \
template TOML_API \
optional<T> node_view<node>::name<T>() const TOML_EXTERN_NOEXCEPT(impl::value_retrieval_is_nothrow<T>); \
TOML_EXTERN \
template TOML_API \
optional<T> node_view<const node>::name<T>() const TOML_EXTERN_NOEXCEPT(impl::value_retrieval_is_nothrow<T>)
TOML_EXTERN_FUNC(value_exact, std::string_view);
TOML_EXTERN_FUNC(value_exact, std::string);
TOML_EXTERN_FUNC(value_exact, const char*);
TOML_EXTERN_FUNC(value_exact, int64_t);
TOML_EXTERN_FUNC(value_exact, double);
TOML_EXTERN_FUNC(value_exact, date);
TOML_EXTERN_FUNC(value_exact, time);
TOML_EXTERN_FUNC(value_exact, date_time);
TOML_EXTERN_FUNC(value_exact, bool);
TOML_EXTERN_FUNC(value, std::string_view);
TOML_EXTERN_FUNC(value, std::string);
TOML_EXTERN_FUNC(value, const char*);
TOML_EXTERN_FUNC(value, signed char);
TOML_EXTERN_FUNC(value, signed short);
TOML_EXTERN_FUNC(value, signed int);
TOML_EXTERN_FUNC(value, signed long);
TOML_EXTERN_FUNC(value, signed long long);
TOML_EXTERN_FUNC(value, unsigned char);
TOML_EXTERN_FUNC(value, unsigned short);
TOML_EXTERN_FUNC(value, unsigned int);
TOML_EXTERN_FUNC(value, unsigned long);
TOML_EXTERN_FUNC(value, unsigned long long);
TOML_EXTERN_FUNC(value, double);
TOML_EXTERN_FUNC(value, float);
TOML_EXTERN_FUNC(value, date);
TOML_EXTERN_FUNC(value, time);
TOML_EXTERN_FUNC(value, date_time);
TOML_EXTERN_FUNC(value, bool);
#if TOML_HAS_CHAR8
TOML_EXTERN_FUNC(value_exact, std::u8string_view);
TOML_EXTERN_FUNC(value_exact, std::u8string);
TOML_EXTERN_FUNC(value_exact, const char8_t*);
TOML_EXTERN_FUNC(value, std::u8string_view);
TOML_EXTERN_FUNC(value, std::u8string);
TOML_EXTERN_FUNC(value, const char8_t*);
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERN_FUNC(value_exact, std::wstring);
TOML_EXTERN_FUNC(value, std::wstring);
#endif
#undef TOML_EXTERN_FUNC
}
TOML_NAMESPACE_END;
/// \endcond

View File

@ -2,85 +2,52 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_PARSER
#error This header cannot not be included when TOML_PARSER is disabled.
#endif
//# }}
TOML_PUSH_WARNINGS;
TOML_DISABLE_INIT_WARNINGS;
#include "preprocessor.h"
#if TOML_ENABLE_PARSER
#include "std_except.h"
#include "source_region.h"
#include "print_to_stream.h"
#include "header_start.h"
#if defined(DOXYGEN) || !TOML_EXCEPTIONS
#define TOML_PARSE_ERROR_BASE
#else
#define TOML_PARSE_ERROR_BASE : public std::runtime_error
#endif
TOML_NAMESPACE_START
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
#if defined(DOXYGEN) || !TOML_EXCEPTIONS
/// \brief An error generated when parsing fails.
///
/// \remarks This class inherits from std::runtime_error when exceptions are enabled.
/// The public interface is the same regardless of exception mode.
class parse_error final
class parse_error TOML_PARSE_ERROR_BASE
{
private:
#if !TOML_EXCEPTIONS
std::string description_;
#endif
source_region source_;
public:
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, source_region&& src) noexcept
: description_{ std::move(desc) },
source_{ std::move(src) }
{}
#if TOML_EXCEPTIONS
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_region& src) noexcept
: parse_error{ std::move(desc), source_region{ src } }
{}
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
: parse_error{ std::move(desc), source_region{ position, position, path } }
{}
/// \brief Returns a textual description of the error.
/// \remark The backing string is guaranteed to be null-terminated.
TOML_NODISCARD
std::string_view description() const noexcept
{
return description_;
}
/// \brief Returns the region of the source document responsible for the error.
TOML_NODISCARD
const source_region& source() const noexcept
{
return source_;
}
};
#else
class parse_error final : public std::runtime_error
{
private:
source_region source_;
public:
TOML_NODISCARD_CTOR
TOML_ATTR(nonnull)
parse_error(const char* desc, source_region&& src) noexcept
parse_error(const char* desc, source_region&& src) noexcept //
: std::runtime_error{ desc },
source_{ std::move(src) }
{}
TOML_NODISCARD_CTOR
TOML_ATTR(nonnull)
parse_error(const char* desc, const source_region& src) noexcept : parse_error{ desc, source_region{ src } }
parse_error(const char* desc, const source_region& src) noexcept //
: parse_error{ desc, source_region{ src } }
{}
TOML_NODISCARD_CTOR
@ -89,62 +56,84 @@ TOML_NAMESPACE_START
: parse_error{ desc, source_region{ position, position, path } }
{}
#else
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, source_region&& src) noexcept //
: description_{ std::move(desc) },
source_{ std::move(src) }
{}
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_region& src) noexcept //
: parse_error{ std::move(desc), source_region{ src } }
{}
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
: parse_error{ std::move(desc), source_region{ position, position, path } }
{}
#endif
/// \brief Returns a textual description of the error.
/// \remark The backing string is guaranteed to be null-terminated.
TOML_NODISCARD
std::string_view description() const noexcept
{
#if TOML_EXCEPTIONS
return std::string_view{ what() };
#else
return description_;
#endif
}
/// \brief Returns the region of the source document responsible for the error.
TOML_NODISCARD
const source_region& source() const noexcept
{
return source_;
}
/// \brief Prints a parse_error to a stream.
///
/// \detail \cpp
/// try
/// {
/// auto tbl = toml::parse("enabled = trUe"sv);
/// }
/// catch (const toml::parse_error & err)
/// {
/// std::cerr << "Parsing failed:\n"sv << err << "\n";
/// }
/// \ecpp
///
/// \out
/// Parsing failed:
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
/// (error occurred at line 1, column 13)
/// \eout
///
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
/// \param lhs The stream.
/// \param rhs The parse_error.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const parse_error& rhs)
{
impl::print_to_stream(lhs, rhs.description());
impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
impl::print_to_stream(lhs, rhs.source());
impl::print_to_stream(lhs, ")"sv);
return lhs;
}
};
#endif
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
/// \brief Prints a parse_error to a stream.
///
/// \detail \cpp
/// try
/// {
/// auto tbl = toml::parse("enabled = trUe"sv);
/// }
/// catch (const toml::parse_error & err)
/// {
/// std::cerr << "Parsing failed:\n"sv << err << "\n";
/// }
/// \ecpp
///
/// \out
/// Parsing failed:
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
/// (error occurred at line 1, column 13)
/// \eout
///
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
/// \param lhs The stream.
/// \param rhs The parse_error.
///
/// \returns The input stream.
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const parse_error& rhs)
{
lhs << rhs.description();
lhs << "\n\t(error occurred at "sv;
lhs << rhs.source();
lhs << ")"sv;
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const parse_error&);
#endif
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS; // TOML_DISABLE_INIT_WARNINGS
#undef TOML_PARSE_ERROR_BASE
#include "header_end.h"
#endif // TOML_ENABLE_PARSER

View File

@ -2,34 +2,39 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_PARSER
#error This header cannot not be included when TOML_PARSER is disabled.
#endif
//# }}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
#include "table.h"
#include "parse_error.h"
#include "header_start.h"
#if defined(DOXYGEN) || !TOML_EXCEPTIONS
TOML_NAMESPACE_START
{
TOML_ABI_NAMESPACE_START(noex);
/// \brief The result of a parsing operation.
///
/// \availability <strong>This type only exists when exceptions are disabled.</strong>
/// Otherwise parse_result is just an alias for toml::table: \cpp
/// #if TOML_EXCEPTIONS
/// using parse_result = table;
/// #else
/// class parse_result { // ...
/// #endif
/// \ecpp
///
/// \detail A parse_result is effectively a discriminated union containing either a toml::table
/// or a toml::parse_error. Most member functions assume a particular one of these two states,
/// and calling them when in the wrong state will cause errors (e.g. attempting to access the
/// error object when parsing was successful). \cpp
/// parse_result result = toml::parse_file("config.toml");
/// toml::parse_result result = toml::parse_file("config.toml");
/// if (result)
/// do_stuff_with_a_table(result); //implicitly converts to table&
/// else
/// std::cerr << "Parse failed:\n"sv << result.error() << "\n";
///
/// \ecpp
///
/// \out
@ -40,19 +45,10 @@ TOML_NAMESPACE_START
/// (error occurred at line 1, column 13 of 'config.toml')
/// \eout
///
/// Getting node_views (`operator[]`) and using the iterator accessor functions (`begin(), end()` etc.) are
/// Getting node_views (`operator[]`, `at_path()`) and using the iterator accessor functions (`begin()`, `end()` etc.) are
/// unconditionally safe; when parsing fails these just return 'empty' values. A ranged-for loop on a failed
/// parse_result is also safe since `begin()` and `end()` return the same iterator and will not lead to any
/// dereferences and iterations.
///
/// \availability <strong>This type only exists when exceptions are disabled.</strong>
/// Otherwise parse_result is just an alias for toml::table: \cpp
/// #if TOML_EXCEPTIONS
/// using parse_result = table;
/// #else
/// class parse_result final { // ...
/// #endif
/// \ecpp
class parse_result
{
private:
@ -86,123 +82,7 @@ TOML_NAMESPACE_START
}
public:
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
using iterator = table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
using const_iterator = const_table_iterator;
/// \brief Returns true if parsing succeeeded.
TOML_NODISCARD
bool succeeded() const noexcept
{
return !err_;
}
/// \brief Returns true if parsing failed.
TOML_NODISCARD
bool failed() const noexcept
{
return err_;
}
/// \brief Returns true if parsing succeeded.
TOML_NODISCARD
explicit operator bool() const noexcept
{
return !err_;
}
/// \brief Returns the internal toml::table.
TOML_NODISCARD
toml::table& table() & noexcept
{
TOML_ASSERT(!err_);
return *get_as<toml::table>(storage_);
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
toml::table&& table() && noexcept
{
TOML_ASSERT(!err_);
return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
const toml::table& table() const& noexcept
{
TOML_ASSERT(!err_);
return *get_as<const toml::table>(storage_);
}
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
parse_error& error() & noexcept
{
TOML_ASSERT(err_);
return *get_as<parse_error>(storage_);
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
parse_error&& error() && noexcept
{
TOML_ASSERT(err_);
return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
const parse_error& error() const& noexcept
{
TOML_ASSERT(err_);
return *get_as<const parse_error>(storage_);
}
/// \brief Returns the internal toml::table.
TOML_NODISCARD
operator toml::table&() noexcept
{
return table();
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
operator toml::table&&() noexcept
{
return std::move(table());
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
operator const toml::table&() const noexcept
{
return table();
}
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
explicit operator parse_error&() noexcept
{
return error();
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
explicit operator parse_error&&() noexcept
{
return std::move(error());
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
explicit operator const parse_error&() const noexcept
{
return error();
}
/// \brief Default constructs an 'error' result.
TOML_NODISCARD_CTOR
parse_result() noexcept //
: err_{ true }
@ -263,6 +143,191 @@ TOML_NAMESPACE_START
destroy();
}
/// \name Result state
/// @{
/// \brief Returns true if parsing succeeeded.
TOML_NODISCARD
bool succeeded() const noexcept
{
return !err_;
}
/// \brief Returns true if parsing failed.
TOML_NODISCARD
bool failed() const noexcept
{
return err_;
}
/// \brief Returns true if parsing succeeded.
TOML_NODISCARD
explicit operator bool() const noexcept
{
return !err_;
}
/// @}
/// \name Successful parses
/// @{
/// \brief Returns the internal toml::table.
TOML_NODISCARD
toml::table& table() & noexcept
{
TOML_ASSERT_ASSUME(!err_);
return *get_as<toml::table>(storage_);
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
toml::table&& table() && noexcept
{
TOML_ASSERT_ASSUME(!err_);
return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
const toml::table& table() const& noexcept
{
TOML_ASSERT_ASSUME(!err_);
return *get_as<const toml::table>(storage_);
}
/// \brief Returns the internal toml::table.
TOML_NODISCARD
/* implicit */ operator toml::table&() noexcept
{
return table();
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
/* implicit */ operator toml::table&&() noexcept
{
return std::move(table());
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
/* implicit */ operator const toml::table&() const noexcept
{
return table();
}
/// @}
/// \name Failed parses
/// @{
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
parse_error& error() & noexcept
{
TOML_ASSERT_ASSUME(err_);
return *get_as<parse_error>(storage_);
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
parse_error&& error() && noexcept
{
TOML_ASSERT_ASSUME(err_);
return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
const parse_error& error() const& noexcept
{
TOML_ASSERT_ASSUME(err_);
return *get_as<const parse_error>(storage_);
}
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
explicit operator parse_error&() noexcept
{
return error();
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
explicit operator parse_error&&() noexcept
{
return std::move(error());
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
explicit operator const parse_error&() const noexcept
{
return error();
}
/// @}
/// \name Iterators
/// @{
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
using iterator = table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
using const_iterator = const_table_iterator;
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
table_iterator begin() noexcept
{
return err_ ? table_iterator{} : table().begin();
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
const_table_iterator begin() const noexcept
{
return err_ ? const_table_iterator{} : table().begin();
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #cend() if parsing failed.
TOML_NODISCARD
const_table_iterator cbegin() const noexcept
{
return err_ ? const_table_iterator{} : table().cbegin();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
table_iterator end() noexcept
{
return err_ ? table_iterator{} : table().end();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
const_table_iterator end() const noexcept
{
return err_ ? const_table_iterator{} : table().end();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
const_table_iterator cend() const noexcept
{
return err_ ? const_table_iterator{} : table().cend();
}
/// @}
/// \name Node views
/// @{
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
///
/// \param key The key used for the lookup.
@ -272,7 +337,7 @@ TOML_NAMESPACE_START
///
/// \see toml::node_view
TOML_NODISCARD
node_view<node> operator[](string_view key) noexcept
node_view<node> operator[](std::string_view key) noexcept
{
return err_ ? node_view<node>{} : table()[key];
}
@ -286,16 +351,34 @@ TOML_NAMESPACE_START
///
/// \see toml::node_view
TOML_NODISCARD
node_view<const node> operator[](string_view key) const noexcept
node_view<const node> operator[](std::string_view key) const noexcept
{
return err_ ? node_view<const node>{} : table()[key];
}
#if TOML_WINDOWS_COMPAT
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
node_view<node> at_path(std::string_view path) noexcept
{
return err_ ? node_view<node>{} : table().at_path(path);
}
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
node_view<const node> at_path(std::string_view path) const noexcept
{
return err_ ? node_view<const node>{} : table().at_path(path);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
///
@ -311,7 +394,7 @@ TOML_NAMESPACE_START
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
///
@ -325,65 +408,48 @@ TOML_NAMESPACE_START
return err_ ? node_view<const node>{} : table()[key];
}
#endif // TOML_WINDOWS_COMPAT
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
table_iterator begin() noexcept
node_view<node> at_path(std::wstring_view path) noexcept
{
return err_ ? table_iterator{} : table().begin();
return err_ ? node_view<node>{} : table().at_path(path);
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
const_table_iterator begin() const noexcept
node_view<const node> at_path(std::wstring_view path) const noexcept
{
return err_ ? const_table_iterator{} : table().begin();
return err_ ? node_view<const node>{} : table().at_path(path);
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
const_table_iterator cbegin() const noexcept
{
return err_ ? const_table_iterator{} : table().cbegin();
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
table_iterator end() noexcept
{
return err_ ? table_iterator{} : table().end();
}
/// @}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
const_table_iterator end() const noexcept
{
return err_ ? const_table_iterator{} : table().end();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
TOML_NODISCARD
const_table_iterator cend() const noexcept
{
return err_ ? const_table_iterator{} : table().cend();
}
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the held error or table object out to a text stream.
template <typename Char>
friend std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, const parse_result& result)
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const parse_result& result)
{
return result.err_ ? (os << result.error()) : (os << result.table());
}
#endif
};
TOML_ABI_NAMESPACE_END;
}
TOML_NAMESPACE_END;
#endif // !TOML_EXCEPTIONS
#include "header_end.h"
#endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS

View File

@ -2,32 +2,14 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_PARSER
#error This header cannot not be included when TOML_PARSER is disabled.
#endif
//# }}
#if TOML_ENABLE_PARSER
#include "table.h"
#include "parse_error.h"
#include "parse_result.h"
#include "utf8_streams.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
TOML_NODISCARD
TOML_API
parse_result do_parse(utf8_reader_interface &&) TOML_MAY_THROW;
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
#include "header_start.h"
TOML_NAMESPACE_START
{
@ -38,7 +20,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -56,14 +37,13 @@ TOML_NAMESPACE_START
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
parse_result parse(std::string_view doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a string view.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -81,235 +61,7 @@ TOML_NAMESPACE_START
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::string_view doc, std::string && source_path) TOML_MAY_THROW;
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a string view.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
#endif // TOML_WINDOWS_COMPAT
#if TOML_HAS_CHAR8
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::string && source_path) TOML_MAY_THROW;
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
#endif // TOML_WINDOWS_COMPAT
#endif // TOML_HAS_CHAR8
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
template <typename Char>
TOML_NODISCARD
inline parse_result parse(std::basic_istream<Char> & doc, std::string_view source_path = {}) TOML_MAY_THROW
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
return impl::do_parse(impl::utf8_reader{ doc, source_path });
}
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
template <typename Char>
TOML_NODISCARD
inline parse_result parse(std::basic_istream<Char> & doc, std::string && source_path) TOML_MAY_THROW
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
}
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
///
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
template <typename Char>
TOML_NODISCARD
inline parse_result parse(std::basic_istream<Char> & doc, std::wstring_view source_path) TOML_MAY_THROW
{
return parse(doc, impl::narrow(source_path));
}
#endif // TOML_WINDOWS_COMPAT
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
extern template TOML_API
parse_result parse(std::istream&, std::string &&) TOML_MAY_THROW;
#endif
parse_result parse(std::string_view doc, std::string && source_path);
/// \brief Parses a TOML document from a file.
///
@ -328,10 +80,58 @@ TOML_NAMESPACE_START
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse_file(std::string_view file_path) TOML_MAY_THROW;
parse_result parse_file(std::string_view file_path);
#if TOML_HAS_CHAR8
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::string && source_path);
/// \brief Parses a TOML document from a file.
///
/// \detail \cpp
@ -349,14 +149,71 @@ TOML_NAMESPACE_START
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse_file(std::u8string_view file_path) TOML_MAY_THROW;
parse_result parse_file(std::u8string_view file_path);
#endif // TOML_HAS_CHAR8
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a string view.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::string_view doc, std::wstring_view source_path);
/// \brief Parses a TOML document from a stream.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::istream & doc, std::wstring_view source_path);
/// \brief Parses a TOML document from a file.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// toml::parse_result get_foo_toml()
/// {
@ -364,8 +221,6 @@ TOML_NAMESPACE_START
/// }
/// \ecpp
///
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
///
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns \conditional_return{With exceptions}
@ -374,9 +229,93 @@ TOML_NAMESPACE_START
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse_file(std::wstring_view file_path) TOML_MAY_THROW;
parse_result parse_file(std::wstring_view file_path);
#endif // TOML_WINDOWS_COMPAT
#endif // TOML_ENABLE_WINDOWS_COMPAT
#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a char8_t string view.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::u8string_view doc, std::wstring_view source_path);
#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::istream & doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss, "foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result parse(std::istream & doc, std::string && source_path);
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
@ -391,7 +330,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = "a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -406,8 +344,10 @@ TOML_NAMESPACE_START
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result operator"" _toml(const char* str, size_t len) TOML_MAY_THROW;
inline parse_result operator"" _toml(const char* str, size_t len)
{
return parse(std::string_view{ str, len });
}
#if TOML_HAS_CHAR8
@ -418,7 +358,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = u8"a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -433,8 +372,10 @@ TOML_NAMESPACE_START
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_API
parse_result operator"" _toml(const char8_t* str, size_t len) TOML_MAY_THROW;
inline parse_result operator"" _toml(const char8_t* str, size_t len)
{
return parse(std::u8string_view{ str, len });
}
#endif // TOML_HAS_CHAR8
@ -442,3 +383,6 @@ TOML_NAMESPACE_START
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_PARSER

View File

@ -66,25 +66,27 @@
_Pragma("clang diagnostic ignored \"-Wswitch\"") \
static_assert(true)
#define TOML_DISABLE_INIT_WARNINGS \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
static_assert(true)
#define TOML_DISABLE_ARITHMETIC_WARNINGS \
_Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
_Pragma("clang diagnostic ignored \"-Wdouble-promotion\"") \
_Pragma("clang diagnostic ignored \"-Wchar-subscripts\"") \
_Pragma("clang diagnostic ignored \"-Wshift-sign-overflow\"") \
static_assert(true)
#define TOML_DISABLE_SHADOW_WARNINGS \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
_Pragma("clang diagnostic ignored \"-Wshadow-field\"") \
static_assert(true)
#if TOML_CLANG >= 10
#define TOML_DISABLE_SPAM_WARNINGS_CLANG_10 \
_Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \
static_assert(true)
#else
#define TOML_DISABLE_SPAM_WARNINGS_CLANG_10 static_assert(true)
#endif
#define TOML_DISABLE_SPAM_WARNINGS \
TOML_DISABLE_SPAM_WARNINGS_CLANG_10; \
_Pragma("clang diagnostic ignored \"-Wweak-vtables\"") \
_Pragma("clang diagnostic ignored \"-Wweak-template-vtables\"") \
_Pragma("clang diagnostic ignored \"-Wdouble-promotion\"") \
_Pragma("clang diagnostic ignored \"-Wchar-subscripts\"") \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("clang diagnostic ignored \"-Wpadded\"") \
static_assert(true)
@ -99,7 +101,7 @@
#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
#define TOML_ASSUME(cond) __builtin_assume(cond)
#define TOML_ASSUME(expr) __builtin_assume(expr)
#define TOML_UNREACHABLE __builtin_unreachable()
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
#if defined(_MSC_VER) // msvc compat mode
@ -128,6 +130,17 @@
#if !defined(TOML_TRIVIAL_ABI) && __has_attribute(trivial_abi)
#define TOML_TRIVIAL_ABI __attribute__((__trivial_abi__))
#endif
#if !defined(TOML_FLAGS_ENUM) && __has_attribute(flag_enum)
#define TOML_FLAGS_ENUM __attribute__((__flag_enum__))
#endif
#if __has_attribute(enum_extensibility)
#ifndef TOML_OPEN_ENUM
#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open)))
#endif
#ifndef TOML_CLOSED_ENUM
#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed)))
#endif
#endif
#endif
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
@ -162,8 +175,8 @@
#endif
#define TOML_DISABLE_SWITCH_WARNINGS \
__pragma(warning(disable: 4061)) \
__pragma(warning(disable: 4062)) \
__pragma(warning(disable: 4061)) /* enumerator 'identifier' is not explicitly handled by a case label */ \
__pragma(warning(disable: 4062)) /* enumerator 'identifier' is not handled */ \
__pragma(warning(disable: 4063)) \
__pragma(warning(disable: 26819)) \
static_assert(true)
@ -222,7 +235,7 @@
#define TOML_ALWAYS_INLINE __forceinline
#endif
#define TOML_NEVER_INLINE __declspec(noinline)
#define TOML_ASSUME(cond) __assume(cond)
#define TOML_ASSUME(expr) __assume(expr)
#define TOML_UNREACHABLE __assume(0)
#define TOML_ABSTRACT_BASE __declspec(novtable)
#define TOML_EMPTY_BASES __declspec(empty_bases)
@ -278,23 +291,17 @@
#define TOML_DISABLE_SWITCH_WARNINGS \
_Pragma("GCC diagnostic ignored \"-Wswitch\"") \
_Pragma("GCC diagnostic ignored \"-Wswitch-enum\"") \
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"") \
static_assert(true)
#define TOML_DISABLE_INIT_WARNINGS \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
_Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"") \
static_assert(true)
#define TOML_DISABLE_ARITHMETIC_WARNINGS \
_Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") \
_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") \
_Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \
static_assert(true)
#define TOML_DISABLE_SHADOW_WARNINGS \
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") \
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=pure\"") \
static_assert(true)
#define TOML_DISABLE_SPAM_WARNINGS \
@ -303,8 +310,10 @@
_Pragma("GCC diagnostic ignored \"-Wcomment\"") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
_Pragma("GCC diagnostic ignored \"-Wuseless-cast\"") \
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") \
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=pure\"") \
_Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \
_Pragma("GCC diagnostic ignored \"-Wsubobject-linkage\"") \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
static_assert(true)
#define TOML_POP_WARNINGS \
@ -317,10 +326,9 @@
_Pragma("GCC diagnostic ignored \"-Wextra\"") \
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
TOML_DISABLE_SWITCH_WARNINGS; \
TOML_DISABLE_INIT_WARNINGS; \
TOML_DISABLE_ARITHMETIC_WARNINGS; \
TOML_DISABLE_SHADOW_WARNINGS; \
TOML_DISABLE_SPAM_WARNINGS; \
TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \
static_assert(true)
@ -339,91 +347,7 @@
#endif
//#====================================================================================================================
//# USER CONFIGURATION
//#====================================================================================================================
#ifdef TOML_CONFIG_HEADER
#include TOML_CONFIG_HEADER
#endif
#ifdef DOXYGEN
#define TOML_HEADER_ONLY 0
#define TOML_WINDOWS_COMPAT 1
#endif
#if defined(TOML_ALL_INLINE) && !defined(TOML_HEADER_ONLY)
#define TOML_HEADER_ONLY TOML_ALL_INLINE
#endif
#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
#undef TOML_HEADER_ONLY
#define TOML_HEADER_ONLY 1
#endif
#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
#undef TOML_IMPLEMENTATION
#define TOML_IMPLEMENTATION 1
#else
#define TOML_IMPLEMENTATION 0
#endif
#ifndef TOML_API
#define TOML_API
#endif
#ifndef TOML_UNRELEASED_FEATURES
#if TOML_INTELLISENSE
#define TOML_UNRELEASED_FEATURES 1
#else
#define TOML_UNRELEASED_FEATURES 0
#endif
#endif
#ifndef TOML_LARGE_FILES
#define TOML_LARGE_FILES 0
#endif
#ifndef TOML_UNDEF_MACROS
#define TOML_UNDEF_MACROS 1
#endif
#ifndef TOML_PARSER
#define TOML_PARSER 1
#endif
#ifndef TOML_MAX_NESTED_VALUES
#define TOML_MAX_NESTED_VALUES 256
// this refers to the depth of nested values, e.g. inline tables and arrays.
// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
#endif
#ifndef TOML_WINDOWS_COMPAT
#define TOML_WINDOWS_COMPAT 1
#endif
/// \cond
#ifndef _WIN32
#undef TOML_WINDOWS_COMPAT
#define TOML_WINDOWS_COMPAT 0
#endif
/// \endcond
#ifndef TOML_INCLUDE_WINDOWS_H
#define TOML_INCLUDE_WINDOWS_H 0
#endif
#ifdef TOML_OPTIONAL_TYPE
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
#else
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
#endif
#ifdef TOML_CHAR_8_STRINGS
#if TOML_CHAR_8_STRINGS
#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly.
#endif
#endif
//#====================================================================================================================
//# ATTRIBUTES, UTILITY MACROS ETC
//# CPP VERSION
//#====================================================================================================================
#ifndef TOML_CPP_VERSION
@ -433,17 +357,116 @@
#error toml++ requires C++17 or higher. For a TOML library supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml
#elif TOML_CPP_VERSION < 201703L
#error toml++ requires C++17 or higher. For a TOML library supporting C++11 see https://github.com/ToruNiina/toml11
#elif TOML_CPP_VERSION >= 202600L
#define TOML_CPP 26
#elif TOML_CPP_VERSION >= 202300L
#define TOML_CPP 23
#elif TOML_CPP_VERSION >= 202002L
#define TOML_CPP 20
#elif TOML_CPP_VERSION >= 201703L
#define TOML_CPP 17
#endif
#undef TOML_CPP_VERSION
//#====================================================================================================================
//# USER CONFIGURATION
//#====================================================================================================================
#ifdef TOML_CONFIG_HEADER
#include TOML_CONFIG_HEADER
#endif
// header-only mode
#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0
#define TOML_HEADER_ONLY TOML_ALL_INLINE
#endif
#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
#undef TOML_HEADER_ONLY
#define TOML_HEADER_ONLY 1
#endif
#ifdef DOXYGEN
#undef TOML_HEADER_ONLY
#define TOML_HEADER_ONLY 0
#endif
// extern templates (for !TOML_HEADER_ONLY)
#ifndef TOML_EXTERN_TEMPLATES
#define TOML_EXTERN_TEMPLATES 1
#endif
#if (defined(DOXYGEN) || TOML_HEADER_ONLY)
#undef TOML_EXTERN_TEMPLATES
#define TOML_EXTERN_TEMPLATES 0
#endif
// internal implementation switch
#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
#undef TOML_IMPLEMENTATION
#define TOML_IMPLEMENTATION 1
#else
#define TOML_IMPLEMENTATION 0
#endif
// dllexport etc
#ifndef TOML_API
#define TOML_API
#endif
// experimental language features
#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES pre-3.0
#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES
#endif
#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE
#undef TOML_ENABLE_UNRELEASED_FEATURES
#define TOML_ENABLE_UNRELEASED_FEATURES 1
#endif
#ifndef TOML_ENABLE_UNRELEASED_FEATURES
#define TOML_ENABLE_UNRELEASED_FEATURES 0
#endif
// parser
#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0
#define TOML_ENABLE_PARSER TOML_PARSER
#endif
#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE
#undef TOML_ENABLE_PARSER
#define TOML_ENABLE_PARSER 1
#endif
// formatters
#if !defined(TOML_ENABLE_FORMATTERS) \
|| (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) \
|| TOML_INTELLISENSE
#undef TOML_ENABLE_FORMATTERS
#define TOML_ENABLE_FORMATTERS 1
#endif
// SIMD
#if !defined(TOML_ENABLE_SIMD) \
|| (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) \
|| TOML_INTELLISENSE
#undef TOML_ENABLE_SIMD
#define TOML_ENABLE_SIMD 1
#endif
// windows compat
#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0
#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT
#endif
#if !defined(TOML_ENABLE_WINDOWS_COMPAT) \
|| (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \
|| TOML_INTELLISENSE
#undef TOML_ENABLE_WINDOWS_COMPAT
#define TOML_ENABLE_WINDOWS_COMPAT 1
#endif
/// \cond
#ifndef _WIN32
#undef TOML_ENABLE_WINDOWS_COMPAT
#define TOML_ENABLE_WINDOWS_COMPAT 0
#endif
/// \endcond
#ifndef TOML_INCLUDE_WINDOWS_H
#define TOML_INCLUDE_WINDOWS_H 0
#endif
// custom optional
#ifdef TOML_OPTIONAL_TYPE
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
#else
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
#endif
// exceptions (compiler support)
#ifndef TOML_COMPILER_EXCEPTIONS
#if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
#define TOML_COMPILER_EXCEPTIONS 1
@ -451,6 +474,8 @@
#define TOML_COMPILER_EXCEPTIONS 0
#endif
#endif
// exceptions (library use)
#if TOML_COMPILER_EXCEPTIONS
#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
#undef TOML_EXCEPTIONS
@ -464,18 +489,39 @@
#define TOML_EXCEPTIONS 0
#endif
#if defined(DOXYGEN) || TOML_EXCEPTIONS
#define TOML_MAY_THROW
#else
#define TOML_MAY_THROW noexcept
#ifndef TOML_UNDEF_MACROS
#define TOML_UNDEF_MACROS 1
#endif
#if TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)
#ifndef TOML_MAX_NESTED_VALUES
#define TOML_MAX_NESTED_VALUES 256
// this refers to the depth of nested values, e.g. inline tables and arrays.
// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
#endif
#ifdef TOML_CHAR_8_STRINGS
#if TOML_CHAR_8_STRINGS
#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly.
#endif
#endif
#ifdef TOML_LARGE_FILES
#if !TOML_LARGE_FILES
#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0.
#endif
#endif
//#====================================================================================================================
//# ATTRIBUTES, UTILITY MACROS ETC
//#====================================================================================================================
#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL))
// not supported by any version of GCC or Clang as of 26/11/2020
// not supported by any version of ICC on Linux as of 11/01/2021
#define TOML_FLOAT_CHARCONV 0
#endif
#if defined(__EMSCRIPTEN__) || defined(__APPLE__)
#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__))
// causes link errors on emscripten
// causes Mac OS SDK version errors on some versions of Apple Clang
#define TOML_INT_CHARCONV 0
@ -502,8 +548,8 @@
#ifndef TOML_DISABLE_SWITCH_WARNINGS
#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_INIT_WARNINGS
#define TOML_DISABLE_INIT_WARNINGS static_assert(true)
#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_SPAM_WARNINGS
#define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
@ -511,9 +557,6 @@
#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_SHADOW_WARNINGS
#define TOML_DISABLE_SHADOW_WARNINGS static_assert(true)
#endif
#ifndef TOML_POP_WARNINGS
#define TOML_POP_WARNINGS static_assert(true)
#endif
@ -544,18 +587,31 @@
#endif
#ifndef TOML_ASSUME
#define TOML_ASSUME(cond) (void)0
#define TOML_ASSUME(expr) static_assert(true)
#endif
#ifndef TOML_UNREACHABLE
#define TOML_UNREACHABLE TOML_ASSERT(false)
#define TOML_UNREACHABLE TOML_ASSUME(false)
#endif
#if defined(__cpp_consteval) && __cpp_consteval >= 201811 && !defined(_MSC_VER)
// https://developercommunity.visualstudio.com/t/Erroneous-C7595-error-with-consteval-in/1404234
#define TOML_CONSTEVAL consteval
#else
#define TOML_CONSTEVAL constexpr
#ifndef TOML_FLAGS_ENUM
#define TOML_FLAGS_ENUM
#endif
#ifndef TOML_OPEN_ENUM
#define TOML_OPEN_ENUM
#endif
#ifndef TOML_CLOSED_ENUM
#define TOML_CLOSED_ENUM
#endif
#ifndef TOML_OPEN_FLAGS_ENUM
#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM
#endif
#ifndef TOML_CLOSED_FLAGS_ENUM
#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM
#endif
#ifdef __has_cpp_attribute
@ -564,19 +620,35 @@
#define TOML_HAS_ATTR(...) 0
#endif
#if !defined(TOML_LIKELY) && TOML_HAS_ATTR(likely) >= 201803
#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
#if TOML_HAS_ATTR(likely) >= 201803
#ifndef TOML_LIKELY
#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
#endif
#ifndef TOML_LIKELY_CASE
#define TOML_LIKELY_CASE [[likely]]
#endif
#endif
#ifndef TOML_LIKELY
#define TOML_LIKELY(...) (__VA_ARGS__)
#endif
#ifndef TOML_LIKELY_CASE
#define TOML_LIKELY_CASE
#endif
#if !defined(TOML_UNLIKELY) && TOML_HAS_ATTR(unlikely) >= 201803
#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
#if TOML_HAS_ATTR(unlikely) >= 201803
#ifndef TOML_UNLIKELY
#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
#endif
#ifndef TOML_UNLIKELY_CASE
#define TOML_UNLIKELY_CASE [[unlikely]]
#endif
#endif
#ifndef TOML_UNLIKELY
#define TOML_UNLIKELY(...) (__VA_ARGS__)
#endif
#ifndef TOML_UNLIKELY_CASE
#define TOML_UNLIKELY_CASE
#endif
#if TOML_HAS_ATTR(nodiscard)
#define TOML_NODISCARD [[nodiscard]]
@ -618,9 +690,7 @@
#endif
#define TOML_MAKE_FLAGS_(name, op) \
TOML_NODISCARD \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_CONST_INLINE_GETTER \
constexpr name operator op(name lhs, name rhs) noexcept \
{ \
using under = std::underlying_type_t<name>; \
@ -636,17 +706,13 @@
TOML_MAKE_FLAGS_(name, &); \
TOML_MAKE_FLAGS_(name, |); \
TOML_MAKE_FLAGS_(name, ^); \
TOML_NODISCARD \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_CONST_INLINE_GETTER \
constexpr name operator~(name val) noexcept \
{ \
using under = std::underlying_type_t<name>; \
return static_cast<name>(~static_cast<under>(val)); \
} \
TOML_NODISCARD \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_CONST_INLINE_GETTER \
constexpr bool operator!(name val) noexcept \
{ \
using under = std::underlying_type_t<name>; \
@ -663,6 +729,37 @@
#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__
#endif
#if TOML_IMPLEMENTATION
#define TOML_EXTERN
#else
#define TOML_EXTERN extern
#endif
#if TOML_CLANG
#define TOML_EXTERN_NOEXCEPT(...)
#else
#define TOML_EXTERN_NOEXCEPT(...) noexcept(__VA_ARGS__)
#endif
#ifdef NDEBUG
#define TOML_PURE_GETTER TOML_NODISCARD TOML_ATTR(pure)
#define TOML_CONST_GETTER TOML_NODISCARD TOML_ATTR(const)
#define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_ATTR(pure)
#define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE TOML_ATTR(const)
#else
#define TOML_PURE_GETTER TOML_NODISCARD
#define TOML_CONST_GETTER TOML_NODISCARD
#define TOML_PURE_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE
#define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE
#endif
#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
#define TOML_DELETE_DEFAULTS(T) \
T(const T&) = delete; \
T(T&&) = delete; \
T& operator=(const T&) = delete; \
T& operator=(T&&) = delete
//======================================================================================================================
// SFINAE
//======================================================================================================================
@ -675,10 +772,16 @@
#endif
#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0
#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__ TOML_ENABLE_IF(condition)> TOML_REQUIRES(condition)
#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)
/// \endcond
//# {{
#ifndef TOML_CONSTRAINED_TEMPLATE
#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__>
#endif
#ifndef TOML_HIDDEN_CONSTRAINT
#define TOML_HIDDEN_CONSTRAINT(condition, ...)
#endif
//# }}
//#====================================================================================================================
//# EXTENDED INT AND FLOAT TYPES
@ -721,24 +824,24 @@
#define TOML_LIB_SINGLE_HEADER 0
#define TOML_MAKE_VERSION(maj, min, rev) \
((maj) * 1000 + (min) * 25 + (rev))
#define TOML_MAKE_VERSION(major, minor, patch) \
((major) * 10000 + (minor) * 100 + (patch))
#if TOML_UNRELEASED_FEATURES
#define TOML_LANG_EFFECTIVE_VERSION \
#if TOML_ENABLE_UNRELEASED_FEATURES
#define TOML_LANG_EFFECTIVE_VERSION \
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
#else
#define TOML_LANG_EFFECTIVE_VERSION \
#define TOML_LANG_EFFECTIVE_VERSION \
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
#endif
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_HIGHER_THAN(major, minor, patch) \
(TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch))
#define TOML_LANG_AT_LEAST(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_AT_LEAST(major, minor, patch) \
(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch))
#define TOML_LANG_UNRELEASED \
#define TOML_LANG_UNRELEASED \
TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
#ifndef TOML_ABI_NAMESPACES
@ -766,17 +869,17 @@
#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl
#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END
#if TOML_HEADER_ONLY
#define TOML_ANON_NAMESPACE_START TOML_IMPL_NAMESPACE_START
#define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START
#define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END
#define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl
#define TOML_USING_ANON_NAMESPACE using namespace TOML_ANON_NAMESPACE
#define TOML_EXTERNAL_LINKAGE inline
#define TOML_INTERNAL_LINKAGE inline
#else
#define TOML_ANON_NAMESPACE_START namespace
#define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \
using namespace toml; \
namespace
#define TOML_ANON_NAMESPACE_END static_assert(true)
#define TOML_ANON_NAMESPACE
#define TOML_USING_ANON_NAMESPACE static_cast<void>(0)
#define TOML_EXTERNAL_LINKAGE
#define TOML_INTERNAL_LINKAGE static
#endif
@ -785,18 +888,23 @@
//# ASSERT
//#====================================================================================================================
TOML_DISABLE_WARNINGS;
#ifndef TOML_ASSERT
#if defined(NDEBUG) || !defined(_DEBUG)
#define TOML_ASSERT(expr) static_cast<void>(0)
#else
#ifndef assert
#include <cassert>
#endif
#define TOML_ASSERT(expr) assert(expr)
#endif
#ifdef NDEBUG
#undef TOML_ASSERT
#define TOML_ASSERT(expr) static_assert(true)
#endif
#ifndef TOML_ASSERT
#ifndef assert
TOML_DISABLE_WARNINGS;
#include <cassert>
TOML_ENABLE_WARNINGS;
#endif
#define TOML_ASSERT(expr) assert(expr)
#endif
#ifdef NDEBUG
#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
#else
#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
#endif
TOML_ENABLE_WARNINGS;
//#====================================================================================================================
//# STATIC ASSERT MESSAGE FORMATTING
@ -914,12 +1022,6 @@ TOML_ENABLE_WARNINGS;
/// \detail Not defined by default. Meaningless when #TOML_HEADER_ONLY is enabled.
/// \def TOML_LARGE_FILES
/// \brief Sets whether line and column indices are 32-bit integers.
/// \detail Defaults to `0`.
/// \see toml::source_index
#define TOML_OPTIONAL_TYPE
/// \def TOML_OPTIONAL_TYPE
/// \brief Overrides the `optional<T>` type used by the library.
@ -929,11 +1031,22 @@ TOML_ENABLE_WARNINGS;
/// (e.g. [tl::optional](https://github.com/TartanLlama/optional)).
/// \def TOML_PARSER
/// \brief Sets whether the parser-related parts of the library are included.
/// \detail Defaults to `1`.
/// \remarks If you don't need to parse TOML data from any strings or files (e.g. you're only using the library to
/// serialize data as TOML), setting `TOML_PARSER` to `0` can yield decent compilation speed improvements.
/// \def TOML_ENABLE_PARSER
/// \brief Sets whether the parser-related parts of the library are included.
/// \detail Defaults to `1`.
/// \remarks If you don't parse any TOML from files or strings, setting `TOML_ENABLE_PARSER`
/// to `0` can improve compilation speed and reduce binary size.
/// \def TOML_ENABLE_FORMATTERS
/// \brief Sets whether the various formatter classes are enabled.
/// \detail Defaults to `1`.
/// \remarks If you don't need to re-serialize TOML data, setting `TOML_ENABLE_FORMATTERS`
/// to `0` can improve compilation speed and reduce binary size.
/// \see
/// - toml::toml_formatter
/// - toml::json_formatter
/// - toml::yaml_formatter
#define TOML_SMALL_FLOAT_TYPE
@ -943,20 +1056,21 @@ TOML_ENABLE_WARNINGS;
/// \remark If you're building for a platform that has a built-in half precision float (e.g. `_Float16`), you don't
/// need to use this configuration option to make toml++ aware of it; the library comes with that built-in.
#define TOML_SMALL_INT_TYPE
/// \def TOML_SMALL_INT_TYPE
/// \brief If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it.
/// \detail Not defined by default.
/// \def TOML_UNRELEASED_FEATURES
/// \def TOML_ENABLE_UNRELEASED_FEATURES
/// \brief Enables support for unreleased TOML language features not yet part of a
/// [numbered version](https://github.com/toml-lang/toml/releases).
/// \detail Defaults to `0`.
/// \see [TOML Language Support](https://github.com/marzer/tomlplusplus/blob/master/README.md#toml-language-support)
/// \def TOML_WINDOWS_COMPAT
/// \def TOML_ENABLE_WINDOWS_COMPAT
/// \brief Enables the use of wide strings (wchar_t, std::wstring) in various places throughout the library
/// when building for Windows.
/// \detail Defaults to `1` when building for Windows, `0` otherwise. Has no effect when building for anything other

View File

@ -2,465 +2,123 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "date_time.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_ARITHMETIC_WARNINGS;
#include "std_string.h"
#include "forward_declarations.h"
#include "header_start.h"
TOML_IMPL_NAMESPACE_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
// A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
// - I'm using <charconv> to format numerics. Faster and locale-independent.
// - I can avoid forcing users to drag in <sstream> and <iomanip>.
// Q: "there's a bit of reinterpret_casting here, is any of it UB?"
// A: - If the source string data is char and the output string is char8_t, then technically yes,
// but not in the other direction. I test in both modes on Clang, GCC and MSVC and have yet to
// see it actually causing an issue, but in the event it does present a problem it's not going to
// be a show-stopper since all it means is I need to do duplicate some code.
// - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
// - Strings in C++. Honestly.
template <typename Char1, typename Char2>
inline void print_to_stream(std::basic_string_view<Char1> str, std::basic_ostream<Char2> & stream)
{
static_assert(sizeof(Char1) == 1);
static_assert(sizeof(Char2) == 1);
stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
}
template <typename Char1, typename Char2>
inline void print_to_stream(const std::basic_string<Char1>& str, std::basic_ostream<Char2>& stream)
{
static_assert(sizeof(Char1) == 1);
static_assert(sizeof(Char2) == 1);
stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
}
template <typename Char>
inline void print_to_stream(char character, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
stream.put(static_cast<Char>(character));
}
template <typename Char>
TOML_API
TOML_ATTR(nonnull)
inline void print_to_stream(const char* str, size_t len, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
}
void print_to_stream(std::ostream&, const char*, size_t);
#if TOML_HAS_CHAR8
TOML_API
void print_to_stream(std::ostream&, std::string_view);
template <typename Char>
inline void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
stream.put(static_cast<Char>(character));
}
TOML_API
void print_to_stream(std::ostream&, const std::string&);
template <typename Char>
TOML_ATTR(nonnull)
inline void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
}
TOML_API
void print_to_stream(std::ostream&, char);
TOML_API
void print_to_stream(std::ostream&, int8_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, int16_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, int32_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, int64_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, uint8_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, uint16_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, uint32_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, uint64_t, value_flags = {}, size_t min_digits = 0);
TOML_API
void print_to_stream(std::ostream&, float, value_flags = {}, bool relaxed_precision = false);
TOML_API
void print_to_stream(std::ostream&, double, value_flags = {}, bool relaxed_precision = false);
TOML_API
void print_to_stream(std::ostream&, bool);
TOML_API
void print_to_stream(std::ostream&, const toml::date&);
TOML_API
void print_to_stream(std::ostream&, const toml::time&);
TOML_API
void print_to_stream(std::ostream&, const toml::time_offset&);
TOML_API
void print_to_stream(std::ostream&, const toml::date_time&);
TOML_API
void print_to_stream(std::ostream&, const source_position&);
TOML_API
void print_to_stream(std::ostream&, const source_region&);
#if TOML_ENABLE_FORMATTERS
TOML_API
void print_to_stream(std::ostream&, const array&);
TOML_API
void print_to_stream(std::ostream&, const table&);
TOML_API
void print_to_stream(std::ostream&, const value<std::string>&);
TOML_API
void print_to_stream(std::ostream&, const value<int64_t>&);
TOML_API
void print_to_stream(std::ostream&, const value<double>&);
TOML_API
void print_to_stream(std::ostream&, const value<bool>&);
TOML_API
void print_to_stream(std::ostream&, const value<date>&);
TOML_API
void print_to_stream(std::ostream&, const value<time>&);
TOML_API
void print_to_stream(std::ostream&, const value<date_time>&);
#endif
template <typename T>
inline constexpr size_t charconv_buffer_length = 0;
template <>
inline constexpr size_t charconv_buffer_length<double> = 60;
template <>
inline constexpr size_t charconv_buffer_length<float> = 40;
template <>
inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
template <>
inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
template <>
inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
template <>
inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
template <>
inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
template <>
inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
template <>
inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
template <>
inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
template <typename T, typename Char>
inline void print_integer_to_stream(T val, std::basic_ostream<Char> & stream, value_flags format = {})
template <typename T, typename U>
inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
if (!val)
{
print_to_stream('0', stream);
return;
}
int base = 10;
if (format != value_flags::none && val >= T{})
{
switch (format)
{
case value_flags::format_as_binary: base = 2; break;
case value_flags::format_as_octal: base = 8; break;
case value_flags::format_as_hexadecimal: base = 16; break;
default: break;
}
}
#if TOML_INT_CHARCONV
char buf[(sizeof(T) * CHAR_BIT)];
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
const auto len = static_cast<size_t>(res.ptr - buf);
if (base == 16)
{
for (size_t i = 0; i < len; i++)
if (buf[i] >= 'a')
buf[i] -= 32;
}
print_to_stream(buf, len, stream);
#else
using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
if TOML_UNLIKELY(format == value_flags::format_as_binary)
{
bool found_one = false;
const auto v = static_cast<unsigned_type>(val);
unsigned_type mask = unsigned_type{ 1 } << (sizeof(unsigned_type) * CHAR_BIT - 1u);
for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++)
{
if ((v & mask))
{
print_to_stream('1', stream);
found_one = true;
}
else if (found_one)
print_to_stream('0', stream);
mask >>= 1;
}
}
else
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << std::uppercase << std::setbase(base);
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
}
#endif
}
#define TOML_P2S_OVERLOAD(T) \
template <typename Char> \
inline void print_to_stream(T val, std::basic_ostream<Char>& stream, value_flags format) \
{ \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream, format); \
} \
static_assert(true)
TOML_P2S_OVERLOAD(int8_t);
TOML_P2S_OVERLOAD(int16_t);
TOML_P2S_OVERLOAD(int32_t);
TOML_P2S_OVERLOAD(int64_t);
TOML_P2S_OVERLOAD(uint8_t);
TOML_P2S_OVERLOAD(uint16_t);
TOML_P2S_OVERLOAD(uint32_t);
TOML_P2S_OVERLOAD(uint64_t);
#undef TOML_P2S_OVERLOAD
template <typename T, typename Char>
inline void print_floating_point_to_stream(T val, std::basic_ostream<Char> & stream, bool hexfloat = false)
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
switch (impl::fpclassify(val))
{
case fp_class::neg_inf: print_to_stream("-inf"sv, stream); break;
case fp_class::pos_inf: print_to_stream("inf"sv, stream); break;
case fp_class::nan: print_to_stream("nan"sv, stream); break;
case fp_class::ok:
{
static constexpr auto needs_decimal_point = [](auto&& s) noexcept
{
for (auto c : s)
if (c == '.' || c == 'E' || c == 'e')
return false;
return true;
};
#if TOML_FLOAT_CHARCONV
char buf[charconv_buffer_length<T>];
const auto res = hexfloat ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
: std::to_chars(buf, buf + sizeof(buf), val);
const auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
print_to_stream(str, stream);
if (!hexfloat && needs_decimal_point(str))
print_to_stream(".0"sv, stream);
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss.precision(std::numeric_limits<T>::digits10 + 1);
if (hexfloat)
ss << std::hexfloat;
ss << val;
const auto str = std::move(ss).str();
print_to_stream(str, stream);
if (!hexfloat && needs_decimal_point(str))
print_to_stream(".0"sv, stream);
#endif
}
break;
default: TOML_UNREACHABLE;
}
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
void print_floating_point_to_stream(double, std::ostream&, bool);
#endif
#define TOML_P2S_OVERLOAD(Type) \
template <typename Char> \
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
{ \
static_assert(sizeof(Char) == 1); \
print_floating_point_to_stream(val, stream); \
} \
static_assert(true)
TOML_P2S_OVERLOAD(double);
#undef TOML_P2S_OVERLOAD
template <typename Char>
inline void print_to_stream(bool val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
print_to_stream(val ? "true"sv : "false"sv, stream);
}
template <typename T, typename Char>
inline void print_to_stream(T val, std::basic_ostream<Char> & stream, size_t zero_pad_to_digits)
{
static_assert(sizeof(Char) == 1);
#if TOML_INT_CHARCONV
char buf[charconv_buffer_length<T>];
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
const auto len = static_cast<size_t>(res.ptr - buf);
for (size_t i = len; i < zero_pad_to_digits; i++)
print_to_stream('0', stream);
print_to_stream(buf, static_cast<size_t>(res.ptr - buf), stream);
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
ss << std::setfill('0') << std::setw(static_cast<int>(zero_pad_to_digits)) << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
#endif
}
template <typename Char>
inline void print_to_stream(const toml::date& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
print_to_stream(val.year, stream, 4_sz);
print_to_stream('-', stream);
print_to_stream(val.month, stream, 2_sz);
print_to_stream('-', stream);
print_to_stream(val.day, stream, 2_sz);
}
template <typename Char>
inline void print_to_stream(const toml::time& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
print_to_stream(val.hour, stream, 2_sz);
print_to_stream(':', stream);
print_to_stream(val.minute, stream, 2_sz);
print_to_stream(':', stream);
print_to_stream(val.second, stream, 2_sz);
if (val.nanosecond && val.nanosecond <= 999999999u)
{
print_to_stream('.', stream);
auto ns = val.nanosecond;
size_t digits = 9_sz;
while (ns % 10u == 0u)
{
ns /= 10u;
digits--;
}
print_to_stream(ns, stream, digits);
}
}
template <typename Char>
inline void print_to_stream(toml::time_offset val, std::basic_ostream<Char> & stream)
{
static_assert(sizeof(Char) == 1);
if (!val.minutes)
print_to_stream('Z', stream);
else
{
auto mins = static_cast<int>(val.minutes);
if (mins < 0)
{
print_to_stream('-', stream);
mins = -mins;
}
else
print_to_stream('+', stream);
const auto hours = mins / 60;
if (hours)
{
print_to_stream(static_cast<unsigned int>(hours), stream, 2_sz);
mins -= hours * 60;
}
else
print_to_stream("00"sv, stream);
print_to_stream(':', stream);
print_to_stream(static_cast<unsigned int>(mins), stream, 2_sz);
}
}
template <typename Char>
inline void print_to_stream(const toml::date_time& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(Char) == 1);
print_to_stream(val.date, stream);
print_to_stream('T', stream);
print_to_stream(val.time, stream);
if (val.offset)
print_to_stream(*val.offset, stream);
}
template <typename T, typename Char>
void print_to_stream_with_escapes(T && str, std::basic_ostream<Char> & stream)
{
static_assert(sizeof(Char) == 1);
for (auto c : str)
{
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
print_to_stream(low_character_escape_table[c], stream);
else if TOML_UNLIKELY(c == '\x7F')
print_to_stream("\\u007F"sv, stream);
else if TOML_UNLIKELY(c == '"')
print_to_stream("\\\""sv, stream);
else if TOML_UNLIKELY(c == '\\')
print_to_stream("\\\\"sv, stream);
else
print_to_stream(c, stream);
}
print_to_stream(stream, bookend);
print_to_stream(stream, val);
print_to_stream(stream, bookend);
}
}
TOML_IMPL_NAMESPACE_END;
TOML_NAMESPACE_START
{
/// \brief Prints a source_position to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42"sv);
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source().begin()
/// << "\n";
///
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7
/// \eout
///
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const source_position& rhs)
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
impl::print_to_stream("line "sv, lhs);
impl::print_to_stream(rhs.line, lhs);
impl::print_to_stream(", column "sv, lhs);
impl::print_to_stream(rhs.column, lhs);
return lhs;
}
/// \brief Prints a source_region to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42", "config.toml");
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source()
/// << "\n";
///
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7 of 'config.toml'
/// \eout
///
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
template <typename Char>
inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const source_region& rhs)
{
static_assert(sizeof(Char) == 1, "The stream's underlying character type must be 1 byte in size.");
lhs << rhs.begin;
if (rhs.path)
{
impl::print_to_stream(" of '"sv, lhs);
impl::print_to_stream(*rhs.path, lhs);
impl::print_to_stream('\'', lhs);
}
return lhs;
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
extern template TOML_API
std::ostream& operator<<(std::ostream&, const source_position&);
extern template TOML_API
std::ostream& operator<<(std::ostream&, const source_region&);
#endif
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS;
#include "header_end.h"

View File

@ -0,0 +1,472 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "print_to_stream.h"
#include "source_region.h"
#include "date_time.h"
#include "toml_formatter.h"
#include "value.h"
#include "array.h"
#include "table.h"
TOML_DISABLE_WARNINGS;
#include <ostream>
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
#include <charconv>
#endif
#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
#include <sstream>
#endif
#if !TOML_INT_CHARCONV
#include <iomanip>
#endif
TOML_ENABLE_WARNINGS;
#include "header_start.h"
TOML_ANON_NAMESPACE_START
{
template <typename T>
inline constexpr size_t charconv_buffer_length = 0;
template <>
inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
template <>
inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
template <>
inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
template <>
inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
template <>
inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
template <>
inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
template <>
inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
template <>
inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
template <>
inline constexpr size_t charconv_buffer_length<float> = 64;
template <>
inline constexpr size_t charconv_buffer_length<double> = 64;
template <typename T>
TOML_INTERNAL_LINKAGE
void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0)
{
if (!val)
{
if (!min_digits)
min_digits = 1;
for (size_t i = 0; i < min_digits; i++)
stream.put('0');
return;
}
static constexpr auto value_flags_mask =
value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
format &= value_flags_mask;
int base = 10;
if (format != value_flags::none && val > T{})
{
switch (format)
{
case value_flags::format_as_binary: base = 2; break;
case value_flags::format_as_octal: base = 8; break;
case value_flags::format_as_hexadecimal: base = 16; break;
default: break;
}
}
#if TOML_INT_CHARCONV
char buf[(sizeof(T) * CHAR_BIT)];
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
const auto len = static_cast<size_t>(res.ptr - buf);
for (size_t i = len; i < min_digits; i++)
stream.put('0');
if (base == 16)
{
for (size_t i = 0; i < len; i++)
if (buf[i] >= 'a')
buf[i] -= 32;
}
impl::print_to_stream(stream, buf, len);
#else
using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
if (base == 2)
{
const auto len = sizeof(T) * CHAR_BIT;
for (size_t i = len; i < min_digits; i++)
stream.put('0');
bool found_one = false;
const auto v = static_cast<unsigned_type>(val);
unsigned_type mask = unsigned_type{ 1 } << (len - 1u);
for (size_t i = 0; i < len; i++)
{
if ((v & mask))
{
stream.put('1');
found_one = true;
}
else if (found_one)
stream.put('0');
mask >>= 1;
}
}
else
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << std::uppercase << std::setbase(base);
if (min_digits)
ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
impl::print_to_stream(stream, str);
}
#endif
}
template <typename T>
TOML_INTERNAL_LINKAGE
void print_floating_point_to_stream(std::ostream & stream,
T val,
value_flags format,
[[maybe_unused]] bool relaxed_precision)
{
switch (impl::fpclassify(val))
{
case impl::fp_class::neg_inf: impl::print_to_stream(stream, "-inf"sv); break;
case impl::fp_class::pos_inf: impl::print_to_stream(stream, "inf"sv); break;
case impl::fp_class::nan: impl::print_to_stream(stream, "nan"sv); break;
case impl::fp_class::ok:
{
static constexpr auto needs_decimal_point = [](auto&& s) noexcept
{
for (auto c : s)
if (c == '.' || c == 'E' || c == 'e')
return false;
return true;
};
#if TOML_FLOAT_CHARCONV
const auto hex = !!(format & value_flags::format_as_hexadecimal);
char buf[charconv_buffer_length<T>];
auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
: std::to_chars(buf, buf + sizeof(buf), val);
auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
char buf2[charconv_buffer_length<T>];
if (!hex && relaxed_precision)
{
res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
const auto str2 = std::string_view{ buf2, static_cast<size_t>(res.ptr - buf2) };
if (str2.length() < str.length())
str = str2;
}
impl::print_to_stream(stream, str);
if (!hex && needs_decimal_point(str))
toml::impl::print_to_stream(stream, ".0"sv);
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
if (!relaxed_precision)
ss.precision(std::numeric_limits<T>::max_digits10);
if (!!(format & value_flags::format_as_hexadecimal))
ss << std::hexfloat;
ss << val;
const auto str = std::move(ss).str();
impl::print_to_stream(stream, str);
if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
impl::print_to_stream(stream, ".0"sv);
#endif
}
break;
default: TOML_UNREACHABLE;
}
}
}
TOML_ANON_NAMESPACE_END;
TOML_IMPL_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
TOML_ATTR(nonnull)
void print_to_stream(std::ostream & stream, const char* val, size_t len)
{
stream.write(val, static_cast<std::streamsize>(len));
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, std::string_view val)
{
stream.write(val.data(), static_cast<std::streamsize>(val.length()));
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const std::string& val)
{
stream.write(val.data(), static_cast<std::streamsize>(val.length()));
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, char val)
{
stream.put(val);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, int8_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, int16_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, int32_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, int64_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, uint8_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, uint16_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, uint32_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, uint64_t val, value_flags format, size_t min_digits)
{
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, float val, value_flags format, bool relaxed_precision)
{
TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, double val, value_flags format, bool relaxed_precision)
{
TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, bool val)
{
print_to_stream(stream, val ? "true"sv : "false"sv);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const toml::date& val)
{
print_to_stream(stream, val.year, {}, 4);
stream.put('-');
print_to_stream(stream, val.month, {}, 2);
stream.put('-');
print_to_stream(stream, val.day, {}, 2);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const toml::time& val)
{
print_to_stream(stream, val.hour, {}, 2);
stream.put(':');
print_to_stream(stream, val.minute, {}, 2);
stream.put(':');
print_to_stream(stream, val.second, {}, 2);
if (val.nanosecond && val.nanosecond <= 999999999u)
{
stream.put('.');
auto ns = val.nanosecond;
size_t digits = 9u;
while (ns % 10u == 0u)
{
ns /= 10u;
digits--;
}
print_to_stream(stream, ns, {}, digits);
}
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const toml::time_offset& val)
{
if (!val.minutes)
{
stream.put('Z');
return;
}
auto mins = static_cast<int>(val.minutes);
if (mins < 0)
{
stream.put('-');
mins = -mins;
}
else
stream.put('+');
const auto hours = mins / 60;
if (hours)
{
print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
mins -= hours * 60;
}
else
print_to_stream(stream, "00"sv);
stream.put(':');
print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const toml::date_time& val)
{
print_to_stream(stream, val.date);
stream.put('T');
print_to_stream(stream, val.time);
if (val.offset)
print_to_stream(stream, *val.offset);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const source_position& val)
{
print_to_stream(stream, "line "sv);
print_to_stream(stream, val.line);
print_to_stream(stream, ", column "sv);
print_to_stream(stream, val.column);
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const source_region& val)
{
print_to_stream(stream, val.begin);
if (val.path)
{
print_to_stream(stream, " of '"sv);
print_to_stream(stream, *val.path);
stream.put('\'');
}
}
#if TOML_ENABLE_FORMATTERS
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const array& arr)
{
stream << toml_formatter{ arr };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const table& tbl)
{
stream << toml_formatter{ tbl };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<std::string>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<int64_t>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<double>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<bool>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<date>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<time>& val)
{
stream << toml_formatter{ val };
}
TOML_EXTERNAL_LINKAGE
void print_to_stream(std::ostream & stream, const value<date_time>& val)
{
stream << toml_formatter{ val };
}
#endif
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,35 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_SIMD
#if defined(__SSE2__) \
|| (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
#define TOML_HAS_SSE2 1
#endif
#if defined(__SSE4_1__) || (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
#define TOML_HAS_SSE4_1 1
#endif
#endif // TOML_ENABLE_SIMD
#ifndef TOML_HAS_SSE2
#define TOML_HAS_SSE2 0
#endif
#ifndef TOML_HAS_SSE4_1
#define TOML_HAS_SSE4_1 0
#endif
TOML_DISABLE_WARNINGS;
#if TOML_HAS_SSE4_1
#include <smmintrin.h>
#endif
#if TOML_HAS_SSE2
#include <emmintrin.h>
#endif
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,195 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "std_optional.h"
#include "std_string.h"
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief The integer type used to tally line numbers and columns.
using source_index = uint32_t;
/// \brief A pointer to a shared string resource containing a source path.
using source_path_ptr = std::shared_ptr<const std::string>;
/// \brief A source document line-and-column pair.
///
/// \detail \cpp
/// auto table = toml::parse_file("config.toml"sv);
/// std::cout << "The node 'description' was defined at "sv
/// << table.get("description")->source().begin()
/// << "\n";
/// \ecpp
///
/// \out
/// The value 'description' was defined at line 7, column 15
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct TOML_TRIVIAL_ABI source_position
{
/// \brief The line number.
/// \remarks Valid line numbers start at 1.
source_index line;
/// \brief The column number.
/// \remarks Valid column numbers start at 1.
source_index column;
/// \brief Returns true if both line and column numbers are non-zero.
TOML_NODISCARD
explicit constexpr operator bool() const noexcept
{
return line > source_index{} && column > source_index{};
}
/// \brief Returns true if two source_positions represent the same line and column.
TOML_NODISCARD
friend constexpr bool operator==(const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line == rhs.line && lhs.column == rhs.column;
}
/// \brief Returns true if two source_positions do not represent the same line and column.
TOML_NODISCARD
friend constexpr bool operator!=(const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line != rhs.line || lhs.column != rhs.column;
}
/// \brief Returns true if the LHS position is before the RHS position.
TOML_NODISCARD
friend constexpr bool operator<(const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line < rhs.line || (lhs.line == rhs.line && lhs.column < rhs.column);
}
/// \brief Returns true if the LHS position is before the RHS position or equal to it.
TOML_NODISCARD
friend constexpr bool operator<=(const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line < rhs.line || (lhs.line == rhs.line && lhs.column <= rhs.column);
}
/// \brief Prints a source_position to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42"sv);
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source().begin()
/// << "\n";
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7
/// \eout
///
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const source_position& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief A source document region.
///
/// \detail \cpp
/// auto tbl = toml::parse_file("config.toml"sv);
/// if (auto server = tbl.get("server"))
/// {
/// std::cout << "begin: "sv << server->source().begin << "\n";
/// std::cout << "end: "sv << server->source().end << "\n";
/// std::cout << "path: "sv << *server->source().path << "\n";
/// }
/// \ecpp
///
/// \out
/// begin: line 3, column 1
/// end: line 3, column 22
/// path: config.toml
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct source_region
{
/// \brief The beginning of the region (inclusive).
source_position begin;
/// \brief The end of the region (exclusive).
source_position end;
/// \brief The path to the corresponding source document.
///
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
source_path_ptr path;
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief The path to the corresponding source document as a wide-string.
///
/// \availability This function is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \remarks This will return an empty optional if no path was provided to toml::parse().
TOML_NODISCARD
optional<std::wstring> wide_path() const
{
if (!path || path->empty())
return {};
return { impl::widen(*path) };
}
#endif
/// \brief Prints a source_region to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42", "config.toml");
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source()
/// << "\n";
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7 of 'config.toml'
/// \eout
///
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const source_region& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,12 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#if TOML_EXCEPTIONS
#include <stdexcept>
#endif
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,10 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <initializer_list>
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,11 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <map>
#include <iterator>
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,18 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <new>
TOML_ENABLE_WARNINGS;
#if TOML_CLANG >= 8 || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914
#define TOML_LAUNDER(x) __builtin_launder(x)
#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
#define TOML_LAUNDER(x) std::launder(x)
#else
#define TOML_LAUNDER(x) x
#endif

View File

@ -0,0 +1,32 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
#include <optional>
#endif
TOML_ENABLE_WARNINGS;
TOML_NAMESPACE_START
{
#if TOML_HAS_CUSTOM_OPTIONAL_TYPE
template <typename T>
using optional = TOML_OPTIONAL_TYPE<T>;
#else
/// \brief The 'optional' type used throughout the library.
///
/// \remarks By default this will be an alias for std::optional, but you can change the optional type
/// used by the library by defining #TOML_OPTIONAL_TYPE.
template <typename T>
using optional = std::optional<T>;
#endif
}
TOML_NAMESPACE_END;

View File

@ -0,0 +1,53 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <string_view>
#include <string>
TOML_ENABLE_WARNINGS;
#if defined(DOXYGEN) \
|| (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \
&& __cpp_lib_char8_t >= 201907)
#define TOML_HAS_CHAR8 1
#else
#define TOML_HAS_CHAR8 0
#endif
/// \cond
namespace toml // non-abi namespace; this is not an error
{
using namespace std::string_literals;
using namespace std::string_view_literals;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_IMPL_NAMESPACE_START
{
TOML_NODISCARD
TOML_API
std::string narrow(std::wstring_view);
TOML_NODISCARD
TOML_API
std::wstring widen(std::string_view);
#if TOML_HAS_CHAR8
TOML_NODISCARD
TOML_API
std::wstring widen(std::u8string_view);
#endif
}
TOML_IMPL_NAMESPACE_END;
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \endcond

View File

@ -0,0 +1,99 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_WINDOWS_COMPAT
#include "std_string.h"
#ifndef _WINDOWS_
#if TOML_INCLUDE_WINDOWS_H
#include <Windows.h>
#else
extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int CodePage,
unsigned long dwFlags,
const wchar_t* lpWideCharStr,
int cchWideChar,
char* lpMultiByteStr,
int cbMultiByte,
const char* lpDefaultChar,
int* lpUsedDefaultChar);
extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage,
unsigned long dwFlags,
const char* lpMultiByteStr,
int cbMultiByte,
wchar_t* lpWideCharStr,
int cchWideChar);
#endif // TOML_INCLUDE_WINDOWS_H
#endif // _WINDOWS_
#include "header_start.h"
TOML_IMPL_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
std::string narrow(std::wstring_view str)
{
if (str.empty())
return {};
std::string s;
const auto len =
::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (len)
{
s.resize(static_cast<size_t>(len));
::WideCharToMultiByte(65001,
0,
str.data(),
static_cast<int>(str.length()),
s.data(),
len,
nullptr,
nullptr);
}
return s;
}
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::string_view str)
{
if (str.empty())
return {};
std::wstring s;
const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (len)
{
s.resize(static_cast<size_t>(len));
::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
}
return s;
}
#if TOML_HAS_CHAR8
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::u8string_view str)
{
if (str.empty())
return {};
return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
}
#endif // TOML_HAS_CHAR8
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_WINDOWS_COMPAT

View File

@ -0,0 +1,10 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <utility>
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,11 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <vector>
#include <iterator>
TOML_ENABLE_WARNINGS;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,294 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "table.h"
#include "node_view.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
TOML_ASSERT_ASSUME(b);
TOML_ASSERT_ASSUME(e);
TOML_ASSERT_ASSUME(b <= e);
if TOML_UNLIKELY(b == e)
return;
for (; b != e; b++)
{
if (!b->value) // empty node_views
continue;
map_.insert_or_assign(std::move(b->key), std::move(b->value));
}
}
TOML_EXTERNAL_LINKAGE
table::table(const table& other) //
: node(other),
inline_{ other.inline_ }
{
for (auto&& [k, v] : other.map_)
map_.emplace_hint(map_.end(), k, impl::make_node(*v));
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table::table(table && other) noexcept //
: node(std::move(other)),
map_{ std::move(other.map_) },
inline_{ other.inline_ }
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table& table::operator=(const table& rhs)
{
if (&rhs != this)
{
node::operator=(rhs);
map_.clear();
for (auto&& [k, v] : rhs.map_)
map_.emplace_hint(map_.end(), k, impl::make_node(*v));
inline_ = rhs.inline_;
}
return *this;
}
TOML_EXTERNAL_LINKAGE
table& table::operator=(table&& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(std::move(rhs));
map_ = std::move(rhs.map_);
inline_ = rhs.inline_;
}
return *this;
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype) const noexcept
{
if (map_.empty())
return false;
if (ntype == node_type::none)
ntype = map_.cbegin()->second->type();
for (auto&& [k, v] : map_)
{
TOML_UNUSED(k);
if (v->type() != ntype)
return false;
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
{
if (map_.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map_.cbegin()->second->type();
for (const auto& [k, v] : map_)
{
TOML_UNUSED(k);
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
{
node* fnm = nullptr;
const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
first_nonmatch = fnm;
return result;
}
TOML_EXTERNAL_LINKAGE
node* table::get(std::string_view key) noexcept
{
if (auto it = map_.find(key); it != map_.end())
return it->second.get();
return nullptr;
}
TOML_EXTERNAL_LINKAGE
node& table::at(std::string_view key)
{
auto n = get(key);
#if TOML_COMPILER_EXCEPTIONS
if (!n)
{
auto err = "key '"s;
err.append(key);
err.append("' not found in table"sv);
throw std::out_of_range{ err };
}
#else
TOML_ASSERT_ASSUME(n && "key not found in table!");
#endif
return *n;
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::get_lower_bound(std::string_view key) noexcept
{
return map_.lower_bound(key);
}
TOML_EXTERNAL_LINKAGE
table::iterator table::find(std::string_view key) noexcept
{
return iterator{ map_.find(key) };
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::find(std::string_view key) const noexcept
{
return const_iterator{ map_.find(key) };
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::erase(const_map_iterator pos) noexcept
{
return map_.erase(pos);
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept
{
return map_.erase(begin, end);
}
TOML_EXTERNAL_LINKAGE
size_t table::erase(std::string_view key) noexcept
{
if (auto it = map_.find(key); it != map_.end())
{
map_.erase(it);
return size_t{ 1 };
}
return size_t{};
}
TOML_EXTERNAL_LINKAGE
table& table::prune(bool recursive)& noexcept
{
if (map_.empty())
return *this;
for (auto it = map_.begin(); it != map_.end();)
{
if (auto arr = it->second->as_array())
{
if (recursive)
arr->prune(true);
if (arr->empty())
{
it = map_.erase(it);
continue;
}
}
else if (auto tbl = it->second->as_table())
{
if (recursive)
tbl->prune(true);
if (tbl->empty())
{
it = map_.erase(it);
continue;
}
}
it++;
}
return *this;
}
TOML_EXTERNAL_LINKAGE
void table::clear() noexcept
{
map_.clear();
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v)
{
return map_.emplace_hint(const_map_iterator{ hint }, std::move(k), std::move(v));
}
TOML_EXTERNAL_LINKAGE
bool table::equal(const table& lhs, const table& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.map_.size() != rhs.map_.size())
return false;
for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
{
if (l->first != r->first)
return false;
const auto lhs_type = l->second->type();
const node& rhs_ = *r->second;
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = l->second->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -1,210 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "table.h"
#include "node_view.h"
/// \cond
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
table::table() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table::table(const table& other) noexcept //
: node(other),
inline_{ other.inline_ }
{
for (auto&& [k, v] : other)
map.emplace_hint(map.end(), k, impl::make_node(v));
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table::table(table && other) noexcept //
: node(std::move(other)),
map{ std::move(other.map) },
inline_{ other.inline_ }
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table& table::operator=(const table& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(rhs);
map.clear();
for (auto&& [k, v] : rhs)
map.emplace_hint(map.end(), k, impl::make_node(v));
inline_ = rhs.inline_;
}
return *this;
}
TOML_EXTERNAL_LINKAGE
table& table::operator=(table&& rhs) noexcept
{
if (&rhs != this)
{
node::operator=(std::move(rhs));
map = std::move(rhs.map);
inline_ = rhs.inline_;
}
return *this;
}
TOML_EXTERNAL_LINKAGE
table::table(impl::table_init_pair * pairs, size_t count) noexcept
{
for (size_t i = 0; i < count; i++)
{
if (!pairs[i].value) // empty node_views
continue;
map.insert_or_assign(std::move(pairs[i].key), std::move(pairs[i].value));
}
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype) const noexcept
{
if (map.empty())
return false;
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
return false;
}
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool table_is_homogeneous(T& map, node_type ntype, U& first_nonmatch) noexcept
{
if (map.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, toml::node * &first_nonmatch) noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
node_view<node> table::operator[](std::string_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
TOML_EXTERNAL_LINKAGE
node_view<const node> table::operator[](std::string_view key) const noexcept
{
return node_view<const node>{ this->get(key) };
}
#if TOML_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node_view<node> table::operator[](std::wstring_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
TOML_EXTERNAL_LINKAGE
node_view<const node> table::operator[](std::wstring_view key) const noexcept
{
return node_view<const node>{ this->get(key) };
}
#endif // TOML_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
bool operator==(const table& lhs, const table& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.map.size() != rhs.map.size())
return false;
for (auto l = lhs.map.begin(), r = rhs.map.begin(), e = lhs.map.end(); l != e; l++, r++)
{
if (l->first != r->first)
return false;
const auto lhs_type = l->second->type();
const node& rhs_ = *r->second;
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = l->second->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool operator!=(const table& lhs, const table& rhs) noexcept
{
return !(lhs == rhs);
}
}
TOML_NAMESPACE_END;
/// \endcond

View File

@ -1,148 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
#if TOML_HEADER_ONLY && !TOML_INTELLISENSE
#error This header cannot not be included when TOML_HEADER_ONLY is enabled.
#endif
//# }}
TOML_DISABLE_WARNINGS;
#include <ostream>
#include <istream>
TOML_ENABLE_WARNINGS;
#include "node_view.h"
#include "default_formatter.h"
#include "json_formatter.h"
#if TOML_PARSER
#include "parser.h"
#endif
// internal implementation namespace
TOML_IMPL_NAMESPACE_START
{
// formatters
template class formatter<char>;
// print to stream machinery
template void print_floating_point_to_stream(double, std::ostream&, bool);
}
TOML_IMPL_NAMESPACE_END;
// public namespace
TOML_NAMESPACE_START
{
// value<>
template class value<std::string>;
template class value<int64_t>;
template class value<double>;
template class value<bool>;
template class value<date>;
template class value<time>;
template class value<date_time>;
// node_view
template class node_view<node>;
template class node_view<const node>;
// formatters
template class default_formatter<char>;
template class json_formatter<char>;
// various ostream operators
template std::ostream& operator<<(std::ostream&, const source_position&);
template std::ostream& operator<<(std::ostream&, const source_region&);
template std::ostream& operator<<(std::ostream&, const date&);
template std::ostream& operator<<(std::ostream&, const time&);
template std::ostream& operator<<(std::ostream&, const time_offset&);
template std::ostream& operator<<(std::ostream&, const date_time&);
template std::ostream& operator<<(std::ostream&, const value<std::string>&);
template std::ostream& operator<<(std::ostream&, const value<int64_t>&);
template std::ostream& operator<<(std::ostream&, const value<double>&);
template std::ostream& operator<<(std::ostream&, const value<bool>&);
template std::ostream& operator<<(std::ostream&, const value<toml::date>&);
template std::ostream& operator<<(std::ostream&, const value<toml::time>&);
template std::ostream& operator<<(std::ostream&, const value<toml::date_time>&);
template std::ostream& operator<<(std::ostream&, default_formatter<char>&);
template std::ostream& operator<<(std::ostream&, default_formatter<char>&&);
template std::ostream& operator<<(std::ostream&, json_formatter<char>&);
template std::ostream& operator<<(std::ostream&, json_formatter<char>&&);
template std::ostream& operator<<(std::ostream&, const table&);
template std::ostream& operator<<(std::ostream&, const array&);
template std::ostream& operator<<(std::ostream&, const node_view<node>&);
template std::ostream& operator<<(std::ostream&, const node_view<const node>&);
template std::ostream& operator<<(std::ostream&, node_type);
// node::value, node_view:::value etc
#define TOML_INSTANTIATE(name, T) \
template optional<T> node::name<T>() const noexcept; \
template optional<T> node_view<node>::name<T>() const noexcept; \
template optional<T> node_view<const node>::name<T>() const noexcept
TOML_INSTANTIATE(value_exact, std::string_view);
TOML_INSTANTIATE(value_exact, std::string);
TOML_INSTANTIATE(value_exact, const char*);
TOML_INSTANTIATE(value_exact, int64_t);
TOML_INSTANTIATE(value_exact, double);
TOML_INSTANTIATE(value_exact, date);
TOML_INSTANTIATE(value_exact, time);
TOML_INSTANTIATE(value_exact, date_time);
TOML_INSTANTIATE(value_exact, bool);
TOML_INSTANTIATE(value, std::string_view);
TOML_INSTANTIATE(value, std::string);
TOML_INSTANTIATE(value, const char*);
TOML_INSTANTIATE(value, signed char);
TOML_INSTANTIATE(value, signed short);
TOML_INSTANTIATE(value, signed int);
TOML_INSTANTIATE(value, signed long);
TOML_INSTANTIATE(value, signed long long);
TOML_INSTANTIATE(value, unsigned char);
TOML_INSTANTIATE(value, unsigned short);
TOML_INSTANTIATE(value, unsigned int);
TOML_INSTANTIATE(value, unsigned long);
TOML_INSTANTIATE(value, unsigned long long);
TOML_INSTANTIATE(value, double);
TOML_INSTANTIATE(value, float);
TOML_INSTANTIATE(value, date);
TOML_INSTANTIATE(value, time);
TOML_INSTANTIATE(value, date_time);
TOML_INSTANTIATE(value, bool);
#if TOML_HAS_CHAR8
TOML_INSTANTIATE(value_exact, std::u8string_view);
TOML_INSTANTIATE(value_exact, std::u8string);
TOML_INSTANTIATE(value_exact, const char8_t*);
TOML_INSTANTIATE(value, std::u8string_view);
TOML_INSTANTIATE(value, std::u8string);
TOML_INSTANTIATE(value, const char8_t*);
#endif
#if TOML_WINDOWS_COMPAT
TOML_INSTANTIATE(value_exact, std::wstring);
TOML_INSTANTIATE(value, std::wstring);
#endif
#undef TOML_INSTANTIATE
// parser instantiations
#if TOML_PARSER
// parse error ostream
template std::ostream& operator<<(std::ostream&, const parse_error&);
// parse() and parse_file()
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
template parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
template parse_result parse(std::istream&, std::string &&) TOML_MAY_THROW;
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
#endif // TOML_PARSER
}
TOML_NAMESPACE_END;

View File

@ -0,0 +1,153 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "std_vector.h"
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
/// operators of the TOML node types already print themselves out using this formatter.
///
/// \detail \cpp
/// auto tbl = toml::table{
/// { "description", "This is some TOML, yo." },
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
/// { "table", toml::table{ { "foo", "bar" } } }
/// };
///
/// // these two lines are equivalent:
/// std::cout << toml::toml_formatter{ tbl } << "\n";
/// std::cout << tbl << "\n";
/// \ecpp
///
/// \out
/// description = "This is some TOML, yo."
/// fruit = ["apple", "orange", "pear"]
/// numbers = [1, 2, 3, 4, 5]
///
/// [table]
/// foo = "bar"
/// \eout
class toml_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
std::vector<const key*> key_path_;
bool pending_table_separator_ = false;
TOML_API
void print_pending_table_separator();
TOML_API
void print(const key&);
TOML_API
void print_inline(const toml::table&);
TOML_API
void print(const toml::array&);
TOML_API
void print(const toml::table&);
TOML_API
void print();
static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory
format_flags::none, // ignored
"inf"sv,
"-inf"sv,
"nan"sv,
"true"sv,
"false"sv };
/// \endcond
public:
/// \brief The default flags for a toml_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_multi_line_strings //
| format_flags::allow_unicode_strings //
| format_flags::allow_real_tabs_in_strings //
| format_flags::allow_binary_integers //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers //
| format_flags::indentation;
/// \brief Constructs a TOML formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a TOML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid TOML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::toml_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::toml_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a = 'b'
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
friend std::ostream& operator<<(std::ostream& lhs, toml_formatter& rhs)
{
rhs.attach(lhs);
rhs.key_path_.clear();
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, toml_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,396 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "toml_formatter.h"
#include "print_to_stream.h"
#include "value.h"
#include "table.h"
#include "array.h"
#include "unicode.h"
#include "header_start.h"
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_ANON_NAMESPACE_START
{
TOML_INTERNAL_LINKAGE
size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept
{
switch (node.type())
{
case node_type::table:
{
auto& tbl = *reinterpret_cast<const table*>(&node);
if (tbl.empty())
return 2u; // "{}"
size_t weight = 3u; // "{ }"
for (auto&& [k, v] : tbl)
{
weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", "
if (weight >= line_wrap_cols)
break;
}
return weight;
}
case node_type::array:
{
auto& arr = *reinterpret_cast<const array*>(&node);
if (arr.empty())
return 2u; // "[]"
size_t weight = 3u; // "[ ]"
for (auto& elem : arr)
{
weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", "
if (weight >= line_wrap_cols)
break;
}
return weight;
}
case node_type::string:
{
// todo: proper utf8 decoding?
// todo: tab awareness?
auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
return str.length() + 2u; // + ""
}
case node_type::integer:
{
auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
if (!val)
return 1u;
size_t weight = {};
if (val < 0)
{
weight += 1u;
val *= -1;
}
return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
}
case node_type::floating_point:
{
auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
if (val == 0.0)
return 3u; // "0.0"
size_t weight = 2u; // ".0"
if (val < 0.0)
{
weight += 1u;
val *= -1.0;
}
return weight + static_cast<size_t>(log10(val)) + 1u;
break;
}
case node_type::boolean: return 5u;
case node_type::date: [[fallthrough]];
case node_type::time: return 10u;
case node_type::date_time: return 30u;
case node_type::none: TOML_UNREACHABLE;
default: TOML_UNREACHABLE;
}
TOML_UNREACHABLE;
}
TOML_INTERNAL_LINKAGE
bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept
{
return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
}
}
TOML_ANON_NAMESPACE_END;
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void toml_formatter::print_pending_table_separator()
{
if (pending_table_separator_)
{
print_newline(true);
print_newline(true);
pending_table_separator_ = false;
}
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const key& k)
{
print_string(k.str(), false, true);
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print_inline(const table& tbl)
{
if (tbl.empty())
{
print_unformatted("{}"sv);
return;
}
print_unformatted("{ "sv);
bool first = false;
for (auto&& [k, v] : tbl)
{
if (first)
print_unformatted(", "sv);
first = true;
print(k);
print_unformatted(" = "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: print_value(v, type);
}
}
print_unformatted(" }"sv);
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const array& arr)
{
if (arr.empty())
{
print_unformatted("[]"sv);
return;
}
const auto original_indent = indent();
const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
arr,
120u,
indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
print_unformatted("["sv);
if (multiline)
{
if (original_indent < 0)
indent(0);
if (indent_array_elements())
increase_indent();
}
else
print_unformatted(' ');
for (size_t i = 0; i < arr.size(); i++)
{
if (i > 0u)
{
print_unformatted(',');
if (!multiline)
print_unformatted(' ');
}
if (multiline)
{
print_newline(true);
print_indent();
}
auto& v = arr[i];
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: print_value(v, type);
}
}
if (multiline)
{
indent(original_indent);
print_newline(true);
print_indent();
}
else
print_unformatted(' ');
print_unformatted("]"sv);
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const table& tbl)
{
static constexpr auto is_non_inline_array_of_tables = [](auto&& nde) noexcept
{
auto arr = nde.as_array();
return arr && arr->is_array_of_tables() && !arr->template get_as<table>(0u)->is_inline();
};
// values, arrays, and inline tables/table arrays
for (auto&& [k, v] : tbl)
{
const auto type = v.type();
if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
|| (type == node_type::array && is_non_inline_array_of_tables(v)))
continue;
pending_table_separator_ = true;
print_newline();
print_indent();
print(k);
print_unformatted(" = "sv);
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
default: print_value(v, type);
}
}
const auto print_key_path = [&]()
{
size_t i{};
for (const auto k : key_path_)
{
if (i++)
print_unformatted('.');
print(*k);
}
};
// non-inline tables
for (auto&& [k, v] : tbl)
{
const auto type = v.type();
if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
continue;
auto& child_tbl = *reinterpret_cast<const table*>(&v);
// we can skip indenting and emitting the headers for tables that only contain other tables
// (so we don't over-nest)
size_t child_value_count{}; // includes inline tables and non-table arrays
size_t child_table_count{};
size_t child_table_array_count{};
for (auto&& [child_k, child_v] : child_tbl)
{
TOML_UNUSED(child_k);
const auto child_type = child_v.type();
TOML_ASSUME(child_type != node_type::none);
switch (child_type)
{
case node_type::table:
if (reinterpret_cast<const table*>(&child_v)->is_inline())
child_value_count++;
else
child_table_count++;
break;
case node_type::array:
if (is_non_inline_array_of_tables(child_v))
child_table_array_count++;
else
child_value_count++;
break;
default: child_value_count++;
}
}
bool skip_self = false;
if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
skip_self = true;
key_path_.push_back(&k);
if (!skip_self)
{
print_pending_table_separator();
if (indent_sub_tables())
increase_indent();
print_indent();
print_unformatted("["sv);
print_key_path();
print_unformatted("]"sv);
pending_table_separator_ = true;
}
print(child_tbl);
key_path_.pop_back();
if (!skip_self && indent_sub_tables())
decrease_indent();
}
// table arrays
for (auto&& [k, v] : tbl)
{
if (!is_non_inline_array_of_tables(v))
continue;
auto& arr = *reinterpret_cast<const array*>(&v);
if (indent_sub_tables())
increase_indent();
key_path_.push_back(&k);
for (size_t i = 0; i < arr.size(); i++)
{
print_pending_table_separator();
print_indent();
print_unformatted("[["sv);
print_key_path();
print_unformatted("]]"sv);
pending_table_separator_ = true;
print(*reinterpret_cast<const table*>(&arr[i]));
}
key_path_.pop_back();
if (indent_sub_tables())
decrease_indent();
}
}
TOML_EXTERNAL_LINKAGE
void toml_formatter::print()
{
if (dump_failed_parse_result())
return;
switch (auto source_type = source().type())
{
case node_type::table:
{
auto& tbl = *reinterpret_cast<const table*>(&source());
if (tbl.is_inline())
print_inline(tbl);
else
{
decrease_indent(); // so root kvps and tables have the same indent
print(tbl);
}
break;
}
case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
default: print_value(source(), source_type);
}
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -2,138 +2,151 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
#include "header_start.h"
/// \cond
#if TOML_GCC && TOML_GCC < 9
#pragma GCC push_options
#pragma GCC optimize("O1") // codegen bugs
#endif
TOML_IMPL_NAMESPACE_START
{
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
// note: a number of these functions were machine-generated. you'll know them when you see them.
// they are tested separately in another project, I promise!
TOML_CONST_GETTER
constexpr bool is_string_delimiter(char32_t c) noexcept
{
return codepoint == U'\t' || codepoint == U' ';
return c == U'"' || c == U'\'';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_ascii_letter(char32_t c) noexcept
{
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that don't say "is a line-break")
return codepoint == U'\u00A0' // no-break space
|| codepoint == U'\u1680' // ogham space mark
|| (codepoint >= U'\u2000' && codepoint <= U'\u200A') // em quad -> hair space
|| codepoint == U'\u202F' // narrow no-break space
|| codepoint == U'\u205F' // medium mathematical space
|| codepoint == U'\u3000' // ideographic space
;
return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z');
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_whitespace(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_binary_digit(char32_t c) noexcept
{
return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint);
return c == U'0' || c == U'1';
}
template <bool IncludeCarriageReturn = true>
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_octal_digit(char32_t c) noexcept
{
constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end);
return (c >= U'0' && c <= U'7');
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_decimal_digit(char32_t c) noexcept
{
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that say "is a line-break")
return codepoint == U'\u0085' // next line
|| codepoint == U'\u2028' // line separator
|| codepoint == U'\u2029' // paragraph separator
;
return (c >= U'0' && c <= U'9');
}
template <bool IncludeCarriageReturn = true>
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_line_break(char32_t codepoint) noexcept
{
return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint);
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_string_delimiter(char32_t codepoint) noexcept
{
return codepoint == U'"' || codepoint == U'\'';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_ascii_letter(char32_t codepoint) noexcept
{
return (codepoint >= U'a' && codepoint <= U'z') || (codepoint >= U'A' && codepoint <= U'Z');
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_binary_digit(char32_t codepoint) noexcept
{
return codepoint == U'0' || codepoint == U'1';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_octal_digit(char32_t codepoint) noexcept
{
return (codepoint >= U'0' && codepoint <= U'7');
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_decimal_digit(char32_t codepoint) noexcept
{
return (codepoint >= U'0' && codepoint <= U'9');
}
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
constexpr bool is_hexadecimal_digit(char32_t c) noexcept
{
return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
}
template <typename T>
TOML_NODISCARD
TOML_ATTR(const)
constexpr uint_least32_t hex_to_dec(const T codepoint) noexcept
TOML_CONST_GETTER
constexpr uint_least32_t hex_to_dec(const T c) noexcept
{
if constexpr (std::is_same_v<remove_cvref_t<T>, uint_least32_t>)
return codepoint >= 0x41u // >= 'A'
? 10u + (codepoint | 0x20u) - 0x61u // - 'a'
: codepoint - 0x30u // - '0'
if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
return c >= 0x41u // >= 'A'
? 10u + (c | 0x20u) - 0x61u // - 'a'
: c - 0x30u // - '0'
;
else
return hex_to_dec(static_cast<uint_least32_t>(codepoint));
return hex_to_dec(static_cast<uint_least32_t>(c));
}
TOML_CONST_GETTER
constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept
{
return c == U'\t' || c == U' ';
}
TOML_CONST_GETTER
constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept
{
if (c < U'\xA0' || c > U'\uFEFF')
return false;
const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
return false;
if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
return true;
switch (child_index_0)
{
case 0x05: return c == U'\u1680' || c == U'\u180E';
case 0x07:
return (U'\u2000' <= c && c <= U'\u200B') || (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
default: TOML_UNREACHABLE;
}
// 20 code units from 8 ranges (spanning a search area of 65120)
TOML_UNREACHABLE;
}
TOML_CONST_GETTER
constexpr bool is_horizontal_whitespace(char32_t c) noexcept
{
return is_ascii_horizontal_whitespace(c) || is_non_ascii_horizontal_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
{
return U'\n' <= c && c <= U'\r';
}
TOML_CONST_GETTER
constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
{
return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
}
TOML_CONST_GETTER
constexpr bool is_vertical_whitespace(char32_t c) noexcept
{
return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_whitespace(char32_t c) noexcept
{
return is_horizontal_whitespace(c) || is_vertical_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
{
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
if (c == U'+')
return true;
#endif
if (c < U'-' || c > U'z')
return false;
if ((1ull << (static_cast<uint_least64_t>(c) - 0x2Du)) & 0xFFF43FFFFFF01FF9ull)
return true;
return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0)
|| ((1ull << (static_cast<uint_least64_t>(c) - 0x2Du)) & 0xFFF43FFFFFF01FF9ull);
}
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
//# Returns true if a codepoint belongs to any of these categories:
//# Ll, Lm, Lo, Lt, Lu
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
constexpr bool is_non_ascii_letter(char32_t c) noexcept
{
if (U'\xAA' > c || c > U'\U0003134A')
@ -486,8 +499,7 @@ TOML_IMPL_NAMESPACE_START
//# Returns true if a codepoint belongs to any of these categories:
//# Nd, Nl
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
constexpr bool is_non_ascii_number(char32_t c) noexcept
{
if (U'\u0660' > c || c > U'\U0001FBF9')
@ -640,8 +652,7 @@ TOML_IMPL_NAMESPACE_START
//# Returns true if a codepoint belongs to any of these categories:
//# Mn, Mc
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
constexpr bool is_combining_mark(char32_t c) noexcept
{
if (U'\u0300' > c || c > U'\U000E01EF')
@ -849,51 +860,55 @@ TOML_IMPL_NAMESPACE_START
TOML_UNREACHABLE;
}
TOML_CONST_GETTER
constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
{
return is_non_ascii_letter(c) || is_non_ascii_number(c) || is_combining_mark(c);
}
#endif // TOML_LANG_UNRELEASED
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_bare_key_character(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_bare_key_character(char32_t c) noexcept
{
return is_ascii_letter(codepoint) || is_decimal_digit(codepoint) || codepoint == U'-' || codepoint == U'_'
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
|| codepoint == U'+' || is_non_ascii_letter(codepoint) || is_non_ascii_number(codepoint)
|| is_combining_mark(codepoint)
return is_ascii_bare_key_character(c)
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
|| is_non_ascii_bare_key_character(c)
#endif
;
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_value_terminator(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_value_terminator(char32_t c) noexcept
{
return is_ascii_line_break(codepoint) || is_ascii_whitespace(codepoint) || codepoint == U']'
|| codepoint == U'}' || codepoint == U',' || codepoint == U'#' || is_non_ascii_line_break(codepoint)
|| is_non_ascii_whitespace(codepoint);
return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_control_character(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_control_character(char c) noexcept
{
return codepoint <= U'\u001F' || codepoint == U'\u007F';
return c <= '\u001F' || c == '\u007F';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_control_character(char32_t c) noexcept
{
return codepoint <= U'\u0008' || (codepoint >= U'\u000A' && codepoint <= U'\u001F') || codepoint == U'\u007F';
return c <= U'\u001F' || c == U'\u007F';
}
TOML_NODISCARD
TOML_ATTR(const)
constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
TOML_CONST_GETTER
constexpr bool is_nontab_control_character(char32_t c) noexcept
{
return codepoint >= 0xD800u && codepoint <= 0xDFFF;
return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') || c == U'\u007F';
}
struct utf8_decoder final
TOML_CONST_GETTER
constexpr bool is_unicode_surrogate(char32_t c) noexcept
{
return c >= 0xD800u && c <= 0xDFFF;
}
struct utf8_decoder
{
// utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
@ -919,27 +934,27 @@ TOML_IMPL_NAMESPACE_START
36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
};
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
constexpr bool error() const noexcept
{
return state == uint_least32_t{ 12u };
}
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
constexpr bool has_code_point() const noexcept
{
return state == uint_least32_t{};
}
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
constexpr bool needs_more_input() const noexcept
{
return state > uint_least32_t{} && state != uint_least32_t{ 12u };
return !has_code_point() && !error();
}
constexpr void operator()(uint8_t byte) noexcept
{
TOML_ASSERT(!error());
TOML_ASSERT_ASSUME(!error());
const auto type = state_table[byte];
@ -949,9 +964,29 @@ TOML_IMPL_NAMESPACE_START
state = state_table[state + uint_least32_t{ 256u } + type];
}
TOML_ALWAYS_INLINE
constexpr void operator()(char c) noexcept
{
operator()(static_cast<uint8_t>(c));
}
TOML_ALWAYS_INLINE
constexpr void reset() noexcept
{
state = {};
}
};
TOML_PURE_GETTER
TOML_ATTR(nonnull)
bool is_ascii(const char* str, size_t len) noexcept;
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
#if TOML_GCC && TOML_GCC < 9
#pragma GCC pop_options
#endif
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,59 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "unicode.h"
#include "simd.h"
#include "header_start.h"
TOML_IMPL_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
bool is_ascii(const char* str, size_t len) noexcept
{
const char* const end = str + len;
#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
{
constexpr size_t chars_per_vector = 128u / CHAR_BIT;
if (const size_t simdable = len - (len % chars_per_vector))
{
__m128i mask = _mm_setzero_si128();
for (const char* const e = str + simdable; str < e; str += chars_per_vector)
{
const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
mask = _mm_or_si128(mask, current_bytes);
}
const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
#if TOML_HAS_SSE4_1
if (!_mm_testz_si128(has_error, has_error))
return false;
#else
if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
return false;
#endif
}
}
#endif
for (; str < end; str++)
if (static_cast<unsigned char>(*str) > 127u)
return false;
return true;
}
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

View File

@ -1,399 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_PARSER
#error This header cannot not be included when TOML_PARSER is disabled.
#endif
//# }}
#include "utf8.h"
#include "parse_error.h"
/// \cond
#if TOML_EXCEPTIONS
#define TOML_ERROR_CHECK (void)0
#define TOML_ERROR throw parse_error
#else
#define TOML_ERROR_CHECK \
if (err) \
return nullptr
#define TOML_ERROR err.emplace
#endif
TOML_IMPL_NAMESPACE_START
{
template <typename T>
class utf8_byte_stream;
inline constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
template <typename Char>
class TOML_API utf8_byte_stream<std::basic_string_view<Char>> final
{
static_assert(sizeof(Char) == 1_sz);
private:
std::basic_string_view<Char> source;
size_t position = {};
public:
explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept : source{ sv }
{
// trim trailing nulls
const size_t initial_len = source.length();
size_t actual_len = initial_len;
for (size_t i = actual_len; i-- > 0_sz;)
{
if (source[i] != Char{}) // not '\0'
{
actual_len = i + 1_sz;
break;
}
}
if (initial_len != actual_len)
source = source.substr(0_sz, actual_len);
// skip bom
if (actual_len >= 3_sz && memcmp(utf8_byte_order_mark.data(), source.data(), 3_sz) == 0)
position += 3_sz;
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
constexpr bool eof() const noexcept
{
return position >= source.length();
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
constexpr bool peek_eof() const noexcept
{
return eof();
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
constexpr bool error() const noexcept
{
return false;
}
TOML_NODISCARD
constexpr unsigned int operator()() noexcept
{
if (position >= source.length())
return 0xFFFFFFFFu;
return static_cast<unsigned int>(static_cast<uint8_t>(source[position++]));
}
};
template <typename Char>
class TOML_API utf8_byte_stream<std::basic_istream<Char>> final
{
static_assert(sizeof(Char) == 1_sz);
private:
std::basic_istream<Char>* source;
public:
explicit utf8_byte_stream(std::basic_istream<Char>& stream) : source{ &stream }
{
if (!source->good()) // eof, fail, bad
return;
const auto initial_pos = source->tellg();
Char bom[3];
source->read(bom, 3);
if (source->bad() || (source->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3_sz) == 0))
return;
source->clear();
source->seekg(initial_pos, std::basic_istream<Char>::beg);
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
bool eof() const noexcept
{
return source->eof();
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
bool peek_eof() const
{
using stream_traits = typename std::remove_pointer_t<decltype(source)>::traits_type;
return eof() || source->peek() == stream_traits::eof();
}
TOML_NODISCARD
TOML_ALWAYS_INLINE
bool error() const noexcept
{
return !(*source);
}
TOML_NODISCARD
unsigned int operator()()
{
auto val = source->get();
if (val == std::basic_istream<Char>::traits_type::eof())
return 0xFFFFFFFFu;
return static_cast<unsigned int>(val);
}
};
TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf);
struct utf8_codepoint final
{
char32_t value;
char bytes[4];
source_position position;
TOML_NODISCARD
std::string_view as_view() const noexcept
{
return bytes[3] ? std::string_view{ bytes, 4_sz } : std::string_view{ bytes };
}
TOML_NODISCARD
TOML_ATTR(pure)
constexpr operator char32_t&() noexcept
{
return value;
}
TOML_NODISCARD
TOML_ATTR(pure)
constexpr operator const char32_t&() const noexcept
{
return value;
}
TOML_NODISCARD
TOML_ATTR(pure)
constexpr const char32_t& operator*() const noexcept
{
return value;
}
};
static_assert(std::is_trivial_v<utf8_codepoint>);
static_assert(std::is_standard_layout_v<utf8_codepoint>);
TOML_ABI_NAMESPACE_END; // TOML_LARGE_FILES
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
struct TOML_ABSTRACT_BASE utf8_reader_interface
{
TOML_NODISCARD
virtual const source_path_ptr& source_path() const noexcept = 0;
TOML_NODISCARD
virtual const utf8_codepoint* read_next() = 0;
TOML_NODISCARD
virtual bool peek_eof() const = 0;
#if !TOML_EXCEPTIONS
TOML_NODISCARD
virtual optional<parse_error>&& error() noexcept = 0;
#endif
virtual ~utf8_reader_interface() noexcept = default;
};
template <typename T>
class TOML_EMPTY_BASES TOML_API utf8_reader final : public utf8_reader_interface
{
private:
utf8_byte_stream<T> stream;
utf8_decoder decoder;
utf8_codepoint codepoints[2];
size_t cp_idx = 1;
uint8_t current_byte_count{};
source_path_ptr source_path_;
#if !TOML_EXCEPTIONS
optional<parse_error> err;
#endif
public:
template <typename U, typename String = std::string_view>
explicit utf8_reader(U&& source, String&& source_path = {}) noexcept(
std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
: stream{ static_cast<U&&>(source) }
{
std::memset(codepoints, 0, sizeof(codepoints));
codepoints[0].position = { 1, 1 };
codepoints[1].position = { 1, 1 };
if (!source_path.empty())
source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
}
TOML_NODISCARD
const source_path_ptr& source_path() const noexcept override
{
return source_path_;
}
TOML_NODISCARD
const utf8_codepoint* read_next() override
{
TOML_ERROR_CHECK;
auto& prev = codepoints[(cp_idx - 1_sz) % 2_sz];
if (stream.eof())
return nullptr;
else if (stream.error())
TOML_ERROR("An error occurred while reading from the underlying stream", prev.position, source_path_);
else if (decoder.error())
TOML_ERROR("Encountered invalid utf-8 sequence", prev.position, source_path_);
TOML_ERROR_CHECK;
while (true)
{
uint8_t next_byte;
{
unsigned int next_byte_raw{ 0xFFFFFFFFu };
if constexpr (noexcept(stream()) || !TOML_EXCEPTIONS)
{
next_byte_raw = stream();
}
#if TOML_EXCEPTIONS
else
{
try
{
next_byte_raw = stream();
}
catch (const std::exception& exc)
{
throw parse_error{ exc.what(), prev.position, source_path_ };
}
catch (...)
{
throw parse_error{ "An unspecified error occurred", prev.position, source_path_ };
}
}
#endif
if (next_byte_raw >= 256u)
{
if (stream.eof())
{
if (decoder.needs_more_input())
TOML_ERROR("Encountered EOF during incomplete utf-8 code point sequence",
prev.position,
source_path_);
return nullptr;
}
else
TOML_ERROR("An error occurred while reading from the underlying stream",
prev.position,
source_path_);
}
TOML_ERROR_CHECK;
next_byte = static_cast<uint8_t>(next_byte_raw);
}
decoder(next_byte);
if (decoder.error())
TOML_ERROR("Encountered invalid utf-8 sequence", prev.position, source_path_);
TOML_ERROR_CHECK;
auto& current = codepoints[cp_idx % 2_sz];
current.bytes[current_byte_count++] = static_cast<char>(next_byte);
if (decoder.has_code_point())
{
// store codepoint
current.value = decoder.codepoint;
// reset prev (will be the next 'current')
std::memset(prev.bytes, 0, sizeof(prev.bytes));
current_byte_count = {};
if (is_line_break<false>(current.value))
prev.position = { static_cast<source_index>(current.position.line + 1), 1 };
else
prev.position = { current.position.line,
static_cast<source_index>(current.position.column + 1) };
cp_idx++;
return &current;
}
}
TOML_UNREACHABLE;
}
TOML_NODISCARD
bool peek_eof() const override
{
return stream.peek_eof();
}
#if !TOML_EXCEPTIONS
TOML_NODISCARD
optional<parse_error>&& error() noexcept override
{
return std::move(err);
}
#endif
};
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string &&) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string &&) -> utf8_reader<std::basic_istream<Char>>;
class TOML_EMPTY_BASES TOML_API utf8_buffered_reader final : public utf8_reader_interface
{
public:
static constexpr size_t max_history_length = 72;
private:
static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
utf8_reader_interface& reader;
struct
{
utf8_codepoint buffer[history_buffer_size];
size_t count, first;
} history = {};
const utf8_codepoint* head = {};
size_t negative_offset = {};
public:
explicit utf8_buffered_reader(utf8_reader_interface& reader_) noexcept;
const source_path_ptr& source_path() const noexcept override;
const utf8_codepoint* read_next() override;
const utf8_codepoint* step_back(size_t count) noexcept;
bool peek_eof() const override;
#if !TOML_EXCEPTIONS
optional<parse_error>&& error() noexcept override;
#endif
};
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_IMPL_NAMESPACE_END;
#undef TOML_ERROR_CHECK
#undef TOML_ERROR
/// \endcond

View File

@ -1,116 +0,0 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
#if !TOML_PARSER
#error This header cannot not be included when TOML_PARSER is disabled.
#endif
//# }}
#include "utf8_streams.h"
/// \cond
#if !TOML_EXCEPTIONS
#undef TOML_ERROR_CHECK
#define TOML_ERROR_CHECK \
if (reader.error()) \
return nullptr
#else
#define TOML_ERROR_CHECK (void)0
#endif
TOML_IMPL_NAMESPACE_START
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
TOML_EXTERNAL_LINKAGE
utf8_buffered_reader::utf8_buffered_reader(utf8_reader_interface & reader_) noexcept : reader{ reader_ }
{}
TOML_EXTERNAL_LINKAGE
const source_path_ptr& utf8_buffered_reader::source_path() const noexcept
{
return reader.source_path();
}
TOML_EXTERNAL_LINKAGE
const utf8_codepoint* utf8_buffered_reader::read_next()
{
TOML_ERROR_CHECK;
if (negative_offset)
{
negative_offset--;
// an entry negative offset of 1 just means "replay the current head"
if (!negative_offset)
return head;
// otherwise step back into the history buffer
else
return history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size);
}
else
{
// first character read from stream
if TOML_UNLIKELY(!history.count && !head)
head = reader.read_next();
// subsequent characters and not eof
else if (head)
{
if TOML_UNLIKELY(history.count < history_buffer_size)
history.buffer[history.count++] = *head;
else
history.buffer[(history.first++ + history_buffer_size) % history_buffer_size] = *head;
head = reader.read_next();
}
return head;
}
}
TOML_EXTERNAL_LINKAGE
const utf8_codepoint* utf8_buffered_reader::step_back(size_t count) noexcept
{
TOML_ERROR_CHECK;
TOML_ASSERT(history.count);
TOML_ASSERT(negative_offset + count <= history.count);
negative_offset += count;
return negative_offset
? history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size)
: head;
}
TOML_EXTERNAL_LINKAGE
bool utf8_buffered_reader::peek_eof() const
{
return reader.peek_eof();
}
#if !TOML_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
optional<parse_error>&& utf8_buffered_reader::error() noexcept
{
return reader.error();
}
#endif
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_IMPL_NAMESPACE_END;
#undef TOML_ERROR_CHECK
/// \endcond

View File

@ -2,15 +2,18 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "date_time.h"
#include "node.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_DISABLE_ARITHMETIC_WARNINGS;
/// \cond
// clang-format off
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
#define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
#else
#define TOML_SA_VALUE_MESSAGE_WSTRING
@ -69,11 +72,6 @@
// clang-format on
/// \endcond
TOML_PUSH_WARNINGS;
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_DISABLE_INIT_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
/// \cond
TOML_IMPL_NAMESPACE_START
{
@ -84,7 +82,10 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD
static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
{
return T(static_cast<Args&&>(args)...);
if constexpr (std::is_aggregate_v<T>)
return T{ static_cast<Args&&>(args)... };
else
return T(static_cast<Args&&>(args)...);
}
};
@ -100,7 +101,7 @@ TOML_IMPL_NAMESPACE_START
}
};
#if TOML_HAS_CHAR8 || TOML_WINDOWS_COMPAT
#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
struct string_maker
{
@ -108,21 +109,29 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD
static std::string make(T&& arg) noexcept
{
#if TOML_HAS_CHAR8
if constexpr (is_one_of<std::decay_t<T>, char8_t*, const char8_t*>)
using arg_type = std::decay_t<T>;
#if TOML_HAS_CHAR8
if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>)
{
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
else if constexpr (is_one_of<remove_cvref_t<T>, std::u8string, std::u8string_view>)
}
if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>)
{
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())),
arg.length());
#endif // TOML_HAS_CHAR8
}
#endif
#if TOML_WINDOWS_COMPAT
if constexpr (is_wide_string<T>)
#if TOML_ENABLE_WINDOWS_COMPAT
if constexpr (is_wide_string<arg_type>)
{
return narrow(static_cast<T&&>(arg));
#endif // TOML_WINDOWS_COMPAT
}
#endif
}
};
#if TOML_HAS_CHAR8
#if TOML_HAS_CHAR8
template <>
struct native_value_maker<std::string, char8_t*> : string_maker
{};
@ -135,8 +144,9 @@ TOML_IMPL_NAMESPACE_START
template <>
struct native_value_maker<std::string, std::u8string_view> : string_maker
{};
#endif // TOML_HAS_CHAR8
#if TOML_WINDOWS_COMPAT
#endif // TOML_HAS_CHAR8
#if TOML_ENABLE_WINDOWS_COMPAT
template <>
struct native_value_maker<std::string, wchar_t*> : string_maker
{};
@ -149,13 +159,12 @@ TOML_IMPL_NAMESPACE_START
template <>
struct native_value_maker<std::string, std::wstring_view> : string_maker
{};
#endif // TOML_WINDOWS_COMPAT
#endif // TOML_ENABLE_WINDOWS_COMPAT
#endif // TOML_HAS_CHAR8 || TOML_WINDOWS_COMPAT
#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
template <typename T>
TOML_NODISCARD
TOML_ATTR(const)
TOML_CONST_GETTER
inline optional<T> node_integer_cast(int64_t val) noexcept
{
static_assert(node_type_of<T> == node_type::integer);
@ -200,20 +209,18 @@ TOML_NAMESPACE_START
/// - double
/// - bool
template <typename ValueType>
class TOML_API value final : public node
class value : public node
{
static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
"A toml::value<> must model one of the native TOML value types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
private:
friend class TOML_PARSER_TYPENAME;
/// \cond
friend class TOML_PARSER_TYPENAME;
template <typename T, typename U>
TOML_NODISCARD
TOML_ALWAYS_INLINE
TOML_ATTR(const)
TOML_CONST_INLINE_GETTER
static auto as_value([[maybe_unused]] U* ptr) noexcept
{
if constexpr (std::is_same_v<value_type, T>)
@ -269,6 +276,18 @@ TOML_NAMESPACE_START
#endif
}
/// \brief Copy constructor with flags override.
TOML_NODISCARD_CTOR
value(const value& other, value_flags flags) noexcept //
: node(other),
val_{ other.val_ },
flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
{
#if TOML_LIFETIME_HOOKS
TOML_VALUE_CREATED;
#endif
}
/// \brief Move constructor.
TOML_NODISCARD_CTOR
value(value&& other) noexcept //
@ -281,6 +300,18 @@ TOML_NAMESPACE_START
#endif
}
/// \brief Move constructor with flags override.
TOML_NODISCARD_CTOR
value(value&& other, value_flags flags) noexcept //
: node(std::move(other)),
val_{ std::move(other.val_) },
flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
{
#if TOML_LIFETIME_HOOKS
TOML_VALUE_CREATED;
#endif
}
/// \brief Copy-assignment operator.
value& operator=(const value& rhs) noexcept
{
@ -303,7 +334,7 @@ TOML_NAMESPACE_START
}
#if TOML_LIFETIME_HOOKS
~value() noexcept override
~value() noexcept
{
TOML_VALUE_DESTROYED;
}
@ -322,86 +353,20 @@ TOML_NAMESPACE_START
/// - node_type::date
/// - node_type::time
/// - node_type::date_time
TOML_NODISCARD
node_type type() const noexcept override
TOML_CONST_INLINE_GETTER
node_type type() const noexcept final
{
return impl::node_type_of<value_type>;
}
TOML_NODISCARD
bool is_table() const noexcept override
{
return false;
}
TOML_NODISCARD
bool is_array() const noexcept override
{
return false;
}
TOML_NODISCARD
bool is_value() const noexcept override
{
return true;
}
TOML_NODISCARD
bool is_string() const noexcept override
{
return std::is_same_v<value_type, std::string>;
}
TOML_NODISCARD
bool is_integer() const noexcept override
{
return std::is_same_v<value_type, int64_t>;
}
TOML_NODISCARD
bool is_floating_point() const noexcept override
{
return std::is_same_v<value_type, double>;
}
TOML_NODISCARD
bool is_number() const noexcept override
{
return impl::is_one_of<value_type, int64_t, double>;
}
TOML_NODISCARD
bool is_boolean() const noexcept override
{
return std::is_same_v<value_type, bool>;
}
TOML_NODISCARD
bool is_date() const noexcept override
{
return std::is_same_v<value_type, date>;
}
TOML_NODISCARD
bool is_time() const noexcept override
{
return std::is_same_v<value_type, time>;
}
TOML_NODISCARD
bool is_date_time() const noexcept override
{
return std::is_same_v<value_type, date_time>;
}
TOML_NODISCARD
bool is_homogeneous(node_type ntype) const noexcept override
TOML_PURE_GETTER
bool is_homogeneous(node_type ntype) const noexcept final
{
return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
}
TOML_NODISCARD
bool is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept override
TOML_PURE_GETTER
bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
@ -411,8 +376,8 @@ TOML_NAMESPACE_START
return true;
}
TOML_NODISCARD
bool is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept override
TOML_PURE_GETTER
bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
@ -422,8 +387,9 @@ TOML_NAMESPACE_START
return true;
}
/// \cond
template <typename ElemType = void>
TOML_NODISCARD
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<ElemType>;
@ -439,92 +405,219 @@ TOML_NAMESPACE_START
else
return impl::node_type_of<type> == impl::node_type_of<value_type>;
}
/// \endcond
/// \brief Returns `false`.
TOML_CONST_INLINE_GETTER
bool is_table() const noexcept final
{
return false;
}
/// \brief Returns `false`.
TOML_CONST_INLINE_GETTER
bool is_array() const noexcept final
{
return false;
}
/// \brief Returns `false`.
TOML_CONST_INLINE_GETTER
bool is_array_of_tables() const noexcept final
{
return false;
}
/// \brief Returns `true`.
TOML_CONST_INLINE_GETTER
bool is_value() const noexcept final
{
return true;
}
/// \brief Returns `true` if the #value_type is std::string.
TOML_CONST_INLINE_GETTER
bool is_string() const noexcept final
{
return std::is_same_v<value_type, std::string>;
}
/// \brief Returns `true` if the #value_type is int64_t.
TOML_CONST_INLINE_GETTER
bool is_integer() const noexcept final
{
return std::is_same_v<value_type, int64_t>;
}
/// \brief Returns `true` if the #value_type is `double`.
TOML_CONST_INLINE_GETTER
bool is_floating_point() const noexcept final
{
return std::is_same_v<value_type, double>;
}
/// \brief Returns `true` if the #value_type is int64_t or `double`.
TOML_CONST_INLINE_GETTER
bool is_number() const noexcept final
{
return impl::is_one_of<value_type, int64_t, double>;
}
/// \brief Returns `true` if the #value_type is `bool`.
TOML_CONST_INLINE_GETTER
bool is_boolean() const noexcept final
{
return std::is_same_v<value_type, bool>;
}
/// \brief Returns `true` if the #value_type is toml::date.
TOML_CONST_INLINE_GETTER
bool is_date() const noexcept final
{
return std::is_same_v<value_type, date>;
}
/// \brief Returns `true` if the #value_type is toml::time.
TOML_CONST_INLINE_GETTER
bool is_time() const noexcept final
{
return std::is_same_v<value_type, time>;
}
/// \brief Returns `true` if the #value_type is toml_date_time.
TOML_CONST_INLINE_GETTER
bool is_date_time() const noexcept final
{
return std::is_same_v<value_type, date_time>;
}
/// @}
/// \name Type casts
/// @{
TOML_NODISCARD
value<std::string>* as_string() noexcept override
/// \brief Returns `nullptr`.
TOML_CONST_INLINE_GETTER
table* as_table() noexcept final
{
return nullptr;
}
/// \brief Returns `nullptr`.
TOML_CONST_INLINE_GETTER
array* as_array() noexcept final
{
return nullptr;
}
/// \brief Returns a pointer to the value if it is a value<std::string>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<std::string>* as_string() noexcept final
{
return as_value<std::string>(this);
}
TOML_NODISCARD
value<int64_t>* as_integer() noexcept override
/// \brief Returns a pointer to the value if it is a value<int64_t>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<int64_t>* as_integer() noexcept final
{
return as_value<int64_t>(this);
}
TOML_NODISCARD
value<double>* as_floating_point() noexcept override
/// \brief Returns a pointer to the value if it is a value<double>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<double>* as_floating_point() noexcept final
{
return as_value<double>(this);
}
TOML_NODISCARD
value<bool>* as_boolean() noexcept override
/// \brief Returns a pointer to the value if it is a value<bool>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<bool>* as_boolean() noexcept final
{
return as_value<bool>(this);
}
TOML_NODISCARD
value<date>* as_date() noexcept override
/// \brief Returns a pointer to the value if it is a value<date>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<date>* as_date() noexcept final
{
return as_value<date>(this);
}
TOML_NODISCARD
value<time>* as_time() noexcept override
/// \brief Returns a pointer to the value if it is a value<time>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<time>* as_time() noexcept final
{
return as_value<time>(this);
}
TOML_NODISCARD
value<date_time>* as_date_time() noexcept override
/// \brief Returns a pointer to the value if it is a value<date_time>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
value<date_time>* as_date_time() noexcept final
{
return as_value<date_time>(this);
}
TOML_NODISCARD
const value<std::string>* as_string() const noexcept override
/// \brief Returns `nullptr`.
TOML_CONST_INLINE_GETTER
const table* as_table() const noexcept final
{
return nullptr;
}
/// \brief Returns `nullptr`.
TOML_CONST_INLINE_GETTER
const array* as_array() const noexcept final
{
return nullptr;
}
/// \brief Returns a const-qualified pointer to the value if it is a value<std::string>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<std::string>* as_string() const noexcept final
{
return as_value<std::string>(this);
}
TOML_NODISCARD
const value<int64_t>* as_integer() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<int64_t>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<int64_t>* as_integer() const noexcept final
{
return as_value<int64_t>(this);
}
TOML_NODISCARD
const value<double>* as_floating_point() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<double>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<double>* as_floating_point() const noexcept final
{
return as_value<double>(this);
}
TOML_NODISCARD
const value<bool>* as_boolean() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<bool>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<bool>* as_boolean() const noexcept final
{
return as_value<bool>(this);
}
TOML_NODISCARD
const value<date>* as_date() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<date>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<date>* as_date() const noexcept final
{
return as_value<date>(this);
}
TOML_NODISCARD
const value<time>* as_time() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<time>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<time>* as_time() const noexcept final
{
return as_value<time>(this);
}
TOML_NODISCARD
const value<date_time>* as_date_time() const noexcept override
/// \brief Returns a const-qualified pointer to the value if it is a value<date_time>, otherwise `nullptr`.
TOML_CONST_INLINE_GETTER
const value<date_time>* as_date_time() const noexcept final
{
return as_value<date_time>(this);
}
@ -535,68 +628,109 @@ TOML_NAMESPACE_START
/// @{
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type& get() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type&& get() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
const value_type& get() const& noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
const value_type&& get() const&& noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type& operator*() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
value_type&& operator*() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
const value_type& operator*() const& noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
const value_type&& operator*() const&& noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator value_type&() & noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (rvalue overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator value_type&&() && noexcept
{
return static_cast<value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value (const overload).
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
explicit operator const value_type&() const& noexcept
{
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
explicit operator const value_type&&() && noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a pointer to the underlying value.
///
/// \availability This operator is only available when #value_type is a class/struct.
TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
TOML_PURE_INLINE_GETTER
value_type* operator->() noexcept
{
return &val_;
}
/// \brief Returns a pointer to the underlying value (const overload).
///
/// \availability This operator is only available when #value_type is a class/struct.
TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
TOML_PURE_INLINE_GETTER
const value_type* operator->() const noexcept
{
return &val_;
}
/// @}
/// \name Metadata
@ -619,11 +753,6 @@ TOML_NAMESPACE_START
/// @}
/// \brief Prints the value out to a stream as formatted TOML.
template <typename Char, typename T>
friend std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, const value<T>& rhs);
// implemented in toml_default_formatter.h
/// \brief Value-assignment operator.
value& operator=(value_arg rhs) noexcept
{
@ -641,7 +770,7 @@ TOML_NAMESPACE_START
return *this;
}
/// \name Equality
/// \name Equality and Comparison
/// @{
/// \brief Value equality operator.
@ -650,12 +779,12 @@ TOML_NAMESPACE_START
{
if constexpr (std::is_same_v<value_type, double>)
{
const auto lhs_class = impl::fpclassify(lhs.val_);
const auto rhs_class = impl::fpclassify(rhs);
if (lhs_class == impl::fp_class::nan && rhs_class == impl::fp_class::nan)
return true;
if ((lhs_class == impl::fp_class::nan) != (rhs_class == impl::fp_class::nan))
const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
if (lhs_nan != rhs_nan)
return false;
if (lhs_nan)
return true;
}
return lhs.val_ == rhs;
}
@ -823,25 +952,29 @@ TOML_NAMESPACE_START
}
/// @}
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the value out to a stream as formatted TOML.
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& lhs, const value& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
#endif
};
/// \cond
template <typename T>
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
#if !TOML_HEADER_ONLY
extern template class TOML_API value<std::string>;
extern template class TOML_API value<int64_t>;
extern template class TOML_API value<double>;
extern template class TOML_API value<bool>;
extern template class TOML_API value<date>;
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
template <typename T>
value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
template <typename T>
TOML_NODISCARD
inline decltype(auto) node::get_value_exact() const noexcept
inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace impl;
@ -864,7 +997,7 @@ TOML_NAMESPACE_START
else if constexpr (std::is_same_v<T, std::wstring>)
{
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
return widen(str);
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
@ -888,13 +1021,14 @@ TOML_NAMESPACE_START
}
template <typename T>
inline optional<T> node::value_exact() const noexcept
TOML_NODISCARD
inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace impl;
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieving values as wide-character strings with node::value_exact() is only "
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
static_assert((is_native<T> || can_represent_native<T>)&&!is_cvref<T>,
TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
@ -910,13 +1044,14 @@ TOML_NAMESPACE_START
}
template <typename T>
inline optional<T> node::value() const noexcept
TOML_NODISCARD
inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace impl;
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieving values as wide-character strings with node::value() is only "
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>)&&!is_cvref<T>,
TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
@ -1026,17 +1161,18 @@ TOML_NAMESPACE_START
}
template <typename T>
inline auto node::value_or(T && default_value) const noexcept
TOML_NODISCARD
inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace impl;
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieving values as wide-character strings with node::value_or() is only "
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (is_wide_string<T>)
{
#if TOML_WINDOWS_COMPAT
#if TOML_ENABLE_WINDOWS_COMPAT
if (type() == node_type::string)
return widen(*ref_cast<std::string>());
@ -1056,39 +1192,47 @@ TOML_NAMESPACE_START
std::decay_t<T>>;
using traits = value_traits<value_type>;
// clang-format off
static_assert(
traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
"The default value type of node::value_or() must be one of:" TOML_SA_LIST_NEW
"A native TOML value type" TOML_SA_NATIVE_VALUE_TYPE_LIST
"The default value type of node::value_or() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
TOML_SA_LIST_NXT
"A non-view type capable of losslessly representing a native TOML value type" TOML_SA_LIST_BEG
"std::string"
#if TOML_WINDOWS_COMPAT
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
TOML_SA_LIST_BEG "std::string"
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring"
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" TOML_SA_LIST_SEP
"any floating-point type >= 64 bits" TOML_SA_LIST_END
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT
"A non-view type capable of (reasonably) representing a native TOML value type" TOML_SA_LIST_BEG
"any other integer type" TOML_SA_LIST_SEP "any floating-point type >= 32 bits" TOML_SA_LIST_END
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
TOML_SA_LIST_BEG "any other integer type"
TOML_SA_LIST_SEP "any floating-point type >= 32 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "A compatible view type" TOML_SA_LIST_BEG "std::string_view"
#if TOML_HAS_CHAR8
TOML_SA_LIST_NXT "A compatible view type"
TOML_SA_LIST_BEG "std::string_view"
#if TOML_HAS_CHAR8
TOML_SA_LIST_SEP "std::u8string_view"
#endif
#if TOML_WINDOWS_COMPAT
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring_view"
#endif
#endif
TOML_SA_LIST_SEP "const char*"
#if TOML_HAS_CHAR8
#if TOML_HAS_CHAR8
TOML_SA_LIST_SEP "const char8_t*"
#endif
#if TOML_WINDOWS_COMPAT
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_SA_LIST_SEP "const wchar_t*"
#endif
TOML_SA_LIST_END);
#endif
TOML_SA_LIST_END
);
// clang-format on
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
@ -1108,57 +1252,14 @@ TOML_NAMESPACE_START
}
}
#if !TOML_HEADER_ONLY
#define TOML_EXTERN(name, T) \
extern template TOML_API \
optional<T> node::name<T>() const noexcept
TOML_EXTERN(value_exact, std::string_view);
TOML_EXTERN(value_exact, std::string);
TOML_EXTERN(value_exact, const char*);
TOML_EXTERN(value_exact, int64_t);
TOML_EXTERN(value_exact, double);
TOML_EXTERN(value_exact, date);
TOML_EXTERN(value_exact, time);
TOML_EXTERN(value_exact, date_time);
TOML_EXTERN(value_exact, bool);
TOML_EXTERN(value, std::string_view);
TOML_EXTERN(value, std::string);
TOML_EXTERN(value, const char*);
TOML_EXTERN(value, signed char);
TOML_EXTERN(value, signed short);
TOML_EXTERN(value, signed int);
TOML_EXTERN(value, signed long);
TOML_EXTERN(value, signed long long);
TOML_EXTERN(value, unsigned char);
TOML_EXTERN(value, unsigned short);
TOML_EXTERN(value, unsigned int);
TOML_EXTERN(value, unsigned long);
TOML_EXTERN(value, unsigned long long);
TOML_EXTERN(value, double);
TOML_EXTERN(value, float);
TOML_EXTERN(value, date);
TOML_EXTERN(value, time);
TOML_EXTERN(value, date_time);
TOML_EXTERN(value, bool);
#if TOML_HAS_CHAR8
TOML_EXTERN(value_exact, std::u8string_view);
TOML_EXTERN(value_exact, std::u8string);
TOML_EXTERN(value_exact, const char8_t*);
TOML_EXTERN(value, std::u8string_view);
TOML_EXTERN(value, std::u8string);
TOML_EXTERN(value, const char8_t*);
#endif
#if TOML_WINDOWS_COMPAT
TOML_EXTERN(value_exact, std::wstring);
TOML_EXTERN(value, std::wstring);
#endif
#undef TOML_EXTERN
#endif // !TOML_HEADER_ONLY
/// \endcond
}
TOML_NAMESPACE_END;
TOML_POP_WARNINGS;
/// \cond
#if TOML_EXTERN_TEMPLATES && !TOML_IMPLEMENTATION
#include "value_extern.inl"
#endif
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,21 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
//# {{
#include "preprocessor.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "value.h"
#include "header_start.h"
#if TOML_EXTERN_TEMPLATES && TOML_IMPLEMENTATION
#include "value_extern.inl"
#endif // TOML_EXTERN_TEMPLATES
#include "header_end.h"

View File

@ -0,0 +1,76 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
/// \cond
#include "value.h"
TOML_NAMESPACE_START
{
TOML_EXTERN
template class TOML_API value<std::string>;
TOML_EXTERN
template class TOML_API value<int64_t>;
TOML_EXTERN
template class TOML_API value<double>;
TOML_EXTERN
template class TOML_API value<bool>;
TOML_EXTERN
template class TOML_API value<date>;
TOML_EXTERN
template class TOML_API value<time>;
TOML_EXTERN
template class TOML_API value<date_time>;
#define TOML_EXTERN_FUNC(name, T) \
TOML_EXTERN \
template TOML_API \
optional<T> node::name<T>() const TOML_EXTERN_NOEXCEPT(impl::value_retrieval_is_nothrow<T>)
TOML_EXTERN_FUNC(value_exact, std::string_view);
TOML_EXTERN_FUNC(value_exact, std::string);
TOML_EXTERN_FUNC(value_exact, const char*);
TOML_EXTERN_FUNC(value_exact, int64_t);
TOML_EXTERN_FUNC(value_exact, double);
TOML_EXTERN_FUNC(value_exact, date);
TOML_EXTERN_FUNC(value_exact, time);
TOML_EXTERN_FUNC(value_exact, date_time);
TOML_EXTERN_FUNC(value_exact, bool);
TOML_EXTERN_FUNC(value, std::string_view);
TOML_EXTERN_FUNC(value, std::string);
TOML_EXTERN_FUNC(value, const char*);
TOML_EXTERN_FUNC(value, signed char);
TOML_EXTERN_FUNC(value, signed short);
TOML_EXTERN_FUNC(value, signed int);
TOML_EXTERN_FUNC(value, signed long);
TOML_EXTERN_FUNC(value, signed long long);
TOML_EXTERN_FUNC(value, unsigned char);
TOML_EXTERN_FUNC(value, unsigned short);
TOML_EXTERN_FUNC(value, unsigned int);
TOML_EXTERN_FUNC(value, unsigned long);
TOML_EXTERN_FUNC(value, unsigned long long);
TOML_EXTERN_FUNC(value, double);
TOML_EXTERN_FUNC(value, float);
TOML_EXTERN_FUNC(value, date);
TOML_EXTERN_FUNC(value, time);
TOML_EXTERN_FUNC(value, date_time);
TOML_EXTERN_FUNC(value, bool);
#if TOML_HAS_CHAR8
TOML_EXTERN_FUNC(value_exact, std::u8string_view);
TOML_EXTERN_FUNC(value_exact, std::u8string);
TOML_EXTERN_FUNC(value_exact, const char8_t*);
TOML_EXTERN_FUNC(value, std::u8string_view);
TOML_EXTERN_FUNC(value, std::u8string);
TOML_EXTERN_FUNC(value, const char8_t*);
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERN_FUNC(value_exact, std::wstring);
TOML_EXTERN_FUNC(value, std::wstring);
#endif
#undef TOML_EXTERN_FUNC
}
TOML_NAMESPACE_END;
/// \endcond

View File

@ -2,11 +2,10 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#define TOML_LIB_MAJOR 2
#define TOML_LIB_MINOR 6
#define TOML_LIB_MAJOR 3
#define TOML_LIB_MINOR 0
#define TOML_LIB_PATCH 0
#define TOML_LANG_MAJOR 1

View File

@ -0,0 +1,139 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted YAML.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
/// apple.color = "red"
/// apple.taste.sweet = true
///
/// [fruit.apple.texture]
/// smooth = true
/// )"sv);
/// std::cout << toml::yaml_formatter{ some_toml } << "\n";
/// \ecpp
///
/// \out
/// fruit:
/// apple:
/// color: red
/// taste:
/// sweet: true
/// texture:
/// smooth: true
/// \eout
class yaml_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
TOML_API
void print_yaml_string(const value<std::string>&);
TOML_API
void print(const toml::table&, bool = false);
TOML_API
void print(const toml::array&, bool = false);
TOML_API
void print();
static constexpr impl::formatter_constants constants = {
//
format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
format_flags::allow_multi_line_strings, // ignored
".inf"sv,
"-.inf"sv,
".NAN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a yaml_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_unicode_strings //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers;
/// \brief Constructs a YAML formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if defined(DOXYGEN) || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a YAML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid YAML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::yaml_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::yaml_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a: b
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as YAML.
friend std::ostream& operator<<(std::ostream& lhs, yaml_formatter& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as YAML (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, yaml_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,162 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "yaml_formatter.h"
#include "print_to_stream.h"
#include "table.h"
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print_yaml_string(const value<std::string>& str)
{
if (str->empty())
{
base::print(str);
return;
}
bool contains_newline = false;
for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
contains_newline = *c == '\n';
if (contains_newline)
{
print_unformatted("|-"sv);
increase_indent();
auto line_end = str->c_str() - 1u;
const auto end = str->c_str() + str->length();
while (line_end != end)
{
auto line_start = line_end + 1u;
line_end = line_start;
for (; line_end != end && *line_end != '\n'; line_end++)
;
if TOML_LIKELY(line_start != line_end || line_end != end)
{
print_newline();
print_indent();
print_unformatted(std::string_view{ line_start, static_cast<size_t>(line_end - line_start) });
}
}
decrease_indent();
}
else
print_string(*str, false, true);
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print(const toml::table& tbl, bool parent_is_array)
{
if (tbl.empty())
{
print_unformatted("{}"sv);
return;
}
increase_indent();
for (auto&& [k, v] : tbl)
{
if (!parent_is_array)
{
print_newline();
print_indent();
}
parent_is_array = false;
print_string(k.str(), false, true);
print_unformatted(": "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
default: print_value(v, type);
}
}
decrease_indent();
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print(const toml::array& arr, bool parent_is_array)
{
if (arr.empty())
{
print_unformatted("[]"sv);
return;
}
increase_indent();
for (auto&& v : arr)
{
if (!parent_is_array)
{
print_newline();
print_indent();
}
parent_is_array = false;
print_unformatted("- "sv);
const auto type = v.type();
TOML_ASSUME(type != node_type::none);
switch (type)
{
case node_type::table: print(*reinterpret_cast<const table*>(&v), true); break;
case node_type::array: print(*reinterpret_cast<const array*>(&v), true); break;
case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
default: print_value(v, type);
}
}
decrease_indent();
}
TOML_EXTERNAL_LINKAGE
void yaml_formatter::print()
{
if (dump_failed_parse_result())
return;
switch (auto source_type = source().type())
{
case node_type::table:
decrease_indent(); // so root kvps and tables have the same indent
print(*reinterpret_cast<const table*>(&source()));
break;
case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source())); break;
default: print_value(source(), source_type);
}
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -2,153 +2,188 @@
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#ifndef TOMLPLUSPLUS_H
#define TOMLPLUSPLUS_H
#ifndef INCLUDE_TOMLPLUSPLUS_H
#define INCLUDE_TOMLPLUSPLUS_H
#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
//# Note: most of these would be included transitively but
//# they're listed explicitly here because this file
//# is used as the source for generate_single_header.py.
//# Note: these would be included transitively as with any normal C++ project but
//# they're listed explicitly here because this file is used as the source for generate_single_header.py.
#include "impl/preprocessor.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
#include "impl/common.h"
#include "impl/date_time.h"
// misc warning false-positives
#if TOML_MSVC
#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
#elif TOML_CLANG
#pragma clang diagnostic ignored "-Wheader-hygiene"
#if TOML_CLANG >= 12
#pragma clang diagnostic ignored "-Wc++20-extensions"
#endif
#if TOML_CLANG == 13
#pragma clang diagnostic ignored "-Wreserved-identifier"
#endif
#endif
#include "impl/std_new.h"
#include "impl/std_string.h"
#include "impl/std_optional.h"
#include "impl/forward_declarations.h"
#include "impl/print_to_stream.h"
#include "impl/source_region.h"
#include "impl/date_time.h"
#include "impl/at_path.h"
#include "impl/node.h"
#include "impl/value.h"
#include "impl/array.h"
#include "impl/table.h"
#include "impl/node_view.h"
#include "impl/utf8.h"
#if TOML_PARSER
#include "impl/parse_error.h"
#include "impl/parse_result.h"
#include "impl/utf8_streams.h"
#include "impl/parser.h"
#endif // TOML_PARSER
#include "impl/value.h"
#include "impl/make_node.h"
#include "impl/array.h"
#include "impl/key.h"
#include "impl/table.h"
#include "impl/unicode.h"
#include "impl/parse_error.h"
#include "impl/parse_result.h"
#include "impl/parser.h"
#include "impl/formatter.h"
#include "impl/default_formatter.h"
#include "impl/toml_formatter.h"
#include "impl/json_formatter.h"
#include "impl/yaml_formatter.h"
#if TOML_IMPLEMENTATION
#include "impl/node_impl.h"
#include "impl/array_impl.h"
#include "impl/table_impl.h"
#if TOML_PARSER
#include "impl/utf8_streams_impl.h"
#include "impl/parser_impl.h"
#endif // TOML_PARSER
#include "impl/default_formatter_impl.h"
#include "impl/json_formatter_impl.h"
#if !TOML_HEADER_ONLY
#include "impl/template_instantiations.h"
#endif // !TOML_HEADER_ONLY
#endif // TOML_IMPLEMENTATION
TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS
#include "impl/std_string.inl"
#include "impl/print_to_stream.inl"
#include "impl/node.inl"
#include "impl/node_view.inl"
#include "impl/at_path.inl"
#include "impl/value.inl"
#include "impl/array.inl"
#include "impl/table.inl"
#include "impl/unicode.inl"
#include "impl/parser.inl"
#include "impl/formatter.inl"
#include "impl/toml_formatter.inl"
#include "impl/json_formatter.inl"
#include "impl/yaml_formatter.inl"
#endif // TOML_IMPLEMENTATION
TOML_POP_WARNINGS;
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACES
#undef TOML_ABSTRACT_BASE
#undef TOML_ALWAYS_INLINE
#undef TOML_ANON_NAMESPACE
#undef TOML_ANON_NAMESPACE_END
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARM
#undef TOML_ASSERT
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
#undef TOML_CLANG
#undef TOML_COMPILER_EXCEPTIONS
#undef TOML_CONCAT
#undef TOML_CONCAT_1
#undef TOML_CONSTEVAL
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_CPP
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_INIT_WARNINGS
#undef TOML_DISABLE_SHADOW_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS
#undef TOML_DISABLE_SUGGEST_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
#undef TOML_DISABLE_WARNINGS
#undef TOML_EMPTY_BASES
#undef TOML_ENABLE_IF
#undef TOML_ENABLE_WARNINGS
#undef TOML_EVAL_BOOL_0
#undef TOML_EVAL_BOOL_1
#undef TOML_EXTERNAL_LINKAGE
#undef TOML_FLOAT_CHARCONV
#undef TOML_FLOAT128
#undef TOML_FLOAT16
#undef TOML_FP16
#undef TOML_GCC
#undef TOML_HAS_ATTR
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_INCLUDE
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END
#undef TOML_IMPL_NAMESPACE_START
#undef TOML_IMPLEMENTATION
#undef TOML_INCLUDE_WINDOWS_H
#undef TOML_INT_CHARCONV
#undef TOML_INT128
#undef TOML_INTELLISENSE
#undef TOML_INTERNAL_LINKAGE
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIFETIME_HOOKS
#undef TOML_LIKELY
#undef TOML_MAKE_FLAGS
#undef TOML_MAKE_FLAGS_
#undef TOML_MAKE_VERSION
#undef TOML_MAY_THROW
#undef TOML_MSVC
#undef TOML_NAMESPACE
#undef TOML_NAMESPACE_END
#undef TOML_NAMESPACE_START
#undef TOML_NEVER_INLINE
#undef TOML_NODISCARD
#undef TOML_NODISCARD_CTOR
#undef TOML_PARSER_TYPENAME
#undef TOML_POP_WARNINGS
#undef TOML_PUSH_WARNINGS
#undef TOML_REQUIRES
#undef TOML_SA_LIST_BEG
#undef TOML_SA_LIST_END
#undef TOML_SA_LIST_NEW
#undef TOML_SA_LIST_NXT
#undef TOML_SA_LIST_SEP
#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128
#undef TOML_UNLIKELY
#undef TOML_UNREACHABLE
#undef TOML_USING_ANON_NAMESPACE
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACES
#undef TOML_ABSTRACT_BASE
#undef TOML_ALWAYS_INLINE
#undef TOML_ANON_NAMESPACE
#undef TOML_ANON_NAMESPACE_END
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARM
#undef TOML_ASSERT
#undef TOML_ASSERT_ASSUME
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
#undef TOML_CLANG
#undef TOML_CLOSED_ENUM
#undef TOML_CLOSED_FLAGS_ENUM
#undef TOML_COMPILER_EXCEPTIONS
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_CPP_VERSION
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
#undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
#undef TOML_DISABLE_WARNINGS
#undef TOML_EMPTY_BASES
#undef TOML_ENABLE_IF
#undef TOML_ENABLE_WARNINGS
#undef TOML_EVAL_BOOL_0
#undef TOML_EVAL_BOOL_1
#undef TOML_EXTERN
#undef TOML_EXTERN_NOEXCEPT
#undef TOML_EXTERNAL_LINKAGE
#undef TOML_FLAGS_ENUM
#undef TOML_FLOAT_CHARCONV
#undef TOML_FLOAT128
#undef TOML_FLOAT16
#undef TOML_FP16
#undef TOML_GCC
#undef TOML_HAS_ATTR
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_INCLUDE
#undef TOML_HAS_SSE2
#undef TOML_HAS_SSE4_1
#undef TOML_HIDDEN_CONSTRAINT
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END
#undef TOML_IMPL_NAMESPACE_START
#undef TOML_IMPLEMENTATION
#undef TOML_INCLUDE_WINDOWS_H
#undef TOML_INT_CHARCONV
#undef TOML_INT128
#undef TOML_INTELLISENSE
#undef TOML_INTERNAL_LINKAGE
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIFETIME_HOOKS
#undef TOML_LIKELY
#undef TOML_LIKELY_CASE
#undef TOML_MAKE_FLAGS
#undef TOML_MAKE_FLAGS_
#undef TOML_MAKE_VERSION
#undef TOML_MSVC
#undef TOML_NAMESPACE
#undef TOML_NEVER_INLINE
#undef TOML_NODISCARD
#undef TOML_NODISCARD_CTOR
#undef TOML_OPEN_ENUM
#undef TOML_OPEN_FLAGS_ENUM
#undef TOML_PARSER_TYPENAME
#undef TOML_POP_WARNINGS
#undef TOML_PURE_GETTER
#undef TOML_PURE_INLINE_GETTER
#undef TOML_PUSH_WARNINGS
#undef TOML_REQUIRES
#undef TOML_SA_LIST_BEG
#undef TOML_SA_LIST_END
#undef TOML_SA_LIST_NEW
#undef TOML_SA_LIST_NXT
#undef TOML_SA_LIST_SEP
#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128
#undef TOML_UNLIKELY
#undef TOML_UNLIKELY_CASE
#undef TOML_UNREACHABLE
#undef TOML_UNUSED
#endif
#endif // INCLUDE_TOMLPLUSPLUS_H
#endif // TOMLPLUSPLUS_H

View File

@ -1,8 +1,8 @@
project(
'tomlplusplus',
'cpp',
version: '2.6.0',
meson_version: '>=0.53.0',
version: '3.0.0',
meson_version: '>=0.54.0',
license: 'MIT',
default_options: [ # https://mesonbuild.com/Builtin-options.html
# core options
@ -122,14 +122,14 @@ if is_gcc
'-Wvariadic-macros',
'-Wwrite-strings',
'-Wmissing-noreturn',
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=pure',
language: 'cpp'
)
endif
if is_release
add_project_arguments(
'-fmerge-constants',
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=pure',
language: 'cpp'
)
endif
@ -156,12 +156,6 @@ if is_clang
if get_option('time_trace')
add_project_arguments('-ftime-trace', language: 'cpp')
endif
if is_release
add_project_arguments(
'-fmerge-all-constants',
language: 'cpp'
)
endif
endif
# MSVC or icc-cl
@ -265,6 +259,16 @@ compiler_supports_cpp20 = compiler_supports_cpp20_args.length() > 0 and compiler
#include <version>
#include <string>
#include <iostream>
#include <cstdint>
#include <cstddef>
#include <cstring>
#include <cfloat>
#include <climits>
#include <cmath>
#include <limits>
#include <memory>
#include <iosfwd>
#include <type_traits>
int main()
{
@ -492,6 +496,11 @@ if build_examples
subdir('examples')
endif
build_tt = (get_option('build_tt_encoder') or get_option('build_tt_encoder')) and not is_subproject
if build_tt
subdir('toml-test')
endif
if not is_subproject
install_subdir('include'/'toml++',
strip_directory: true,
@ -508,9 +517,7 @@ tomlplusplus_dep = declare_dependency(
version: meson.project_version(),
)
if meson.version().version_compare('>=0.54.0')
meson.override_dependency('tomlplusplus', tomlplusplus_dep)
endif
meson.override_dependency('tomlplusplus', tomlplusplus_dep)
if not is_subproject
import('pkgconfig').generate(

View File

@ -3,3 +3,8 @@ option('build_examples', type: 'boolean', value: false, description: 'Build exa
option('generate_cmake_config', type: 'boolean', value: true, description: 'Generate a cmake package config file (default: true - no effect when included as a subproject)')
option('pedantic', type: 'boolean', value: false, description: 'Enable as many compiler warnings as possible (default: false)')
option('time_trace', type: 'boolean', value: false, description: 'Enable the -ftime-trace option (Clang only)')
option('asan_examples', type: 'boolean', value: false)
option('asan_tests', type: 'boolean', value: false)
option('build_tt_encoder', type: 'boolean', value: false, description: 'Enable to build the toml-test encoder.')
option('build_tt_decoder', type: 'boolean', value: false, description: 'Enable to build the toml-test decoder.')

115
tests/at_path.cpp Normal file
View File

@ -0,0 +1,115 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#include "tests.h"
TOML_DISABLE_SPAM_WARNINGS;
TEST_CASE("at_path")
{
// clang-format off
const auto tbl = table
{
{ ""sv, 0 }, // blank key
{ "a"sv, 1 },
{
"b"sv,
array
{
2,
array{ 3 },
table { { "c", 4 } }
},
},
{ "d", table{ {"e", 5, }, {""sv, -1 } } }
};
// clang-format on
/*
# equivalent to the following TOML:
"" = 0
a = 1
b = [
2,
[ 3 ],
{ "c" = 4 }
]
d = { "e" = 5, "" = -1 }
*/
SECTION("table")
{
// this section uses the free function version of at_path
CHECK(tbl[""]);
CHECK(tbl[""] == at_path(tbl, ""));
CHECK(tbl["a"]);
CHECK(tbl["a"] == at_path(tbl, "a"));
CHECK(tbl["a"] != at_path(tbl, ".a")); // equivalent to ""."a"
CHECK(!at_path(tbl, ".a"));
CHECK(tbl["b"]);
CHECK(tbl["b"] == at_path(tbl, "b"));
CHECK(tbl["b"][0]);
CHECK(tbl["b"][0] == at_path(tbl, "b[0]"));
CHECK(tbl["b"][0] == at_path(tbl, "b[0] "));
CHECK(tbl["b"][0] == at_path(tbl, "b[ 0\t]")); // whitespace is allowed inside array indexer
CHECK(tbl["b"][1]);
CHECK(tbl["b"][1] != tbl["b"][0]);
CHECK(tbl["b"][1] == at_path(tbl, "b[1]"));
CHECK(tbl["b"][1][0]);
CHECK(tbl["b"][1][0] == at_path(tbl, "b[1][0]"));
CHECK(tbl["b"][1][0] == at_path(tbl, "b[1] \t [0]")); // whitespace is allowed after array
// indexers
CHECK(tbl["b"][2]["c"]);
CHECK(tbl["b"][2]["c"] == at_path(tbl, "b[2].c"));
CHECK(tbl["b"][2]["c"] == at_path(tbl, "b[2] \t.c")); // whitespace is allowed after array indexers
CHECK(tbl["d"]);
CHECK(tbl["d"] == at_path(tbl, "d"));
CHECK(tbl["d"]["e"]);
CHECK(tbl["d"]["e"] == at_path(tbl, "d.e"));
CHECK(tbl["d"]["e"] != at_path(tbl, "d. e")); // equivalent to "d"." e"
CHECK(!at_path(tbl, "d. e"));
CHECK(tbl["d"][""]);
CHECK(tbl["d"][""] == at_path(tbl, "d."));
}
SECTION("array")
{
// this section uses the node_view member function version of at_path
auto arr = tbl["b"];
CHECK(tbl["b"][0]);
CHECK(tbl["b"][0] == arr.at_path("[0]"));
CHECK(tbl["b"][0] == arr.at_path("[0] "));
CHECK(tbl["b"][0] == arr.at_path("[ 0\t]")); // whitespace is allowed inside array indexer
CHECK(tbl["b"][1]);
CHECK(tbl["b"][1].node() != arr[0].node());
CHECK(tbl["b"][1] == arr.at_path("[1]"));
CHECK(tbl["b"][1][0]);
CHECK(tbl["b"][1][0] == arr.at_path("[1][0]"));
CHECK(tbl["b"][1][0] == arr.at_path("[1] \t [0]")); // whitespace is allowed after array
// indexers
CHECK(tbl["b"][2]["c"]);
CHECK(tbl["b"][2]["c"] == arr.at_path("[2].c"));
CHECK(tbl["b"][2]["c"] == arr.at_path("[2] \t.c")); // whitespace is allowed after array indexers
}
}

View File

@ -1,38 +0,0 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#pragma once
#include "settings.h"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#elif defined (__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wpadded"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#elif defined(_MSC_VER)
#pragma warning(push, 0)
#pragma warning(disable : 4365)
#pragma warning(disable : 4868)
#pragma warning(disable : 5105)
#endif
#if __has_include(<Catch2/single_include/catch2/catch.hpp>)
#include <Catch2/single_include/catch2/catch.hpp>
#else
#error Catch2 is missing! You probably need to fetch submodules ("git submodule update --init --depth 1 external/Catch2")
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@ -6,22 +6,19 @@
// this file was generated by generate_conformance_tests.py - do not modify it directly
#include "tests.h"
using namespace toml::impl;
TOML_DISABLE_WARNINGS; // unused variable spam
namespace
{
static constexpr auto array_missing_separator = R"(wrong = [ 1 2 3 ])"sv;
static constexpr auto array_no_close_2 = R"(x = [42 #)"sv;
static constexpr auto array_no_close_table_2 = R"(x = [{ key = 42 #)"sv;
static constexpr auto array_no_close_table = R"(x = [{ key = 42)"sv;
static constexpr auto array_no_close = R"(long_array = [ 1, 2, 3)"sv;
static constexpr auto array_tables_1 = R"(# INVALID TOML DOC
static constexpr auto array_missing_separator = R"(wrong = [ 1 2 3 ])"sv;
static constexpr auto array_no_close_2 = R"(x = [42 #)"sv;
static constexpr auto array_no_close_table_2 = R"(x = [{ key = 42 #)"sv;
static constexpr auto array_no_close_table = R"(x = [{ key = 42)"sv;
static constexpr auto array_no_close = R"(long_array = [ 1, 2, 3)"sv;
static constexpr auto array_tables_1 = R"(# INVALID TOML DOC
fruit = []
[[fruit]] # Not allowed)"sv;
static constexpr auto array_tables_2 = R"(# INVALID TOML DOC
static constexpr auto array_tables_2 = R"(# INVALID TOML DOC
[[fruit]]
name = "apple"
@ -31,7 +28,7 @@ fruit = []
# This table conflicts with the previous table
[fruit.variety]
name = "granny smith")"sv;
static constexpr auto array_text_after_array_entries = R"(array = [
static constexpr auto array_text_after_array_entries = R"(array = [
"Is there life after an array separator?", No
"Entry"
])"sv;
@ -39,66 +36,160 @@ fruit = []
"Is there life before an array separator?" No,
"Entry"
])"sv;
static constexpr auto array_text_in_array = R"(array = [
static constexpr auto array_text_in_array = R"(array = [
"Entry 1",
I don't belong,
"Entry 2",
])"sv;
static constexpr auto bool_mixed_case = R"(valid = False)"sv;
static constexpr auto bool_mixed_case = R"(valid = False)"sv;
static constexpr auto bool_wrong_case_false = R"(b = FALSE)"sv;
static constexpr auto bool_wrong_case_true = R"(a = TRUE)"sv;
static constexpr auto bool_wrong_case_true = R"(a = TRUE)"sv;
static constexpr auto datetime_impossible_date = R"(d = 2006-01-50T00:00:00Z)"sv;
static constexpr auto datetime_no_leads_with_milli = R"(with-milli = 1987-07-5T17:45:00.12Z)"sv;
static constexpr auto datetime_no_leads = R"(no-leads = 1987-7-05T17:45:00Z)"sv;
static constexpr auto datetime_no_t = R"(no-t = 1987-07-0517:45:00Z)"sv;
static constexpr auto datetime_trailing_t = R"(d = 2006-01-30T)"sv;
static constexpr auto control_bare_cr =
"# The following line contains a single carriage return control character\r\n"
"\r"sv;
static constexpr auto control_bare_formfeed = "bare-formfeed = \f"sv;
static constexpr auto control_bare_null = "bare-null = \"some value\" \x00"sv;
static constexpr auto control_bare_vertical_tab = "bare-vertical-tab = \v"sv;
static constexpr auto control_comment_cr = "comment-cr = \"Carriage return in comment\" # \ra=1"sv;
static constexpr auto control_comment_del = "comment-del = \"0x7f\" # \x7F"sv;
static constexpr auto control_comment_lf = "comment-lf = \"ctrl-P\" # \x10"sv;
static constexpr auto control_comment_null = "comment-null = \"null\" # \x00"sv;
static constexpr auto control_comment_us = "comment-us = \"ctrl-_\" # \x1F"sv;
static constexpr auto control_multi_del = "multi-del = \"\"\"null\x7F\"\"\""sv;
static constexpr auto control_multi_lf = "multi-lf = \"\"\"null\x10\"\"\""sv;
static constexpr auto control_multi_null = "multi-null = \"\"\"null\x00\"\"\""sv;
static constexpr auto control_multi_us = "multi-us = \"\"\"null\x1F\"\"\""sv;
static constexpr auto control_rawmulti_del = "rawmulti-del = '''null\x7F'''"sv;
static constexpr auto control_rawmulti_lf = "rawmulti-lf = '''null\x10'''"sv;
static constexpr auto control_rawmulti_null = "rawmulti-null = '''null\x00'''"sv;
static constexpr auto control_rawmulti_us = "rawmulti-us = '''null\x1F'''"sv;
static constexpr auto control_rawstring_del = "rawstring-del = 'null\x7F'"sv;
static constexpr auto control_rawstring_lf = "rawstring-lf = 'null\x10'"sv;
static constexpr auto control_rawstring_null = "rawstring-null = 'null\x00'"sv;
static constexpr auto control_rawstring_us = "rawstring-us = 'null\x1F'"sv;
static constexpr auto control_string_bs = "string-bs = \"backspace\x08\""sv;
static constexpr auto control_string_del = "string-del = \"null\x7F\""sv;
static constexpr auto control_string_lf = "string-lf = \"null\x10\""sv;
static constexpr auto control_string_null = "string-null = \"null\x00\""sv;
static constexpr auto control_string_us = "string-us = \"null\x1F\""sv;
static constexpr auto datetime_hour_over = R"(# time-hour = 2DIGIT ; 00-23
d = 2006-01-01T24:00:00-00:00)"sv;
static constexpr auto datetime_mday_over = R"(# date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
# ; month/year
d = 2006-01-32T00:00:00-00:00)"sv;
static constexpr auto datetime_mday_under = R"(# date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
# ; month/year
d = 2006-01-00T00:00:00-00:00)"sv;
static constexpr auto datetime_minute_over = R"(# time-minute = 2DIGIT ; 00-59
d = 2006-01-01T00:60:00-00:00)"sv;
static constexpr auto datetime_month_over = R"(# date-month = 2DIGIT ; 01-12
d = 2006-13-01T00:00:00-00:00)"sv;
static constexpr auto datetime_month_under = R"(# date-month = 2DIGIT ; 01-12
d = 2007-00-01T00:00:00-00:00)"sv;
static constexpr auto datetime_no_leads_with_milli = R"(# Day "5" instead of "05"; the leading zero is required.
with-milli = 1987-07-5T17:45:00.12Z)"sv;
static constexpr auto datetime_no_leads = R"(# Month "7" instead of "07"; the leading zero is required.
no-leads = 1987-7-05T17:45:00Z)"sv;
static constexpr auto datetime_no_t = R"(# No "t" or "T" between the date and time.
no-t = 1987-07-0517:45:00Z)"sv;
static constexpr auto datetime_second_over =
R"(# time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
# ; rules
d = 2006-01-01T00:00:61-00:00)"sv;
static constexpr auto datetime_time_no_leads_2 = R"(# Leading 0 is always required.
d = 01:32:0)"sv;
static constexpr auto datetime_time_no_leads = R"(# Leading 0 is always required.
d = 1:32:00)"sv;
static constexpr auto datetime_trailing_t = R"(# Date cannot end with trailing T
d = 2006-01-30T)"sv;
#if !TOML_LANG_UNRELEASED
static constexpr auto datetime_no_secs = R"(no-secs = 1987-07-05T17:45Z)"sv;
static constexpr auto datetime_no_secs = R"(# No seconds in time.
no-secs = 1987-07-05T17:45Z)"sv;
#endif // !TOML_LANG_UNRELEASED
static constexpr auto float_double_point_1 = R"(double-point-1 = 0..1)"sv;
static constexpr auto float_double_point_2 = R"(double-point-2 = 0.1.2)"sv;
static constexpr auto float_exp_double_e_1 = R"(exp-double-e-1 = 1ee2)"sv;
static constexpr auto float_exp_double_e_2 = R"(exp-double-e-2 = 1e2e3)"sv;
static constexpr auto float_exp_double_us = R"(exp-double-us = 1e__23)"sv;
static constexpr auto float_exp_leading_us = R"(exp-leading-us = 1e_23)"sv;
static constexpr auto float_exp_point_1 = R"(exp-point-1 = 1e2.3)"sv;
static constexpr auto float_exp_point_2 = R"(exp-point-2 = 1.e2)"sv;
static constexpr auto float_exp_trailing_us = R"(exp-trailing-us = 1e_23_)"sv;
static constexpr auto float_inf_incomplete_1 = R"(inf-incomplete-1 = in)"sv;
static constexpr auto float_inf_incomplete_2 = R"(inf-incomplete-2 = +in)"sv;
static constexpr auto float_inf_incomplete_3 = R"(inf-incomplete-3 = -in)"sv;
static constexpr auto float_inf_underscore = R"(inf_underscore = in_f)"sv;
static constexpr auto float_leading_point_neg = R"(leading-point-neg = -.12345)"sv;
static constexpr auto float_leading_point_plus = R"(leading-point-plus = +.12345)"sv;
static constexpr auto float_leading_point = R"(leading-point = .12345)"sv;
static constexpr auto float_leading_us = R"(leading-us = _1.2)"sv;
static constexpr auto float_leading_zero_neg = R"(leading-zero-neg = -03.14)"sv;
static constexpr auto float_leading_zero_plus = R"(leading-zero-plus = +03.14)"sv;
static constexpr auto float_leading_zero = R"(leading-zero = 03.14)"sv;
static constexpr auto float_nan_incomplete_1 = R"(nan-incomplete-1 = na)"sv;
static constexpr auto float_nan_incomplete_2 = R"(nan-incomplete-2 = +na)"sv;
static constexpr auto float_nan_incomplete_3 = R"(nan-incomplete-3 = -na)"sv;
static constexpr auto float_nan_underscore = R"(nan_underscore = na_n)"sv;
static constexpr auto float_trailing_point_min = R"(trailing-point-min = -1.)"sv;
static constexpr auto float_trailing_point_plus = R"(trailing-point-plus = +1.)"sv;
static constexpr auto float_trailing_point = R"(trailing-point = 1.)"sv;
static constexpr auto float_trailing_us = R"(trailing-us = 1.2_)"sv;
static constexpr auto float_us_after_point = R"(us-after-point = 1._2)"sv;
static constexpr auto float_us_before_point = R"(us-before-point = 1_.2)"sv;
static constexpr auto encoding_bad_utf8_at_end =
"\x23\x20\x54\x68\x65\x72\x65\x20\x69\x73\x20\x61\x20\x30\x78\x64\x61\x20\x61\x74\x20\x61\x66\x74\x65"
"\x72\x20\x74\x68\x65\x20\x71\x75\x6F\x74\x65\x73\x2C\x20\x61\x6E\x64\x20\x6E\x6F\x20\x45\x4F\x4C\x20"
"\x61\x74\x20\x74\x68\x65\x20\x65\x6E\x64\x20\x6F\x66\x20\x74\x68\x65\x20\x66\x69\x6C\x65\x2E\x0A\x23"
"\x0A\x23\x20\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x62\x69\x74\x20\x6F\x66\x20\x61\x6E\x20\x65\x64"
"\x67\x65\x20\x63\x61\x73\x65\x3A\x20\x54\x68\x69\x73\x20\x69\x6E\x64\x69\x63\x61\x74\x65\x73\x20\x74"
"\x68\x65\x72\x65\x20\x73\x68\x6F\x75\x6C\x64\x20\x62\x65\x20\x74\x77\x6F\x20\x62\x79\x74\x65\x73\x0A"
"\x23\x20\x28\x30\x62\x31\x31\x30\x31\x5F\x31\x30\x31\x30\x29\x20\x62\x75\x74\x20\x74\x68\x65\x72\x65"
"\x20\x69\x73\x20\x6E\x6F\x20\x62\x79\x74\x65\x20\x74\x6F\x20\x66\x6F\x6C\x6C\x6F\x77\x20\x62\x65\x63"
"\x61\x75\x73\x65\x20\x69\x74\x27\x73\x20\x74\x68\x65\x20\x65\x6E\x64\x20\x6F\x66\x20\x74\x68\x65\x20"
"\x66\x69\x6C\x65\x2E\x0A\x78\x20\x3D\x20\x22\x22\x22\x22\x22\x22\xDA"sv;
static constexpr auto encoding_bad_utf8_in_comment = "\x23\x20\xC3\x0A"sv;
static constexpr auto encoding_bad_utf8_in_string =
"\x23\x20\x54\x68\x65\x20\x66\x6F\x6C\x6C\x6F\x77\x69\x6E\x67\x20\x6C\x69\x6E\x65\x20\x63\x6F\x6E\x74"
"\x61\x69\x6E\x73\x20\x61\x6E\x20\x69\x6E\x76\x61\x6C\x69\x64\x20\x55\x54\x46\x2D\x38\x20\x73\x65\x71"
"\x75\x65\x6E\x63\x65\x2E\x0A\x62\x61\x64\x20\x3D\x20\x22\xC3\x22\x0A"sv;
static constexpr auto encoding_bom_not_at_start_1 =
"\x62\x6F\x6D\x2D\x6E\x6F\x74\x2D\x61\x74\x2D\x73\x74\x61\x72\x74\x20\xFF\xFD\x0A"sv;
static constexpr auto encoding_bom_not_at_start_2 =
"\x62\x6F\x6D\x2D\x6E\x6F\x74\x2D\x61\x74\x2D\x73\x74\x61\x72\x74\x3D\x20\xFF\xFD\x0A"sv;
static constexpr auto encoding_utf16_bom =
"\xFE\xFF\x00\x23\x00\x20\x00\x55\x00\x54\x00\x46\x00\x2D\x00\x31\x00\x36\x00\x20\x00\x77\x00\x69\x00"
"\x74\x00\x68\x00\x20\x00\x42\x00\x4F\x00\x4D\x00\x0A"sv;
static constexpr auto encoding_utf16 =
"\x00#\x00 \x00U\x00T\x00F\x00-\x001\x006\x00 \x00w\x00i\x00t\x00h\x00o\x00u\x00t\x00 \x00B\x00O\x00M\x00"sv;
static constexpr auto inline_table_double_comma = R"(t = {x=3,,y=4})"sv;
static constexpr auto inline_table_empty = R"(t = {,})"sv;
static constexpr auto inline_table_no_comma = R"(t = {x = 3 y = 4})"sv;
static constexpr auto float_double_point_1 = R"(double-point-1 = 0..1)"sv;
static constexpr auto float_double_point_2 = R"(double-point-2 = 0.1.2)"sv;
static constexpr auto float_exp_double_e_1 = R"(exp-double-e-1 = 1ee2)"sv;
static constexpr auto float_exp_double_e_2 = R"(exp-double-e-2 = 1e2e3)"sv;
static constexpr auto float_exp_double_us = R"(exp-double-us = 1e__23)"sv;
static constexpr auto float_exp_leading_us = R"(exp-leading-us = 1e_23)"sv;
static constexpr auto float_exp_point_1 = R"(exp-point-1 = 1e2.3)"sv;
static constexpr auto float_exp_point_2 = R"(exp-point-2 = 1.e2)"sv;
static constexpr auto float_exp_trailing_us = R"(exp-trailing-us = 1e_23_)"sv;
static constexpr auto float_inf_incomplete_1 = R"(inf-incomplete-1 = in)"sv;
static constexpr auto float_inf_incomplete_2 = R"(inf-incomplete-2 = +in)"sv;
static constexpr auto float_inf_incomplete_3 = R"(inf-incomplete-3 = -in)"sv;
static constexpr auto float_inf_underscore = R"(inf_underscore = in_f)"sv;
static constexpr auto float_leading_point_neg = R"(leading-point-neg = -.12345)"sv;
static constexpr auto float_leading_point_plus = R"(leading-point-plus = +.12345)"sv;
static constexpr auto float_leading_point = R"(leading-point = .12345)"sv;
static constexpr auto float_leading_us = R"(leading-us = _1.2)"sv;
static constexpr auto float_leading_zero_neg = R"(leading-zero-neg = -03.14)"sv;
static constexpr auto float_leading_zero_plus = R"(leading-zero-plus = +03.14)"sv;
static constexpr auto float_leading_zero = R"(leading-zero = 03.14)"sv;
static constexpr auto float_nan_incomplete_1 = R"(nan-incomplete-1 = na)"sv;
static constexpr auto float_nan_incomplete_2 = R"(nan-incomplete-2 = +na)"sv;
static constexpr auto float_nan_incomplete_3 = R"(nan-incomplete-3 = -na)"sv;
static constexpr auto float_nan_underscore = R"(nan_underscore = na_n)"sv;
static constexpr auto float_trailing_point_min = R"(trailing-point-min = -1.)"sv;
static constexpr auto float_trailing_point_plus = R"(trailing-point-plus = +1.)"sv;
static constexpr auto float_trailing_point = R"(trailing-point = 1.)"sv;
static constexpr auto float_trailing_us_exp = R"(# trailing underscore in integer part is not allowed
trailing-us-exp = 1_e2
# trailing underscore in float part is not allowed
trailing-us-exp2 = 1.2_e2)"sv;
static constexpr auto float_trailing_us = R"(trailing-us = 1.2_)"sv;
static constexpr auto float_us_after_point = R"(us-after-point = 1._2)"sv;
static constexpr auto float_us_before_point = R"(us-before-point = 1_.2)"sv;
static constexpr auto inline_table_add = R"(a={}
# Inline tables are immutable and can't be extended
[a.b])"sv;
static constexpr auto inline_table_double_comma = R"(t = {x=3,,y=4})"sv;
static constexpr auto inline_table_duplicate_key = R"(# Duplicate keys within an inline table are invalid
a={b=1, b=2})"sv;
static constexpr auto inline_table_empty = R"(t = {,})"sv;
static constexpr auto inline_table_no_comma = R"(t = {x = 3 y = 4})"sv;
static constexpr auto inline_table_overwrite = R"(a.b=0
# Since table "a" is already defined, it can't be replaced by an inline table.
a={})"sv;
#if !TOML_LANG_UNRELEASED
static constexpr auto inline_table_linebreak_1 = R"(# No newlines are allowed between the curly braces unless they are valid within
static constexpr auto inline_table_linebreak_1 =
R"(# No newlines are allowed between the curly braces unless they are valid within
# a value.
simple = { a = 1
})"sv;
@ -110,77 +201,83 @@ b=2})"sv;
first = "Tom",
last = "Preston-Werner"
})"sv;
static constexpr auto inline_table_trailing_comma = R"(# A terminating comma (also called trailing comma) is not permitted after the
static constexpr auto inline_table_trailing_comma =
R"(# A terminating comma (also called trailing comma) is not permitted after the
# last key/value pair in an inline table
abc = { abc = 123, })"sv;
#endif // !TOML_LANG_UNRELEASED
static constexpr auto integer_capital_bin = R"(capital-bin = 0B0)"sv;
static constexpr auto integer_capital_hex = R"(capital-hex = 0X1)"sv;
static constexpr auto integer_capital_oct = R"(capital-oct = 0O0)"sv;
static constexpr auto integer_double_sign_nex = R"(double-sign-nex = --99)"sv;
static constexpr auto integer_double_sign_plus = R"(double-sign-plus = ++99)"sv;
static constexpr auto integer_double_us = R"(double-us = 1__23)"sv;
static constexpr auto integer_invalid_bin = R"(invalid-bin = 0b0012)"sv;
static constexpr auto integer_invalid_hex = R"(invalid-hex = 0xaafz)"sv;
static constexpr auto integer_invalid_oct = R"(invalid-oct = 0o778)"sv;
static constexpr auto integer_leading_us_bin = R"(leading-us-bin = _0o1)"sv;
static constexpr auto integer_leading_us_hex = R"(leading-us-hex = _0o1)"sv;
static constexpr auto integer_leading_us_oct = R"(leading-us-oct = _0o1)"sv;
static constexpr auto integer_leading_us = R"(leading-us = _123)"sv;
static constexpr auto integer_leading_zero_1 = R"(leading-zero-1 = 01)"sv;
static constexpr auto integer_leading_zero_2 = R"(leading-zero-2 = 00)"sv;
static constexpr auto integer_capital_bin = R"(capital-bin = 0B0)"sv;
static constexpr auto integer_capital_hex = R"(capital-hex = 0X1)"sv;
static constexpr auto integer_capital_oct = R"(capital-oct = 0O0)"sv;
static constexpr auto integer_double_sign_nex = R"(double-sign-nex = --99)"sv;
static constexpr auto integer_double_sign_plus = R"(double-sign-plus = ++99)"sv;
static constexpr auto integer_double_us = R"(double-us = 1__23)"sv;
static constexpr auto integer_incomplete_bin = R"(incomplete-bin = 0b)"sv;
static constexpr auto integer_incomplete_hex = R"(incomplete-hex = 0x)"sv;
static constexpr auto integer_incomplete_oct = R"(incomplete-oct = 0o)"sv;
static constexpr auto integer_invalid_bin = R"(invalid-bin = 0b0012)"sv;
static constexpr auto integer_invalid_hex = R"(invalid-hex = 0xaafz)"sv;
static constexpr auto integer_invalid_oct = R"(invalid-oct = 0o778)"sv;
static constexpr auto integer_leading_us_bin = R"(leading-us-bin = _0o1)"sv;
static constexpr auto integer_leading_us_hex = R"(leading-us-hex = _0o1)"sv;
static constexpr auto integer_leading_us_oct = R"(leading-us-oct = _0o1)"sv;
static constexpr auto integer_leading_us = R"(leading-us = _123)"sv;
static constexpr auto integer_leading_zero_1 = R"(leading-zero-1 = 01)"sv;
static constexpr auto integer_leading_zero_2 = R"(leading-zero-2 = 00)"sv;
static constexpr auto integer_leading_zero_3 = R"(leading-zero-3 = 0_0)"sv;
static constexpr auto integer_leading_zero_sign_1 = R"(leading-zero-sign-1 = -01)"sv;
static constexpr auto integer_leading_zero_sign_2 = R"(leading-zero-sign-2 = +01)"sv;
static constexpr auto integer_negative_bin = R"(negative-bin = -0b11010110)"sv;
static constexpr auto integer_negative_hex = R"(negative-hex = -0xff)"sv;
static constexpr auto integer_negative_oct = R"(negative-oct = -0o99)"sv;
static constexpr auto integer_positive_bin = R"(positive-bin = +0b11010110)"sv;
static constexpr auto integer_positive_hex = R"(positive-hex = +0xff)"sv;
static constexpr auto integer_positive_oct = R"(positive-oct = +0o99)"sv;
static constexpr auto integer_text_after_integer = R"(answer = 42 the ultimate answer?)"sv;
static constexpr auto integer_trailing_us_bin = R"(trailing-us-bin = 0b1_)"sv;
static constexpr auto integer_trailing_us_hex = R"(trailing-us-hex = 0x1_)"sv;
static constexpr auto integer_trailing_us_oct = R"(trailing-us-oct = 0o1_)"sv;
static constexpr auto integer_trailing_us = R"(trailing-us = 123_)"sv;
static constexpr auto integer_us_after_bin = R"(us-after-bin = 0b_1)"sv;
static constexpr auto integer_us_after_hex = R"(us-after-hex = 0x_1)"sv;
static constexpr auto integer_us_after_oct = R"(us-after-oct = 0o_1)"sv;
static constexpr auto integer_leading_zero_sign_3 = R"(leading-zero-sign-3 = +0_1)"sv;
static constexpr auto integer_negative_bin = R"(negative-bin = -0b11010110)"sv;
static constexpr auto integer_negative_hex = R"(negative-hex = -0xff)"sv;
static constexpr auto integer_negative_oct = R"(negative-oct = -0o99)"sv;
static constexpr auto integer_positive_bin = R"(positive-bin = +0b11010110)"sv;
static constexpr auto integer_positive_hex = R"(positive-hex = +0xff)"sv;
static constexpr auto integer_positive_oct = R"(positive-oct = +0o99)"sv;
static constexpr auto integer_text_after_integer = R"(answer = 42 the ultimate answer?)"sv;
static constexpr auto integer_trailing_us_bin = R"(trailing-us-bin = 0b1_)"sv;
static constexpr auto integer_trailing_us_hex = R"(trailing-us-hex = 0x1_)"sv;
static constexpr auto integer_trailing_us_oct = R"(trailing-us-oct = 0o1_)"sv;
static constexpr auto integer_trailing_us = R"(trailing-us = 123_)"sv;
static constexpr auto integer_us_after_bin = R"(us-after-bin = 0b_1)"sv;
static constexpr auto integer_us_after_hex = R"(us-after-hex = 0x_1)"sv;
static constexpr auto integer_us_after_oct = R"(us-after-oct = 0o_1)"sv;
static constexpr auto key_after_array = R"([[agencies]] owner = "S Cjelli")"sv;
static constexpr auto key_after_table = R"([error] this = "should not be here")"sv;
static constexpr auto key_after_value = R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv;
static constexpr auto key_after_array = R"([[agencies]] owner = "S Cjelli")"sv;
static constexpr auto key_after_table = R"([error] this = "should not be here")"sv;
static constexpr auto key_after_value = R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv;
static constexpr auto key_bare_invalid_character = R"(bare!key = 123)"sv;
static constexpr auto key_dotted_redefine_table = R"(# Defined a.b as int
static constexpr auto key_dotted_redefine_table = R"(# Defined a.b as int
a.b = 1
# Tries to access it as table: error
a.b.c = 2)"sv;
static constexpr auto key_duplicate_keys = R"(dupe = false
static constexpr auto key_duplicate_keys = R"(dupe = false
dupe = true)"sv;
static constexpr auto key_duplicate = R"(# DO NOT DO THIS
static constexpr auto key_duplicate = R"(# DO NOT DO THIS
name = "Tom"
name = "Pradyun")"sv;
static constexpr auto key_empty = R"(= 1)"sv;
static constexpr auto key_escape = R"(\u00c0 = "latin capital letter A with grave")"sv;
static constexpr auto key_hash = R"(a# = 1)"sv;
static constexpr auto key_multiline = R"("""long
static constexpr auto key_empty = R"( = 1)"sv;
static constexpr auto key_escape = R"(\u00c0 = "latin capital letter A with grave")"sv;
static constexpr auto key_hash = R"(a# = 1)"sv;
static constexpr auto key_multiline = R"("""long
key""" = 1)"sv;
static constexpr auto key_newline = R"(barekey
static constexpr auto key_newline = R"(barekey
= 123)"sv;
static constexpr auto key_no_eol = R"(a = 1 b = 2)"sv;
static constexpr auto key_open_bracket = R"([abc = 1)"sv;
static constexpr auto key_partial_quoted = R"(partial"quoted" = 5)"sv;
static constexpr auto key_single_open_bracket = R"([)"sv;
static constexpr auto key_space = R"(a b = 1)"sv;
static constexpr auto key_start_bracket = R"([a]
static constexpr auto key_no_eol = R"(a = 1 b = 2)"sv;
static constexpr auto key_open_bracket = R"([abc = 1)"sv;
static constexpr auto key_partial_quoted = R"(partial"quoted" = 5)"sv;
static constexpr auto key_single_open_bracket = R"([)"sv;
static constexpr auto key_space = R"(a b = 1)"sv;
static constexpr auto key_start_bracket = R"([a]
[xyz = 5
[b])"sv;
static constexpr auto key_two_equals = R"(key= = 1)"sv;
static constexpr auto key_two_equals2 = R"(a==1)"sv;
static constexpr auto key_two_equals3 = R"(a=b=1)"sv;
static constexpr auto key_without_value_1 = R"(key)"sv;
static constexpr auto key_without_value_2 = R"(key =)"sv;
static constexpr auto key_two_equals = R"(key= = 1)"sv;
static constexpr auto key_two_equals2 = R"(a==1)"sv;
static constexpr auto key_two_equals3 = R"(a=b=1)"sv;
static constexpr auto key_without_value_1 = R"(key)"sv;
static constexpr auto key_without_value_2 = R"(key = )"sv;
#if !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK
@ -189,34 +286,42 @@ key""" = 1)"sv;
#endif // !TOML_LANG_UNRELEASED && UNICODE_LITERALS_OK
static constexpr auto string_bad_byte_escape = R"(naughty = "\xAg")"sv;
static constexpr auto string_bad_codepoint = R"(invalid-codepoint = "This string contains a non scalar unicode codepoint \uD801")"sv;
static constexpr auto string_bad_concat = R"(no_concat = "first" "second")"sv;
static constexpr auto string_bad_escape = R"(invalid-escape = "This string has a bad \a escape character.")"sv;
static constexpr auto string_bad_codepoint =
R"(invalid-codepoint = "This string contains a non scalar unicode codepoint \uD801")"sv;
static constexpr auto string_bad_concat = R"(no_concat = "first" "second")"sv;
static constexpr auto string_bad_escape_1 = R"(invalid-escape = "This string has a bad \a escape character.")"sv;
static constexpr auto string_bad_escape_2 = R"(invalid-escape = "This string has a bad \ escape character.")"sv;
static constexpr auto string_bad_multiline = R"(multi = "first line
second line")"sv;
static constexpr auto string_bad_slash_escape = R"(invalid-escape = "This string has a bad \/ escape character.")"sv;
static constexpr auto string_bad_uni_esc = R"(str = "val\ue")"sv;
static constexpr auto string_bad_slash_escape =
R"(invalid-escape = "This string has a bad \/ escape character.")"sv;
static constexpr auto string_bad_uni_esc = R"(str = "val\ue")"sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_1 = R"(a = """\UFFFFFFFF""")"sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_2 = R"(a = """\U00D80000""")"sv;
static constexpr auto string_basic_multiline_quotes = R"(str5 = """Here are three quotation marks: """.""")"sv;
static constexpr auto string_basic_multiline_unknown_escape = R"(a = """\@""")"sv;
static constexpr auto string_basic_multiline_unknown_escape = R"(a = """\@""")"sv;
static constexpr auto string_basic_out_of_range_unicode_escape_1 = R"(a = "\UFFFFFFFF")"sv;
static constexpr auto string_basic_out_of_range_unicode_escape_2 = R"(a = "\U00D80000")"sv;
static constexpr auto string_basic_unknown_escape = R"(a = "\@")"sv;
static constexpr auto string_literal_multiline_quotes_1 = R"(a = '''6 apostrophes: '''''')"sv;
static constexpr auto string_literal_multiline_quotes_2 = R"(a = '''15 apostrophes: '''''''''''''''''')"sv;
static constexpr auto string_missing_quotes = R"(name = value)"sv;
static constexpr auto string_multiline_escape_space = R"(a = """
static constexpr auto string_basic_unknown_escape = R"(a = "\@")"sv;
static constexpr auto string_literal_multiline_quotes_1 = R"(a = '''6 apostrophes: '''''')"sv;
static constexpr auto string_literal_multiline_quotes_2 = R"(a = '''15 apostrophes: '''''''''''''''''')"sv;
static constexpr auto string_missing_quotes = R"(name = value)"sv;
static constexpr auto string_multiline_bad_escape_1 = R"(k = """t\a""")"sv;
static constexpr auto string_multiline_bad_escape_2 = R"(# \<Space> is not a valid escape.
k = """t\ t""")"sv;
static constexpr auto string_multiline_bad_escape_3 = R"(# \<Space> is not a valid escape.
k = """t\ """)"sv;
static constexpr auto string_multiline_escape_space = R"(a = """
foo \ \n
bar""")"sv;
static constexpr auto string_multiline_no_close_2 = R"(x=""")"sv;
static constexpr auto string_multiline_no_close = R"(invalid = """
static constexpr auto string_multiline_no_close_2 = R"(x=""")"sv;
static constexpr auto string_multiline_no_close = R"(invalid = """
this will fail)"sv;
static constexpr auto string_multiline_quotes_1 = R"(a = """6 quotes: """""")"sv;
static constexpr auto string_multiline_quotes_2 = R"(a = """6 quotes: """""")"sv;
static constexpr auto string_no_close = R"(no-ending-quote = "One time, at band camp)"sv;
static constexpr auto string_multiline_quotes_1 = R"(a = """6 quotes: """""")"sv;
static constexpr auto string_multiline_quotes_2 = R"(a = """6 quotes: """""")"sv;
static constexpr auto string_no_close = R"(no-ending-quote = "One time, at band camp)"sv;
static constexpr auto string_text_after_string = R"(string = "Is there life after strings?" No.)"sv;
static constexpr auto string_wrong_close = R"(bad-ending-quote = "double and single')"sv;
static constexpr auto string_wrong_close = R"(bad-ending-quote = "double and single')"sv;
#if !TOML_LANG_UNRELEASED
@ -224,9 +329,36 @@ second line")"sv;
#endif // !TOML_LANG_UNRELEASED
static constexpr auto table_append_with_dotted_keys_1 = R"(# First a.b.c defines a table: a.b.c = {z=9}
#
# Then we define a.b.c.t = "str" to add a str to the above table, making it:
#
# a.b.c = {z=9, t="..."}
#
# While this makes sense, logically, it was decided this is not valid TOML as
# it's too confusing/convoluted.
#
# See: https://github.com/toml-lang/toml/issues/846
# https://github.com/toml-lang/toml/pull/859
[a.b.c]
z = 9
[a]
b.c.t = "Using dotted keys to add to [a.b.c] after explicitly defining it above is not allowed")"sv;
static constexpr auto table_append_with_dotted_keys_2 =
R"(# This is the same issue as in injection-1.toml, except that nests one level
# deeper. See that file for a more complete description.
[a.b.c.d]
z = 9
[a]
b.c.d.k.t = "Using dotted keys to add to [a.b.c.d] after explicitly defining it above is not allowed")"sv;
static constexpr auto table_array_empty = R"([[]]
name = "Born to Run")"sv;
static constexpr auto table_array_implicit = R"(# This test is a bit tricky. It should fail because the first use of
static constexpr auto table_array_implicit =
R"(# This test is a bit tricky. It should fail because the first use of
# `[[albums.songs]]` without first declaring `albums` implies that `albums`
# must be a table. The alternative would be quite weird. Namely, it wouldn't
# comply with the TOML spec: "Each double-bracketed sub-table will belong to
@ -240,59 +372,53 @@ name = "Glory Days"
[[albums]]
name = "Born in the USA")"sv;
static constexpr auto table_array_missing_bracket = R"([[albums]
static constexpr auto table_array_missing_bracket = R"([[albums]
name = "Born to Run")"sv;
static constexpr auto table_duplicate_key_table = R"([fruit]
static constexpr auto table_duplicate_key_dotted_table = R"([fruit]
apple.color = "red"
[fruit.apple] # INVALID)"sv;
static constexpr auto table_duplicate_key_dotted_table2 = R"([fruit]
apple.taste.sweet = true
[fruit.apple.taste] # INVALID)"sv;
static constexpr auto table_duplicate_key_table = R"([fruit]
type = "apple"
[fruit.type]
apple = "yes")"sv;
static constexpr auto table_duplicate_table_array = R"([tbl]
static constexpr auto table_duplicate_table_array = R"([tbl]
[[tbl]])"sv;
static constexpr auto table_duplicate_table_array2 = R"([[tbl]]
static constexpr auto table_duplicate_table_array2 = R"([[tbl]]
[tbl])"sv;
static constexpr auto table_duplicate = R"([a]
static constexpr auto table_duplicate = R"([a]
b = 1
[a]
c = 2)"sv;
static constexpr auto table_empty_implicit_table = R"([naughty..naughty])"sv;
static constexpr auto table_empty = R"([])"sv;
static constexpr auto table_equals_sign = R"([name=bad])"sv;
static constexpr auto table_injection_1 = R"([a.b.c]
z = 9
[a]
b.c.t = "Using dotted keys to add to [a.b.c] after explicitly defining it above is not allowed"
# see https://github.com/toml-lang/toml/issues/846)"sv;
static constexpr auto table_injection_2 = R"([a.b.c.d]
z = 9
[a]
b.c.d.k.t = "Using dotted keys to add to [a.b.c.d] after explicitly defining it above is not allowed"
# see https://github.com/toml-lang/toml/issues/846)"sv;
static constexpr auto table_llbrace = R"([ [table]])"sv;
static constexpr auto table_nested_brackets_close = R"([a]b]
static constexpr auto table_empty_implicit_table = R"([naughty..naughty])"sv;
static constexpr auto table_empty = R"([])"sv;
static constexpr auto table_equals_sign = R"([name=bad])"sv;
static constexpr auto table_llbrace = R"([ [table]])"sv;
static constexpr auto table_nested_brackets_close = R"([a]b]
zyx = 42)"sv;
static constexpr auto table_nested_brackets_open = R"([a[b]
static constexpr auto table_nested_brackets_open = R"([a[b]
zyx = 42)"sv;
static constexpr auto table_quoted_no_close = R"(["where will it end]
static constexpr auto table_quoted_no_close = R"(["where will it end]
name = value)"sv;
static constexpr auto table_redefine = R"(# Define b as int, and try to use it as a table: error
static constexpr auto table_redefine = R"(# Define b as int, and try to use it as a table: error
[a]
b = 1
[a.b]
c = 2)"sv;
static constexpr auto table_rrbrace = R"([[table] ])"sv;
static constexpr auto table_text_after_table = R"([error] this shouldn't be here)"sv;
static constexpr auto table_whitespace = R"([invalid key])"sv;
static constexpr auto table_with_pound = R"([key#group]
static constexpr auto table_rrbrace = R"([[table] ])"sv;
static constexpr auto table_text_after_table = R"([error] this shouldn't be here)"sv;
static constexpr auto table_whitespace = R"([invalid key])"sv;
static constexpr auto table_with_pound = R"([key#group]
answer = 42)"sv;
}
TOML_ENABLE_WARNINGS;
TEST_CASE("conformance - burntsushi/invalid")
{
parsing_should_fail(FILE_LINE_ARGS, array_missing_separator); // array-missing-separator
@ -321,7 +447,69 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, bool_wrong_case_true); // bool-wrong-case-true
parsing_should_fail(FILE_LINE_ARGS, datetime_impossible_date); // datetime-impossible-date
parsing_should_fail(FILE_LINE_ARGS, control_bare_cr); // control-bare-cr
parsing_should_fail(FILE_LINE_ARGS, control_bare_formfeed); // control-bare-formfeed
parsing_should_fail(FILE_LINE_ARGS, control_bare_null); // control-bare-null
parsing_should_fail(FILE_LINE_ARGS, control_bare_vertical_tab); // control-bare-vertical-tab
parsing_should_fail(FILE_LINE_ARGS, control_comment_cr); // control-comment-cr
parsing_should_fail(FILE_LINE_ARGS, control_comment_del); // control-comment-del
parsing_should_fail(FILE_LINE_ARGS, control_comment_lf); // control-comment-lf
parsing_should_fail(FILE_LINE_ARGS, control_comment_null); // control-comment-null
parsing_should_fail(FILE_LINE_ARGS, control_comment_us); // control-comment-us
parsing_should_fail(FILE_LINE_ARGS, control_multi_del); // control-multi-del
parsing_should_fail(FILE_LINE_ARGS, control_multi_lf); // control-multi-lf
parsing_should_fail(FILE_LINE_ARGS, control_multi_null); // control-multi-null
parsing_should_fail(FILE_LINE_ARGS, control_multi_us); // control-multi-us
parsing_should_fail(FILE_LINE_ARGS, control_rawmulti_del); // control-rawmulti-del
parsing_should_fail(FILE_LINE_ARGS, control_rawmulti_lf); // control-rawmulti-lf
parsing_should_fail(FILE_LINE_ARGS, control_rawmulti_null); // control-rawmulti-null
parsing_should_fail(FILE_LINE_ARGS, control_rawmulti_us); // control-rawmulti-us
parsing_should_fail(FILE_LINE_ARGS, control_rawstring_del); // control-rawstring-del
parsing_should_fail(FILE_LINE_ARGS, control_rawstring_lf); // control-rawstring-lf
parsing_should_fail(FILE_LINE_ARGS, control_rawstring_null); // control-rawstring-null
parsing_should_fail(FILE_LINE_ARGS, control_rawstring_us); // control-rawstring-us
parsing_should_fail(FILE_LINE_ARGS, control_string_bs); // control-string-bs
parsing_should_fail(FILE_LINE_ARGS, control_string_del); // control-string-del
parsing_should_fail(FILE_LINE_ARGS, control_string_lf); // control-string-lf
parsing_should_fail(FILE_LINE_ARGS, control_string_null); // control-string-null
parsing_should_fail(FILE_LINE_ARGS, control_string_us); // control-string-us
parsing_should_fail(FILE_LINE_ARGS, datetime_hour_over); // datetime-hour-over
parsing_should_fail(FILE_LINE_ARGS, datetime_mday_over); // datetime-mday-over
parsing_should_fail(FILE_LINE_ARGS, datetime_mday_under); // datetime-mday-under
parsing_should_fail(FILE_LINE_ARGS, datetime_minute_over); // datetime-minute-over
parsing_should_fail(FILE_LINE_ARGS, datetime_month_over); // datetime-month-over
parsing_should_fail(FILE_LINE_ARGS, datetime_month_under); // datetime-month-under
parsing_should_fail(FILE_LINE_ARGS, datetime_no_leads_with_milli); // datetime-no-leads-with-milli
@ -329,6 +517,12 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, datetime_no_t); // datetime-no-t
parsing_should_fail(FILE_LINE_ARGS, datetime_second_over); // datetime-second-over
parsing_should_fail(FILE_LINE_ARGS, datetime_time_no_leads_2); // datetime-time-no-leads-2
parsing_should_fail(FILE_LINE_ARGS, datetime_time_no_leads); // datetime-time-no-leads
parsing_should_fail(FILE_LINE_ARGS, datetime_trailing_t); // datetime-trailing-t
#if !TOML_LANG_UNRELEASED
@ -337,6 +531,20 @@ TEST_CASE("conformance - burntsushi/invalid")
#endif // !TOML_LANG_UNRELEASED
parsing_should_fail(FILE_LINE_ARGS, encoding_bad_utf8_at_end); // encoding-bad-utf8-at-end
parsing_should_fail(FILE_LINE_ARGS, encoding_bad_utf8_in_comment); // encoding-bad-utf8-in-comment
parsing_should_fail(FILE_LINE_ARGS, encoding_bad_utf8_in_string); // encoding-bad-utf8-in-string
parsing_should_fail(FILE_LINE_ARGS, encoding_bom_not_at_start_1); // encoding-bom-not-at-start-1
parsing_should_fail(FILE_LINE_ARGS, encoding_bom_not_at_start_2); // encoding-bom-not-at-start-2
parsing_should_fail(FILE_LINE_ARGS, encoding_utf16_bom); // encoding-utf16-bom
parsing_should_fail(FILE_LINE_ARGS, encoding_utf16); // encoding-utf16
parsing_should_fail(FILE_LINE_ARGS, float_double_point_1); // float-double-point-1
parsing_should_fail(FILE_LINE_ARGS, float_double_point_2); // float-double-point-2
@ -391,18 +599,26 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, float_trailing_point); // float-trailing-point
parsing_should_fail(FILE_LINE_ARGS, float_trailing_us_exp); // float-trailing-us-exp
parsing_should_fail(FILE_LINE_ARGS, float_trailing_us); // float-trailing-us
parsing_should_fail(FILE_LINE_ARGS, float_us_after_point); // float-us-after-point
parsing_should_fail(FILE_LINE_ARGS, float_us_before_point); // float-us-before-point
parsing_should_fail(FILE_LINE_ARGS, inline_table_add); // inline-table-add
parsing_should_fail(FILE_LINE_ARGS, inline_table_double_comma); // inline-table-double-comma
parsing_should_fail(FILE_LINE_ARGS, inline_table_duplicate_key); // inline-table-duplicate-key
parsing_should_fail(FILE_LINE_ARGS, inline_table_empty); // inline-table-empty
parsing_should_fail(FILE_LINE_ARGS, inline_table_no_comma); // inline-table-no-comma
parsing_should_fail(FILE_LINE_ARGS, inline_table_overwrite); // inline-table-overwrite
#if !TOML_LANG_UNRELEASED
parsing_should_fail(FILE_LINE_ARGS, inline_table_linebreak_1); // inline-table-linebreak-1
@ -429,6 +645,12 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, integer_double_us); // integer-double-us
parsing_should_fail(FILE_LINE_ARGS, integer_incomplete_bin); // integer-incomplete-bin
parsing_should_fail(FILE_LINE_ARGS, integer_incomplete_hex); // integer-incomplete-hex
parsing_should_fail(FILE_LINE_ARGS, integer_incomplete_oct); // integer-incomplete-oct
parsing_should_fail(FILE_LINE_ARGS, integer_invalid_bin); // integer-invalid-bin
parsing_should_fail(FILE_LINE_ARGS, integer_invalid_hex); // integer-invalid-hex
@ -447,10 +669,14 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_2); // integer-leading-zero-2
parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_3); // integer-leading-zero-3
parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_sign_1); // integer-leading-zero-sign-1
parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_sign_2); // integer-leading-zero-sign-2
parsing_should_fail(FILE_LINE_ARGS, integer_leading_zero_sign_3); // integer-leading-zero-sign-3
parsing_should_fail(FILE_LINE_ARGS, integer_negative_bin); // integer-negative-bin
parsing_should_fail(FILE_LINE_ARGS, integer_negative_hex); // integer-negative-hex
@ -537,7 +763,9 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, string_bad_concat); // string-bad-concat
parsing_should_fail(FILE_LINE_ARGS, string_bad_escape); // string-bad-escape
parsing_should_fail(FILE_LINE_ARGS, string_bad_escape_1); // string-bad-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_bad_escape_2); // string-bad-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_bad_multiline); // string-bad-multiline
@ -545,17 +773,23 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, string_bad_uni_esc); // string-bad-uni-esc
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_1); // string-basic-multiline-out-of-range-unicode-escape-1
parsing_should_fail(
FILE_LINE_ARGS,
string_basic_multiline_out_of_range_unicode_escape_1); // string-basic-multiline-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_2); // string-basic-multiline-out-of-range-unicode-escape-2
parsing_should_fail(
FILE_LINE_ARGS,
string_basic_multiline_out_of_range_unicode_escape_2); // string-basic-multiline-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_quotes); // string-basic-multiline-quotes
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_unknown_escape); // string-basic-multiline-unknown-escape
parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_1); // string-basic-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS,
string_basic_out_of_range_unicode_escape_1); // string-basic-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_2); // string-basic-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS,
string_basic_out_of_range_unicode_escape_2); // string-basic-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_unknown_escape); // string-basic-unknown-escape
@ -565,6 +799,12 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, string_missing_quotes); // string-missing-quotes
parsing_should_fail(FILE_LINE_ARGS, string_multiline_bad_escape_1); // string-multiline-bad-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_multiline_bad_escape_2); // string-multiline-bad-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_multiline_bad_escape_3); // string-multiline-bad-escape-3
parsing_should_fail(FILE_LINE_ARGS, string_multiline_escape_space); // string-multiline-escape-space
parsing_should_fail(FILE_LINE_ARGS, string_multiline_no_close_2); // string-multiline-no-close-2
@ -587,12 +827,20 @@ TEST_CASE("conformance - burntsushi/invalid")
#endif // !TOML_LANG_UNRELEASED
parsing_should_fail(FILE_LINE_ARGS, table_append_with_dotted_keys_1); // table-append-with-dotted-keys-1
parsing_should_fail(FILE_LINE_ARGS, table_append_with_dotted_keys_2); // table-append-with-dotted-keys-2
parsing_should_fail(FILE_LINE_ARGS, table_array_empty); // table-array-empty
parsing_should_fail(FILE_LINE_ARGS, table_array_implicit); // table-array-implicit
parsing_should_fail(FILE_LINE_ARGS, table_array_missing_bracket); // table-array-missing-bracket
parsing_should_fail(FILE_LINE_ARGS, table_duplicate_key_dotted_table); // table-duplicate-key-dotted-table
parsing_should_fail(FILE_LINE_ARGS, table_duplicate_key_dotted_table2); // table-duplicate-key-dotted-table2
parsing_should_fail(FILE_LINE_ARGS, table_duplicate_key_table); // table-duplicate-key-table
parsing_should_fail(FILE_LINE_ARGS, table_duplicate_table_array); // table-duplicate-table-array
@ -607,10 +855,6 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, table_equals_sign); // table-equals-sign
parsing_should_fail(FILE_LINE_ARGS, table_injection_1); // table-injection-1
parsing_should_fail(FILE_LINE_ARGS, table_injection_2); // table-injection-2
parsing_should_fail(FILE_LINE_ARGS, table_llbrace); // table-llbrace
parsing_should_fail(FILE_LINE_ARGS, table_nested_brackets_close); // table-nested-brackets-close
@ -629,4 +873,3 @@ TEST_CASE("conformance - burntsushi/invalid")
parsing_should_fail(FILE_LINE_ARGS, table_with_pound); // table-with-pound
}

File diff suppressed because it is too large Load Diff

View File

@ -6,146 +6,165 @@
// this file was generated by generate_conformance_tests.py - do not modify it directly
#include "tests.h"
using namespace toml::impl;
TOML_DISABLE_WARNINGS; // unused variable spam
namespace
{
static constexpr auto array_of_tables_1 = R"(# INVALID TOML DOC
fruit = []
static constexpr auto array_of_tables_1 = "# INVALID TOML DOC\r\n"
"fruit = []\r\n"
"\r\n"
"[[fruit]] # Not allowed"sv;
static constexpr auto array_of_tables_2 = "# INVALID TOML DOC\r\n"
"[[fruit]]\r\n"
" name = \"apple\"\r\n"
"\r\n"
" [[fruit.variety]]\r\n"
" name = \"red delicious\"\r\n"
"\r\n"
" # This table conflicts with the previous table\r\n"
" [fruit.variety]\r\n"
" name = \"granny smith\""sv;
[[fruit]] # Not allowed)"sv;
static constexpr auto array_of_tables_2 = R"(# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
# This table conflicts with the previous table
[fruit.variety]
name = "granny smith")"sv;
static constexpr auto bare_key_1 = R"(bare!key = 123)"sv;
static constexpr auto bare_key_2 = R"(barekey
= 123)"sv;
static constexpr auto bare_key_1 = "bare!key = 123"sv;
static constexpr auto bare_key_2 = "barekey\r\n"
" = 123"sv;
static constexpr auto bare_key_3 = R"(barekey =)"sv;
static constexpr auto inline_table_imutable_1 = R"([product]
type = { name = "Nail" }
type.edible = false # INVALID)"sv;
static constexpr auto inline_table_imutable_2 = R"([product]
type.name = "Nail"
type = { edible = false } # INVALID)"sv;
static constexpr auto comment_control_1 = "a = \"null\" # \x00"sv;
static constexpr auto comment_control_2 = "a = \"ctrl-P\" # \x10"sv;
static constexpr auto comment_control_3 = "a = \"ctrl-_\" # \x1F"sv;
static constexpr auto comment_control_4 = "a = \"0x7f\" # \x7F"sv;
static constexpr auto inline_table_imutable_1 = "[product]\r\n"
"type = { name = \"Nail\" }\r\n"
"type.edible = false # INVALID"sv;
static constexpr auto inline_table_imutable_2 = "[product]\r\n"
"type.name = \"Nail\"\r\n"
"type = { edible = false } # INVALID"sv;
#if !TOML_LANG_UNRELEASED
static constexpr auto inline_table_trailing_comma = R"(abc = { abc = 123, })"sv;
static constexpr auto inline_table_trailing_comma = "abc = { abc = 123, }"sv;
#endif // !TOML_LANG_UNRELEASED
static constexpr auto int_0_padded = R"(int = 0123)"sv;
static constexpr auto int_signed_bin = R"(bin = +0b10)"sv;
static constexpr auto int_signed_hex = R"(hex = +0xab)"sv;
static constexpr auto int_signed_oct = R"(oct = +0o23)"sv;
static constexpr auto int_0_padded = "int = 0123"sv;
static constexpr auto int_signed_bin = "bin = +0b10"sv;
static constexpr auto int_signed_hex = "hex = +0xab"sv;
static constexpr auto int_signed_oct = "oct = +0o23"sv;
static constexpr auto key_value_pair_1 = R"(key = # INVALID)"sv;
static constexpr auto key_value_pair_2 = R"(first = "Tom" last = "Preston-Werner" # INVALID)"sv;
static constexpr auto key_value_pair_1 = "key = # INVALID"sv;
static constexpr auto key_value_pair_2 = "first = \"Tom\" last = \"Preston-Werner\" # INVALID"sv;
static constexpr auto multiple_dot_key = R"(# THE FOLLOWING IS INVALID
static constexpr auto multiple_dot_key = "# THE FOLLOWING IS INVALID\r\n"
"\r\n"
"# This defines the value of fruit.apple to be an integer.\r\n"
"fruit.apple = 1\r\n"
"\r\n"
"# But then this treats fruit.apple like it's a table.\r\n"
"# You can't turn an integer into a table.\r\n"
"fruit.apple.smooth = true"sv;
static constexpr auto multiple_key = "# DO NOT DO THIS\r\n"
"name = \"Tom\"\r\n"
"name = \"Pradyun\""sv;
# This defines the value of fruit.apple to be an integer.
fruit.apple = 1
static constexpr auto no_key_name = "= \"no key name\" # INVALID"sv;
# But then this treats fruit.apple like it's a table.
# You can't turn an integer into a table.
fruit.apple.smooth = true)"sv;
static constexpr auto multiple_key = R"(# DO NOT DO THIS
name = "Tom"
name = "Pradyun")"sv;
static constexpr auto string_basic_control_1 = "a = \"null\x00\""sv;
static constexpr auto string_basic_control_2 = "a = \"ctrl-P\x10\""sv;
static constexpr auto string_basic_control_3 = "a = \"ctrl-_\x1F\""sv;
static constexpr auto string_basic_control_4 = "a = \"0x7f\x7F\""sv;
static constexpr auto string_basic_multiline_control_1 = "a = \"\"\"null\x00\"\"\""sv;
static constexpr auto string_basic_multiline_control_2 = "a = \"\"\"null\x10\"\"\""sv;
static constexpr auto string_basic_multiline_control_3 = "a = \"\"\"null\x1F\"\"\""sv;
static constexpr auto string_basic_multiline_control_4 = "a = \"\"\"null\x7F\"\"\""sv;
static constexpr auto string_basic_multiline_invalid_backslash = "a = \"\"\"\r\n"
" foo \\ \\n\r\n"
" bar\"\"\""sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_1 = "a = \"\"\"\\UFFFFFFFF\"\"\""sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_2 = "a = \"\"\"\\U00D80000\"\"\""sv;
static constexpr auto string_basic_multiline_quotes =
"str5 = \"\"\"Here are three quotation marks: \"\"\".\"\"\""sv;
static constexpr auto string_basic_multiline_unknown_escape = "a = \"\"\"\\@\"\"\""sv;
static constexpr auto string_basic_out_of_range_unicode_escape_1 = "a = \"\\UFFFFFFFF\""sv;
static constexpr auto string_basic_out_of_range_unicode_escape_2 = "a = \"\\U00D80000\""sv;
static constexpr auto string_basic_unknown_escape = "a = \"\\@\""sv;
static constexpr auto string_literal_control_1 = "a = 'null\x00'"sv;
static constexpr auto string_literal_control_2 = "a = 'null\x10'"sv;
static constexpr auto string_literal_control_3 = "a = 'null\x1F'"sv;
static constexpr auto string_literal_control_4 = "a = 'null\x7F'"sv;
static constexpr auto string_literal_multiline_control_1 = "a = '''null\x00'''"sv;
static constexpr auto string_literal_multiline_control_2 = "a = '''null\x10'''"sv;
static constexpr auto string_literal_multiline_control_3 = "a = '''null\x1F'''"sv;
static constexpr auto string_literal_multiline_control_4 = "a = '''null\x7F'''"sv;
static constexpr auto string_literal_multiline_quotes =
"apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID"sv;
static constexpr auto no_key_name = R"(= "no key name" # INVALID)"sv;
static constexpr auto string_basic_multiline_invalid_backslash = R"(a = """
foo \ \n
bar""")"sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_1 = R"(a = """\UFFFFFFFF""")"sv;
static constexpr auto string_basic_multiline_out_of_range_unicode_escape_2 = R"(a = """\U00D80000""")"sv;
static constexpr auto string_basic_multiline_quotes = R"(str5 = """Here are three quotation marks: """.""")"sv;
static constexpr auto string_basic_multiline_unknown_escape = R"(a = """\@""")"sv;
static constexpr auto string_basic_out_of_range_unicode_escape_1 = R"(a = "\UFFFFFFFF")"sv;
static constexpr auto string_basic_out_of_range_unicode_escape_2 = R"(a = "\U00D80000")"sv;
static constexpr auto string_basic_unknown_escape = R"(a = "\@")"sv;
static constexpr auto string_literal_multiline_quotes = R"(apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID)"sv;
static constexpr auto table_1 = R"(# DO NOT DO THIS
[fruit]
apple = "red"
[fruit]
orange = "orange")"sv;
static constexpr auto table_2 = R"(# DO NOT DO THIS EITHER
[fruit]
apple = "red"
[fruit.apple]
texture = "smooth")"sv;
static constexpr auto table_3 = R"([fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple] # INVALID)"sv;
static constexpr auto table_4 = R"([fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple.taste] # INVALID)"sv;
static constexpr auto table_invalid_1 = R"([fruit.physical] # subtable, but to which parent element should it belong?
color = "red"
shape = "round"
[[fruit]] # parser must throw an error upon discovering that "fruit" is
# an array rather than a table
name = "apple")"sv;
static constexpr auto table_invalid_2 = R"(# INVALID TOML DOC
fruit = []
[[fruit]] # Not allowed)"sv;
static constexpr auto table_invalid_3 = R"(# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
# INVALID: This table conflicts with the previous array of tables
[fruit.variety]
name = "granny smith"
[fruit.physical]
color = "red"
shape = "round")"sv;
static constexpr auto table_invalid_4 = R"(# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
[fruit.physical]
color = "red"
shape = "round"
# INVALID: This array of tables conflicts with the previous table
[[fruit.physical]]
color = "green")"sv;
static constexpr auto table_1 = "# DO NOT DO THIS\r\n"
"\r\n"
"[fruit]\r\n"
"apple = \"red\"\r\n"
"\r\n"
"[fruit]\r\n"
"orange = \"orange\""sv;
static constexpr auto table_2 = "# DO NOT DO THIS EITHER\r\n"
"\r\n"
"[fruit]\r\n"
"apple = \"red\"\r\n"
"\r\n"
"[fruit.apple]\r\n"
"texture = \"smooth\""sv;
static constexpr auto table_3 = "[fruit]\r\n"
"apple.color = \"red\"\r\n"
"apple.taste.sweet = true\r\n"
"\r\n"
"[fruit.apple] # INVALID"sv;
static constexpr auto table_4 = "[fruit]\r\n"
"apple.color = \"red\"\r\n"
"apple.taste.sweet = true\r\n"
"\r\n"
"[fruit.apple.taste] # INVALID"sv;
static constexpr auto table_invalid_1 =
"[fruit.physical] # subtable, but to which parent element should it belong?\r\n"
" color = \"red\"\r\n"
" shape = \"round\"\r\n"
"\r\n"
"[[fruit]] # parser must throw an error upon discovering that \"fruit\" is\r\n"
" # an array rather than a table\r\n"
" name = \"apple\""sv;
static constexpr auto table_invalid_2 = "# INVALID TOML DOC\r\n"
"fruit = []\r\n"
"\r\n"
"[[fruit]] # Not allowed"sv;
static constexpr auto table_invalid_3 = "# INVALID TOML DOC\r\n"
"[[fruit]]\r\n"
" name = \"apple\"\r\n"
"\r\n"
" [[fruit.variety]]\r\n"
" name = \"red delicious\"\r\n"
"\r\n"
" # INVALID: This table conflicts with the previous array of tables\r\n"
" [fruit.variety]\r\n"
" name = \"granny smith\"\r\n"
"\r\n"
" [fruit.physical]\r\n"
" color = \"red\"\r\n"
" shape = \"round\""sv;
static constexpr auto table_invalid_4 = "# INVALID TOML DOC\r\n"
"[[fruit]]\r\n"
" name = \"apple\"\r\n"
"\r\n"
" [[fruit.variety]]\r\n"
" name = \"red delicious\"\r\n"
"\r\n"
" [fruit.physical]\r\n"
" color = \"red\"\r\n"
" shape = \"round\"\r\n"
"\r\n"
" # INVALID: This array of tables conflicts with the previous table\r\n"
" [[fruit.physical]]\r\n"
" color = \"green\""sv;
}
TOML_ENABLE_WARNINGS;
TEST_CASE("conformance - iarna/invalid")
{
parsing_should_fail(FILE_LINE_ARGS, array_of_tables_1); // array-of-tables-1
@ -158,6 +177,14 @@ TEST_CASE("conformance - iarna/invalid")
parsing_should_fail(FILE_LINE_ARGS, bare_key_3); // bare-key-3
parsing_should_fail(FILE_LINE_ARGS, comment_control_1); // comment-control-1
parsing_should_fail(FILE_LINE_ARGS, comment_control_2); // comment-control-2
parsing_should_fail(FILE_LINE_ARGS, comment_control_3); // comment-control-3
parsing_should_fail(FILE_LINE_ARGS, comment_control_4); // comment-control-4
parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_1); // inline-table-imutable-1
parsing_should_fail(FILE_LINE_ARGS, inline_table_imutable_2); // inline-table-imutable-2
@ -186,22 +213,61 @@ TEST_CASE("conformance - iarna/invalid")
parsing_should_fail(FILE_LINE_ARGS, no_key_name); // no-key-name
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_invalid_backslash); // string-basic-multiline-invalid-backslash
parsing_should_fail(FILE_LINE_ARGS, string_basic_control_1); // string-basic-control-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_1); // string-basic-multiline-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_control_2); // string-basic-control-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_out_of_range_unicode_escape_2); // string-basic-multiline-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_control_3); // string-basic-control-3
parsing_should_fail(FILE_LINE_ARGS, string_basic_control_4); // string-basic-control-4
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_control_1); // string-basic-multiline-control-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_control_2); // string-basic-multiline-control-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_control_3); // string-basic-multiline-control-3
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_control_4); // string-basic-multiline-control-4
parsing_should_fail(FILE_LINE_ARGS,
string_basic_multiline_invalid_backslash); // string-basic-multiline-invalid-backslash
parsing_should_fail(
FILE_LINE_ARGS,
string_basic_multiline_out_of_range_unicode_escape_1); // string-basic-multiline-out-of-range-unicode-escape-1
parsing_should_fail(
FILE_LINE_ARGS,
string_basic_multiline_out_of_range_unicode_escape_2); // string-basic-multiline-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_quotes); // string-basic-multiline-quotes
parsing_should_fail(FILE_LINE_ARGS, string_basic_multiline_unknown_escape); // string-basic-multiline-unknown-escape
parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_1); // string-basic-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS,
string_basic_out_of_range_unicode_escape_1); // string-basic-out-of-range-unicode-escape-1
parsing_should_fail(FILE_LINE_ARGS, string_basic_out_of_range_unicode_escape_2); // string-basic-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS,
string_basic_out_of_range_unicode_escape_2); // string-basic-out-of-range-unicode-escape-2
parsing_should_fail(FILE_LINE_ARGS, string_basic_unknown_escape); // string-basic-unknown-escape
parsing_should_fail(FILE_LINE_ARGS, string_literal_control_1); // string-literal-control-1
parsing_should_fail(FILE_LINE_ARGS, string_literal_control_2); // string-literal-control-2
parsing_should_fail(FILE_LINE_ARGS, string_literal_control_3); // string-literal-control-3
parsing_should_fail(FILE_LINE_ARGS, string_literal_control_4); // string-literal-control-4
parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_control_1); // string-literal-multiline-control-1
parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_control_2); // string-literal-multiline-control-2
parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_control_3); // string-literal-multiline-control-3
parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_control_4); // string-literal-multiline-control-4
parsing_should_fail(FILE_LINE_ARGS, string_literal_multiline_quotes); // string-literal-multiline-quotes
parsing_should_fail(FILE_LINE_ARGS, table_1); // table-1
@ -220,4 +286,3 @@ TEST_CASE("conformance - iarna/invalid")
parsing_should_fail(FILE_LINE_ARGS, table_invalid_4); // table-invalid-4
}

File diff suppressed because it is too large Load Diff

332
tests/formatters.cpp Normal file
View File

@ -0,0 +1,332 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#include "tests.h"
namespace
{
template <typename Formatter, typename T>
static auto format_to_string(const T& obj,
format_flags flags = Formatter::default_flags,
format_flags exclude_flags = format_flags::none)
{
std::stringstream ss;
ss << "*****\n" << Formatter{ obj, flags & ~(exclude_flags) } << "\n*****";
return ss.str();
}
struct char32_printer
{
char32_t value;
friend std::ostream& operator<<(std::ostream& os, const char32_printer& p)
{
if (p.value <= U'\x1F')
return os << '\'' << impl::control_char_escapes[static_cast<size_t>(p.value)] << '\'';
else if (p.value == U'\x7F')
return os << "'\\u007F'"sv;
else if (p.value < 127u)
return os << '\'' << static_cast<char>(static_cast<uint8_t>(p.value)) << '\'';
else
return os << static_cast<uint_least32_t>(p.value);
}
};
struct string_difference
{
source_position position;
size_t index;
char32_t a, b;
friend std::ostream& operator<<(std::ostream& os, const string_difference& diff)
{
if (diff.a && diff.b && diff.a != diff.b)
os << char32_printer{ diff.a } << " vs "sv << char32_printer{ diff.b } << " at "sv;
return os << diff.position << ", index "sv << diff.index;
}
};
static optional<string_difference> find_first_difference(std::string_view str_a, std::string_view str_b) noexcept
{
string_difference diff{ { 1u, 1u } };
impl::utf8_decoder a, b;
for (size_t i = 0, e = std::min(str_a.length(), str_b.length()); i < e; i++, diff.index++)
{
a(static_cast<uint8_t>(str_a[i]));
b(static_cast<uint8_t>(str_b[i]));
if (a.has_code_point() != b.has_code_point() || a.error() != b.error())
return diff;
if (a.error())
{
a.reset();
b.reset();
continue;
}
if (!a.has_code_point())
continue;
if (a.codepoint != b.codepoint)
{
diff.a = a.codepoint;
diff.b = b.codepoint;
return diff;
}
if (a.codepoint == U'\n')
{
diff.position.line++;
diff.position.column = 1u;
}
else
diff.position.column++;
}
if (str_a.length() != str_b.length())
return diff;
return {};
}
}
#define CHECK_FORMATTER(formatter, data, expected) \
do \
{ \
const auto str = format_to_string<formatter>(data); \
const auto diff = find_first_difference(str, expected); \
if (diff) \
FORCE_FAIL("string mismatch: "sv << *diff); \
} \
while (false)
TEST_CASE("formatters")
{
const auto data_date = toml::date{ 2021, 11, 2 };
const auto data_time = toml::time{ 20, 33, 0 };
const auto data = toml::table{
{ "integers"sv,
toml::table{ { "zero"sv, 0 },
{ "one"sv, 1 },
{ "dec"sv, 10 },
{ "bin"sv, 10, toml::value_flags::format_as_binary },
{ "oct"sv, 10, toml::value_flags::format_as_octal },
{ "hex"sv, 10, toml::value_flags::format_as_hexadecimal } } },
{ "floats"sv,
toml::table{ { "pos_zero"sv, +0.0 },
{ "neg_zero"sv, -0.0 },
{ "one"sv, 1.0 },
{ "pos_inf"sv, +std::numeric_limits<double>::infinity() },
{ "neg_inf"sv, -std::numeric_limits<double>::infinity() },
{ "pos_nan"sv, +std::numeric_limits<double>::quiet_NaN() },
{ "neg_nan"sv, -std::numeric_limits<double>::quiet_NaN() }
} },
{ "dates and times"sv,
toml::table{
{ "dates"sv, toml::table{ { "val"sv, data_date } } },
{ "times"sv, toml::table{ { "val"sv, data_time } } },
{ "date-times"sv,
toml::table{
{ "local"sv, toml::table{ { "val"sv, toml::date_time{ data_date, data_time } } } },
{ "offset"sv,
toml::table{
{ "val"sv, toml::date_time{ data_date, data_time, toml::time_offset{} } } } } } } } },
{ "bools"sv,
toml::table{ { "true"sv, true }, //
{ "false"sv, false } } },
{
"strings"sv,
toml::array{ R"()"sv,
R"(string)"sv,
R"(string with a single quote in it: ')"sv,
R"(string with a double quote in it: ")"sv,
"string with a tab: \t"sv,
R"(a long string to force the array over multiple lines)"sv },
},
{ "a"sv,
toml::table{ { "val", true },
{ "b"sv, toml::table{ { "val", true }, { "c"sv, toml::table{ { "val", true } } } } } } }
};
SECTION("toml_formatter")
{
static constexpr auto expected = R"(*****
strings = [
'',
'string',
"string with a single quote in it: '",
'string with a double quote in it: "',
'string with a tab: ',
'a long string to force the array over multiple lines'
]
[a]
val = true
[a.b]
val = true
[a.b.c]
val = true
[bools]
false = false
true = true
['dates and times'.date-times.local]
val = 2021-11-02T20:33:00
['dates and times'.date-times.offset]
val = 2021-11-02T20:33:00Z
['dates and times'.dates]
val = 2021-11-02
['dates and times'.times]
val = 20:33:00
[floats]
neg_inf = -inf
neg_nan = nan
neg_zero = -0.0
one = 1.0
pos_inf = inf
pos_nan = nan
pos_zero = 0.0
[integers]
bin = 0b1010
dec = 10
hex = 0xA
oct = 0o12
one = 1
zero = 0
*****)"sv;
CHECK_FORMATTER(toml_formatter, data, expected);
}
SECTION("json_formatter")
{
static constexpr auto expected = R"(*****
{
"a" : {
"b" : {
"c" : {
"val" : true
},
"val" : true
},
"val" : true
},
"bools" : {
"false" : false,
"true" : true
},
"dates and times" : {
"date-times" : {
"local" : {
"val" : "2021-11-02T20:33:00"
},
"offset" : {
"val" : "2021-11-02T20:33:00Z"
}
},
"dates" : {
"val" : "2021-11-02"
},
"times" : {
"val" : "20:33:00"
}
},
"floats" : {
"neg_inf" : "-Infinity",
"neg_nan" : "NaN",
"neg_zero" : -0.0,
"one" : 1.0,
"pos_inf" : "Infinity",
"pos_nan" : "NaN",
"pos_zero" : 0.0
},
"integers" : {
"bin" : 10,
"dec" : 10,
"hex" : 10,
"oct" : 10,
"one" : 1,
"zero" : 0
},
"strings" : [
"",
"string",
"string with a single quote in it: '",
"string with a double quote in it: \"",
"string with a tab: \t",
"a long string to force the array over multiple lines"
]
}
*****)"sv;
CHECK_FORMATTER(json_formatter, data, expected);
}
SECTION("yaml_formatter")
{
static constexpr auto expected = R"(*****
a:
b:
c:
val: true
val: true
val: true
bools:
false: false
true: true
'dates and times':
date-times:
local:
val: '2021-11-02T20:33:00'
offset:
val: '2021-11-02T20:33:00Z'
dates:
val: '2021-11-02'
times:
val: '20:33:00'
floats:
neg_inf: -.inf
neg_nan: .NAN
neg_zero: -0.0
one: 1.0
pos_inf: .inf
pos_nan: .NAN
pos_zero: 0.0
integers:
bin: 10
dec: 10
hex: 0xA
oct: 0o12
one: 1
zero: 0
strings:
- ''
- string
- "string with a single quote in it: '"
- 'string with a double quote in it: "'
- "string with a tab: \t"
- 'a long string to force the array over multiple lines'
*****)"sv;
CHECK_FORMATTER(yaml_formatter, data, expected);
}
}

View File

@ -5,17 +5,17 @@
#include "settings.h"
#if !TOML_HEADER_ONLY
#define TOML_IMPLEMENTATION
#define TOML_IMPLEMENTATION
#endif
#if USE_TARTANLLAMA_OPTIONAL
#include "tloptional.h"
#include "lib_tloptional.h"
#endif
#if USE_SINGLE_HEADER
#include "../toml.hpp"
#include "../toml.hpp"
#else
#include "../include/toml++/toml.h"
#include "../include/toml++/toml.h"
#endif
namespace toml
@ -23,306 +23,395 @@ namespace toml
using std::declval;
using std::is_same_v;
#define CHECK_NODE_TYPE_MAPPING(T, expected) \
static_assert(impl::node_type_of<T> == expected); \
static_assert(impl::node_type_of<T&> == expected); \
static_assert(impl::node_type_of<T&&> == expected); \
static_assert(impl::node_type_of<const T> == expected); \
static_assert(impl::node_type_of<const T&> == expected); \
static_assert(impl::node_type_of<const T&&> == expected); \
static_assert(impl::node_type_of<volatile T> == expected); \
static_assert(impl::node_type_of<volatile T&> == expected); \
static_assert(impl::node_type_of<volatile T&&> == expected); \
static_assert(impl::node_type_of<const volatile T> == expected); \
static_assert(impl::node_type_of<const volatile T&> == expected); \
static_assert(impl::node_type_of<const volatile T&&> == expected)
#define CHECK_NODE_TYPE_MAPPING(T, expected) \
static_assert(impl::node_type_of<T> == expected); \
static_assert(impl::node_type_of<T&> == expected); \
static_assert(impl::node_type_of<T&&> == expected); \
static_assert(impl::node_type_of<const T> == expected); \
static_assert(impl::node_type_of<const T&> == expected); \
static_assert(impl::node_type_of<const T&&> == expected); \
static_assert(impl::node_type_of<volatile T> == expected); \
static_assert(impl::node_type_of<volatile T&> == expected); \
static_assert(impl::node_type_of<volatile T&&> == expected); \
static_assert(impl::node_type_of<const volatile T> == expected); \
static_assert(impl::node_type_of<const volatile T&> == expected); \
static_assert(impl::node_type_of<const volatile T&&> == expected)
CHECK_NODE_TYPE_MAPPING(int64_t, node_type::integer);
CHECK_NODE_TYPE_MAPPING(double, node_type::floating_point);
CHECK_NODE_TYPE_MAPPING(std::string, node_type::string);
CHECK_NODE_TYPE_MAPPING(bool, node_type::boolean);
CHECK_NODE_TYPE_MAPPING(toml::date, node_type::date);
CHECK_NODE_TYPE_MAPPING(toml::time, node_type::time);
CHECK_NODE_TYPE_MAPPING(toml::date_time, node_type::date_time);
CHECK_NODE_TYPE_MAPPING(toml::array, node_type::array);
CHECK_NODE_TYPE_MAPPING(toml::table, node_type::table);
CHECK_NODE_TYPE_MAPPING(int64_t, node_type::integer);
CHECK_NODE_TYPE_MAPPING(double, node_type::floating_point);
CHECK_NODE_TYPE_MAPPING(std::string, node_type::string);
CHECK_NODE_TYPE_MAPPING(bool, node_type::boolean);
CHECK_NODE_TYPE_MAPPING(toml::date, node_type::date);
CHECK_NODE_TYPE_MAPPING(toml::time, node_type::time);
CHECK_NODE_TYPE_MAPPING(toml::date_time, node_type::date_time);
CHECK_NODE_TYPE_MAPPING(toml::array, node_type::array);
CHECK_NODE_TYPE_MAPPING(toml::table, node_type::table);
#define CHECK_CAN_REPRESENT_NATIVE(T, expected) \
static_assert((impl::value_traits<T>::is_native || impl::value_traits<T>::can_represent_native) == expected)
#define CHECK_CAN_REPRESENT_NATIVE(T, expected) \
static_assert((impl::value_traits<T>::is_native || impl::value_traits<T>::can_represent_native) == expected)
CHECK_CAN_REPRESENT_NATIVE(time, true);
CHECK_CAN_REPRESENT_NATIVE(date, true);
CHECK_CAN_REPRESENT_NATIVE(date_time, true);
CHECK_CAN_REPRESENT_NATIVE(bool, true);
CHECK_CAN_REPRESENT_NATIVE(int8_t, false);
CHECK_CAN_REPRESENT_NATIVE(int16_t, false);
CHECK_CAN_REPRESENT_NATIVE(int32_t, false);
CHECK_CAN_REPRESENT_NATIVE(int64_t, true);
CHECK_CAN_REPRESENT_NATIVE(uint8_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint16_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint32_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint64_t, false);
CHECK_CAN_REPRESENT_NATIVE(float, false);
CHECK_CAN_REPRESENT_NATIVE(double, true);
#ifdef TOML_INT128
CHECK_CAN_REPRESENT_NATIVE(TOML_INT128, true);
CHECK_CAN_REPRESENT_NATIVE(TOML_UINT128, false);
#endif
#ifdef TOML_FP16
CHECK_CAN_REPRESENT_NATIVE(time, true);
CHECK_CAN_REPRESENT_NATIVE(date, true);
CHECK_CAN_REPRESENT_NATIVE(date_time, true);
CHECK_CAN_REPRESENT_NATIVE(bool, true);
CHECK_CAN_REPRESENT_NATIVE(int8_t, false);
CHECK_CAN_REPRESENT_NATIVE(int16_t, false);
CHECK_CAN_REPRESENT_NATIVE(int32_t, false);
CHECK_CAN_REPRESENT_NATIVE(int64_t, true);
CHECK_CAN_REPRESENT_NATIVE(uint8_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint16_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint32_t, false);
CHECK_CAN_REPRESENT_NATIVE(uint64_t, false);
CHECK_CAN_REPRESENT_NATIVE(float, false);
CHECK_CAN_REPRESENT_NATIVE(double, true);
#ifdef TOML_INT128
CHECK_CAN_REPRESENT_NATIVE(TOML_INT128, true);
CHECK_CAN_REPRESENT_NATIVE(TOML_UINT128, false);
#endif
#ifdef TOML_FP16
CHECK_CAN_REPRESENT_NATIVE(TOML_FP16, false);
#endif
#ifdef TOML_FLOAT16
CHECK_CAN_REPRESENT_NATIVE(TOML_FLOAT16, false);
#endif
#ifdef TOML_FLOAT128
CHECK_CAN_REPRESENT_NATIVE(TOML_FLOAT128, true);
#endif
#endif
#ifdef TOML_FLOAT16
CHECK_CAN_REPRESENT_NATIVE(TOML_FLOAT16, false);
#endif
#ifdef TOML_FLOAT128
CHECK_CAN_REPRESENT_NATIVE(TOML_FLOAT128, true);
#endif
CHECK_CAN_REPRESENT_NATIVE(char*, false);
CHECK_CAN_REPRESENT_NATIVE(char*const, false);
CHECK_CAN_REPRESENT_NATIVE(char[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char[2], false);
CHECK_CAN_REPRESENT_NATIVE(char(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char*, true);
CHECK_CAN_REPRESENT_NATIVE(const char*const, true);
CHECK_CAN_REPRESENT_NATIVE(std::string, true);
CHECK_CAN_REPRESENT_NATIVE(std::string_view, true);
#if TOML_HAS_CHAR8
CHECK_CAN_REPRESENT_NATIVE(char8_t*, false);
CHECK_CAN_REPRESENT_NATIVE(char8_t*const, false);
CHECK_CAN_REPRESENT_NATIVE(char8_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(char8_t(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t*, true);
CHECK_CAN_REPRESENT_NATIVE(const char8_t*const, true);
CHECK_CAN_REPRESENT_NATIVE(std::u8string, true);
CHECK_CAN_REPRESENT_NATIVE(std::u8string_view, true);
#endif
CHECK_CAN_REPRESENT_NATIVE(wchar_t*, false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t*const, false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t(&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t*, false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t*const, false);
CHECK_CAN_REPRESENT_NATIVE(std::wstring, !!TOML_WINDOWS_COMPAT);
CHECK_CAN_REPRESENT_NATIVE(std::wstring_view, false);
CHECK_CAN_REPRESENT_NATIVE(char*, false);
CHECK_CAN_REPRESENT_NATIVE(char* const, false);
CHECK_CAN_REPRESENT_NATIVE(char[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char[2], false);
CHECK_CAN_REPRESENT_NATIVE(char (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char*, true);
CHECK_CAN_REPRESENT_NATIVE(const char* const, true);
CHECK_CAN_REPRESENT_NATIVE(std::string, true);
CHECK_CAN_REPRESENT_NATIVE(std::string_view, true);
#if TOML_HAS_CHAR8
CHECK_CAN_REPRESENT_NATIVE(char8_t*, false);
CHECK_CAN_REPRESENT_NATIVE(char8_t* const, false);
CHECK_CAN_REPRESENT_NATIVE(char8_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(char8_t (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const char8_t*, true);
CHECK_CAN_REPRESENT_NATIVE(const char8_t* const, true);
CHECK_CAN_REPRESENT_NATIVE(std::u8string, true);
CHECK_CAN_REPRESENT_NATIVE(std::u8string_view, true);
#endif
CHECK_CAN_REPRESENT_NATIVE(wchar_t*, false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t* const, false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t[2], false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t (&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(wchar_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t(&&)[2], false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t*, false);
CHECK_CAN_REPRESENT_NATIVE(const wchar_t* const, false);
CHECK_CAN_REPRESENT_NATIVE(std::wstring, !!TOML_ENABLE_WINDOWS_COMPAT);
CHECK_CAN_REPRESENT_NATIVE(std::wstring_view, false);
#define CHECK_VALUE_EXACT(T, expected) \
static_assert(is_same_v<decltype(declval<node>().value_exact<T>()), optional<expected>>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().value_exact<T>()), optional<expected>>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_exact<T>()), optional<expected>>)
#define CHECK_VALUE_EXACT(T, expected) \
static_assert(is_same_v<decltype(declval<node>().value_exact<T>()), optional<expected>>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().value_exact<T>()), optional<expected>>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_exact<T>()), optional<expected>>)
#define CHECK_VALUE_OR(T, expected) \
static_assert(is_same_v<decltype(declval<node>().value_or(declval<T>())), expected>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().value_or(declval<T>())), expected>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_or(declval<T>())), expected>)
#define CHECK_VALUE_OR(T, expected) \
static_assert(is_same_v<decltype(declval<node>().value_or(declval<T>())), expected>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().value_or(declval<T>())), expected>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_or(declval<T>())), expected>)
CHECK_VALUE_EXACT( time, time);
CHECK_VALUE_EXACT( date, date);
CHECK_VALUE_EXACT( date_time, date_time);
CHECK_VALUE_EXACT( bool, bool);
CHECK_VALUE_EXACT( double, double);
CHECK_VALUE_EXACT( int64_t, int64_t);
CHECK_VALUE_EXACT( const char*, const char*);
CHECK_VALUE_EXACT( std::string_view, std::string_view);
CHECK_VALUE_EXACT( std::string, std::string);
#if TOML_HAS_CHAR8
CHECK_VALUE_EXACT( const char8_t*, const char8_t*);
CHECK_VALUE_EXACT( std::u8string_view, std::u8string_view);
CHECK_VALUE_EXACT( std::u8string, std::u8string);
#endif
CHECK_VALUE_EXACT(time, time);
CHECK_VALUE_EXACT(date, date);
CHECK_VALUE_EXACT(date_time, date_time);
CHECK_VALUE_EXACT(bool, bool);
CHECK_VALUE_EXACT(double, double);
CHECK_VALUE_EXACT(int64_t, int64_t);
CHECK_VALUE_EXACT(const char*, const char*);
CHECK_VALUE_EXACT(std::string_view, std::string_view);
CHECK_VALUE_EXACT(std::string, std::string);
#if TOML_HAS_CHAR8
CHECK_VALUE_EXACT(const char8_t*, const char8_t*);
CHECK_VALUE_EXACT(std::u8string_view, std::u8string_view);
CHECK_VALUE_EXACT(std::u8string, std::u8string);
#endif
CHECK_VALUE_OR( time, time);
CHECK_VALUE_OR( time&, time);
CHECK_VALUE_OR( time&&, time);
CHECK_VALUE_OR( time const, time);
CHECK_VALUE_OR( date, date);
CHECK_VALUE_OR( date&, date);
CHECK_VALUE_OR( date&&, date);
CHECK_VALUE_OR( date const, date);
CHECK_VALUE_OR( date_time, date_time);
CHECK_VALUE_OR( date_time&, date_time);
CHECK_VALUE_OR( date_time&&, date_time);
CHECK_VALUE_OR( date_time const, date_time);
CHECK_VALUE_OR( bool, bool);
CHECK_VALUE_OR( bool&, bool);
CHECK_VALUE_OR( bool&&, bool);
CHECK_VALUE_OR( bool const, bool);
CHECK_VALUE_OR( int32_t, int32_t);
CHECK_VALUE_OR( int32_t&, int32_t);
CHECK_VALUE_OR( int32_t&&, int32_t);
CHECK_VALUE_OR( int32_t const, int32_t);
CHECK_VALUE_OR( int64_t, int64_t);
CHECK_VALUE_OR( int64_t&, int64_t);
CHECK_VALUE_OR( int64_t&&, int64_t);
CHECK_VALUE_OR( int64_t const, int64_t);
#ifdef TOML_INT128
CHECK_VALUE_OR( TOML_INT128, TOML_INT128);
CHECK_VALUE_OR( TOML_INT128&, TOML_INT128);
CHECK_VALUE_OR( TOML_INT128&&, TOML_INT128);
CHECK_VALUE_OR( TOML_INT128 const, TOML_INT128);
CHECK_VALUE_OR( TOML_UINT128, TOML_UINT128);
CHECK_VALUE_OR( TOML_UINT128&, TOML_UINT128);
CHECK_VALUE_OR( TOML_UINT128&&, TOML_UINT128);
CHECK_VALUE_OR( TOML_UINT128 const, TOML_UINT128);
#endif
CHECK_VALUE_OR( float, float);
CHECK_VALUE_OR( float&, float);
CHECK_VALUE_OR( float&&, float);
CHECK_VALUE_OR( float const, float);
CHECK_VALUE_OR( double, double);
CHECK_VALUE_OR( double&, double);
CHECK_VALUE_OR( double&&, double);
CHECK_VALUE_OR( double const, double);
#ifdef TOML_FLOAT128
CHECK_VALUE_OR( TOML_FLOAT128, TOML_FLOAT128);
CHECK_VALUE_OR( TOML_FLOAT128&, TOML_FLOAT128);
CHECK_VALUE_OR( TOML_FLOAT128&&, TOML_FLOAT128);
CHECK_VALUE_OR( TOML_FLOAT128 const, TOML_FLOAT128);
#endif
CHECK_VALUE_OR( char*, const char*);
CHECK_VALUE_OR( char*&, const char*);
CHECK_VALUE_OR( char*&&, const char*);
CHECK_VALUE_OR( char*const, const char*);
CHECK_VALUE_OR( char[2], const char*);
CHECK_VALUE_OR( char(&)[2], const char*);
CHECK_VALUE_OR( char(&&)[2], const char*);
CHECK_VALUE_OR( const char*, const char*);
CHECK_VALUE_OR( const char*&, const char*);
CHECK_VALUE_OR( const char*&&, const char*);
CHECK_VALUE_OR( const char*const, const char*);
CHECK_VALUE_OR( const char[2], const char*);
CHECK_VALUE_OR( const char(&)[2], const char*);
CHECK_VALUE_OR( const char(&&)[2], const char*);
CHECK_VALUE_OR( std::string_view, std::string_view);
CHECK_VALUE_OR( std::string_view&, std::string_view);
CHECK_VALUE_OR( std::string_view&&, std::string_view);
CHECK_VALUE_OR( const std::string_view, std::string_view);
CHECK_VALUE_OR( const std::string_view&, std::string_view);
CHECK_VALUE_OR( const std::string_view&&, std::string_view);
CHECK_VALUE_OR( std::string, std::string);
CHECK_VALUE_OR( std::string&, std::string);
CHECK_VALUE_OR( std::string&&, std::string);
CHECK_VALUE_OR( const std::string, std::string);
CHECK_VALUE_OR( const std::string&, std::string);
CHECK_VALUE_OR( const std::string&&, std::string);
#if TOML_HAS_CHAR8
CHECK_VALUE_OR( char8_t*, const char8_t*);
CHECK_VALUE_OR( char8_t*&, const char8_t*);
CHECK_VALUE_OR( char8_t*&&, const char8_t*);
CHECK_VALUE_OR( char8_t*const, const char8_t*);
CHECK_VALUE_OR( char8_t[2], const char8_t*);
CHECK_VALUE_OR( char8_t(&)[2], const char8_t*);
CHECK_VALUE_OR( char8_t(&&)[2], const char8_t*);
CHECK_VALUE_OR( const char8_t*, const char8_t*);
CHECK_VALUE_OR( const char8_t*&, const char8_t*);
CHECK_VALUE_OR( const char8_t*&&, const char8_t*);
CHECK_VALUE_OR( const char8_t*const, const char8_t*);
CHECK_VALUE_OR( const char8_t[2], const char8_t*);
CHECK_VALUE_OR( const char8_t(&)[2], const char8_t*);
CHECK_VALUE_OR( const char8_t(&&)[2], const char8_t*);
CHECK_VALUE_OR( std::u8string_view, std::u8string_view);
CHECK_VALUE_OR( std::u8string_view&, std::u8string_view);
CHECK_VALUE_OR( std::u8string_view&&, std::u8string_view);
CHECK_VALUE_OR( const std::u8string_view, std::u8string_view);
CHECK_VALUE_OR( const std::u8string_view&, std::u8string_view);
CHECK_VALUE_OR( const std::u8string_view&&, std::u8string_view);
CHECK_VALUE_OR( std::u8string, std::u8string);
CHECK_VALUE_OR( std::u8string&, std::u8string);
CHECK_VALUE_OR( std::u8string&&, std::u8string);
CHECK_VALUE_OR( const std::u8string, std::u8string);
CHECK_VALUE_OR( const std::u8string&, std::u8string);
CHECK_VALUE_OR( const std::u8string&&, std::u8string);
#endif
#if TOML_WINDOWS_COMPAT
CHECK_VALUE_OR( wchar_t*, std::wstring);
CHECK_VALUE_OR( wchar_t*&, std::wstring);
CHECK_VALUE_OR( wchar_t*&&, std::wstring);
CHECK_VALUE_OR( wchar_t*const, std::wstring);
CHECK_VALUE_OR( wchar_t[2], std::wstring);
CHECK_VALUE_OR( wchar_t(&)[2], std::wstring);
CHECK_VALUE_OR( wchar_t(&&)[2], std::wstring);
CHECK_VALUE_OR( const wchar_t*, std::wstring);
CHECK_VALUE_OR( const wchar_t*&, std::wstring);
CHECK_VALUE_OR( const wchar_t*&&, std::wstring);
CHECK_VALUE_OR( const wchar_t*const, std::wstring);
CHECK_VALUE_OR( const wchar_t[2], std::wstring);
CHECK_VALUE_OR( const wchar_t(&)[2], std::wstring);
CHECK_VALUE_OR( const wchar_t(&&)[2], std::wstring);
CHECK_VALUE_OR( std::wstring_view, std::wstring);
CHECK_VALUE_OR( std::wstring_view&, std::wstring);
CHECK_VALUE_OR( std::wstring_view&&, std::wstring);
CHECK_VALUE_OR( const std::wstring_view, std::wstring);
CHECK_VALUE_OR( const std::wstring_view&, std::wstring);
CHECK_VALUE_OR( const std::wstring_view&&, std::wstring);
CHECK_VALUE_OR( std::wstring, std::wstring);
CHECK_VALUE_OR( std::wstring&, std::wstring);
CHECK_VALUE_OR( std::wstring&&, std::wstring);
CHECK_VALUE_OR( const std::wstring, std::wstring);
CHECK_VALUE_OR( const std::wstring&, std::wstring);
CHECK_VALUE_OR( const std::wstring&&, std::wstring);
#endif
CHECK_VALUE_OR(time, time);
CHECK_VALUE_OR(time&, time);
CHECK_VALUE_OR(time&&, time);
CHECK_VALUE_OR(time const, time);
CHECK_VALUE_OR(date, date);
CHECK_VALUE_OR(date&, date);
CHECK_VALUE_OR(date&&, date);
CHECK_VALUE_OR(date const, date);
CHECK_VALUE_OR(date_time, date_time);
CHECK_VALUE_OR(date_time&, date_time);
CHECK_VALUE_OR(date_time&&, date_time);
CHECK_VALUE_OR(date_time const, date_time);
CHECK_VALUE_OR(bool, bool);
CHECK_VALUE_OR(bool&, bool);
CHECK_VALUE_OR(bool&&, bool);
CHECK_VALUE_OR(bool const, bool);
CHECK_VALUE_OR(int32_t, int32_t);
CHECK_VALUE_OR(int32_t&, int32_t);
CHECK_VALUE_OR(int32_t&&, int32_t);
CHECK_VALUE_OR(int32_t const, int32_t);
CHECK_VALUE_OR(int64_t, int64_t);
CHECK_VALUE_OR(int64_t&, int64_t);
CHECK_VALUE_OR(int64_t&&, int64_t);
CHECK_VALUE_OR(int64_t const, int64_t);
#ifdef TOML_INT128
CHECK_VALUE_OR(TOML_INT128, TOML_INT128);
CHECK_VALUE_OR(TOML_INT128&, TOML_INT128);
CHECK_VALUE_OR(TOML_INT128&&, TOML_INT128);
CHECK_VALUE_OR(TOML_INT128 const, TOML_INT128);
CHECK_VALUE_OR(TOML_UINT128, TOML_UINT128);
CHECK_VALUE_OR(TOML_UINT128&, TOML_UINT128);
CHECK_VALUE_OR(TOML_UINT128&&, TOML_UINT128);
CHECK_VALUE_OR(TOML_UINT128 const, TOML_UINT128);
#endif
CHECK_VALUE_OR(float, float);
CHECK_VALUE_OR(float&, float);
CHECK_VALUE_OR(float&&, float);
CHECK_VALUE_OR(float const, float);
CHECK_VALUE_OR(double, double);
CHECK_VALUE_OR(double&, double);
CHECK_VALUE_OR(double&&, double);
CHECK_VALUE_OR(double const, double);
#ifdef TOML_FLOAT128
CHECK_VALUE_OR(TOML_FLOAT128, TOML_FLOAT128);
CHECK_VALUE_OR(TOML_FLOAT128&, TOML_FLOAT128);
CHECK_VALUE_OR(TOML_FLOAT128&&, TOML_FLOAT128);
CHECK_VALUE_OR(TOML_FLOAT128 const, TOML_FLOAT128);
#endif
CHECK_VALUE_OR(char*, const char*);
CHECK_VALUE_OR(char*&, const char*);
CHECK_VALUE_OR(char*&&, const char*);
CHECK_VALUE_OR(char* const, const char*);
CHECK_VALUE_OR(char[2], const char*);
CHECK_VALUE_OR(char (&)[2], const char*);
CHECK_VALUE_OR(char(&&)[2], const char*);
CHECK_VALUE_OR(const char*, const char*);
CHECK_VALUE_OR(const char*&, const char*);
CHECK_VALUE_OR(const char*&&, const char*);
CHECK_VALUE_OR(const char* const, const char*);
CHECK_VALUE_OR(const char[2], const char*);
CHECK_VALUE_OR(const char (&)[2], const char*);
CHECK_VALUE_OR(const char(&&)[2], const char*);
CHECK_VALUE_OR(std::string_view, std::string_view);
CHECK_VALUE_OR(std::string_view&, std::string_view);
CHECK_VALUE_OR(std::string_view&&, std::string_view);
CHECK_VALUE_OR(const std::string_view, std::string_view);
CHECK_VALUE_OR(const std::string_view&, std::string_view);
CHECK_VALUE_OR(const std::string_view&&, std::string_view);
CHECK_VALUE_OR(std::string, std::string);
CHECK_VALUE_OR(std::string&, std::string);
CHECK_VALUE_OR(std::string&&, std::string);
CHECK_VALUE_OR(const std::string, std::string);
CHECK_VALUE_OR(const std::string&, std::string);
CHECK_VALUE_OR(const std::string&&, std::string);
#if TOML_HAS_CHAR8
CHECK_VALUE_OR(char8_t*, const char8_t*);
CHECK_VALUE_OR(char8_t*&, const char8_t*);
CHECK_VALUE_OR(char8_t*&&, const char8_t*);
CHECK_VALUE_OR(char8_t* const, const char8_t*);
CHECK_VALUE_OR(char8_t[2], const char8_t*);
CHECK_VALUE_OR(char8_t (&)[2], const char8_t*);
CHECK_VALUE_OR(char8_t(&&)[2], const char8_t*);
CHECK_VALUE_OR(const char8_t*, const char8_t*);
CHECK_VALUE_OR(const char8_t*&, const char8_t*);
CHECK_VALUE_OR(const char8_t*&&, const char8_t*);
CHECK_VALUE_OR(const char8_t* const, const char8_t*);
CHECK_VALUE_OR(const char8_t[2], const char8_t*);
CHECK_VALUE_OR(const char8_t (&)[2], const char8_t*);
CHECK_VALUE_OR(const char8_t(&&)[2], const char8_t*);
CHECK_VALUE_OR(std::u8string_view, std::u8string_view);
CHECK_VALUE_OR(std::u8string_view&, std::u8string_view);
CHECK_VALUE_OR(std::u8string_view&&, std::u8string_view);
CHECK_VALUE_OR(const std::u8string_view, std::u8string_view);
CHECK_VALUE_OR(const std::u8string_view&, std::u8string_view);
CHECK_VALUE_OR(const std::u8string_view&&, std::u8string_view);
CHECK_VALUE_OR(std::u8string, std::u8string);
CHECK_VALUE_OR(std::u8string&, std::u8string);
CHECK_VALUE_OR(std::u8string&&, std::u8string);
CHECK_VALUE_OR(const std::u8string, std::u8string);
CHECK_VALUE_OR(const std::u8string&, std::u8string);
CHECK_VALUE_OR(const std::u8string&&, std::u8string);
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
CHECK_VALUE_OR(wchar_t*, std::wstring);
CHECK_VALUE_OR(wchar_t*&, std::wstring);
CHECK_VALUE_OR(wchar_t*&&, std::wstring);
CHECK_VALUE_OR(wchar_t* const, std::wstring);
CHECK_VALUE_OR(wchar_t[2], std::wstring);
CHECK_VALUE_OR(wchar_t (&)[2], std::wstring);
CHECK_VALUE_OR(wchar_t(&&)[2], std::wstring);
CHECK_VALUE_OR(const wchar_t*, std::wstring);
CHECK_VALUE_OR(const wchar_t*&, std::wstring);
CHECK_VALUE_OR(const wchar_t*&&, std::wstring);
CHECK_VALUE_OR(const wchar_t* const, std::wstring);
CHECK_VALUE_OR(const wchar_t[2], std::wstring);
CHECK_VALUE_OR(const wchar_t (&)[2], std::wstring);
CHECK_VALUE_OR(const wchar_t(&&)[2], std::wstring);
CHECK_VALUE_OR(std::wstring_view, std::wstring);
CHECK_VALUE_OR(std::wstring_view&, std::wstring);
CHECK_VALUE_OR(std::wstring_view&&, std::wstring);
CHECK_VALUE_OR(const std::wstring_view, std::wstring);
CHECK_VALUE_OR(const std::wstring_view&, std::wstring);
CHECK_VALUE_OR(const std::wstring_view&&, std::wstring);
CHECK_VALUE_OR(std::wstring, std::wstring);
CHECK_VALUE_OR(std::wstring&, std::wstring);
CHECK_VALUE_OR(std::wstring&&, std::wstring);
CHECK_VALUE_OR(const std::wstring, std::wstring);
CHECK_VALUE_OR(const std::wstring&, std::wstring);
CHECK_VALUE_OR(const std::wstring&&, std::wstring);
#endif
#define CHECK_INSERTED_AS(T, expected) \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&&>>)
#define CHECK_INSERTED_AS(T, expected) \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<const T&>>); \
static_assert(std::is_same_v<expected, toml::inserted_type_of<T&&>>)
CHECK_INSERTED_AS(table, table);
CHECK_INSERTED_AS(array, array);
CHECK_INSERTED_AS(node, node);
CHECK_INSERTED_AS(time, value<time>);
CHECK_INSERTED_AS(date, value<date>);
CHECK_INSERTED_AS(date_time, value<date_time>);
CHECK_INSERTED_AS(bool, value<bool>);
CHECK_INSERTED_AS(int8_t, value<int64_t>);
CHECK_INSERTED_AS(int16_t, value<int64_t>);
CHECK_INSERTED_AS(int32_t, value<int64_t>);
CHECK_INSERTED_AS(int64_t, value<int64_t>);
CHECK_INSERTED_AS(uint8_t, value<int64_t>);
CHECK_INSERTED_AS(uint16_t, value<int64_t>);
CHECK_INSERTED_AS(uint32_t, value<int64_t>);
CHECK_INSERTED_AS(float, value<double>);
CHECK_INSERTED_AS(double, value<double>);
#ifdef TOML_FP16
CHECK_INSERTED_AS(TOML_FP16, value<double>);
#endif
#ifdef TOML_FLOAT16
CHECK_INSERTED_AS(TOML_FLOAT16, value<double>);
#endif
CHECK_INSERTED_AS(table, table);
CHECK_INSERTED_AS(array, array);
CHECK_INSERTED_AS(node, node);
CHECK_INSERTED_AS(time, value<time>);
CHECK_INSERTED_AS(date, value<date>);
CHECK_INSERTED_AS(date_time, value<date_time>);
CHECK_INSERTED_AS(bool, value<bool>);
CHECK_INSERTED_AS(int8_t, value<int64_t>);
CHECK_INSERTED_AS(int16_t, value<int64_t>);
CHECK_INSERTED_AS(int32_t, value<int64_t>);
CHECK_INSERTED_AS(int64_t, value<int64_t>);
CHECK_INSERTED_AS(uint8_t, value<int64_t>);
CHECK_INSERTED_AS(uint16_t, value<int64_t>);
CHECK_INSERTED_AS(uint32_t, value<int64_t>);
CHECK_INSERTED_AS(float, value<double>);
CHECK_INSERTED_AS(double, value<double>);
#ifdef TOML_FP16
CHECK_INSERTED_AS(TOML_FP16, value<double>);
#endif
#ifdef TOML_FLOAT16
CHECK_INSERTED_AS(TOML_FLOAT16, value<double>);
#endif
static_assert(is_same_v<decltype(declval<node&>().ref<double>()), double&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<double>()), double&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<double>()), const double&>);
static_assert(is_same_v<decltype(declval<node&>().ref<value<double>>()), double&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<value<double>>()), double&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<value<double>>()), const double&>);
static_assert(is_same_v<decltype(declval<node&>().ref<table>()), table&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<table>()), table&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<table>()), const table&>);
static_assert(is_same_v<decltype(declval<node&>().ref<array>()), array&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<array>()), array&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<array>()), const array&>);
#define CHECK_NODE_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node&>().ref<T>()), T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<node&&>().ref<T>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<const node&>().ref<T>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<const node&&>().ref<T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_NODE_REF_TYPE(table);
CHECK_NODE_REF_TYPE(array);
CHECK_NODE_REF_TYPE(std::string);
CHECK_NODE_REF_TYPE(int64_t);
CHECK_NODE_REF_TYPE(double);
CHECK_NODE_REF_TYPE(bool);
CHECK_NODE_REF_TYPE(date);
CHECK_NODE_REF_TYPE(time);
CHECK_NODE_REF_TYPE(date_time);
#define CHECK_NODE_VIEW_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T>()), T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_NODE_VIEW_REF_TYPE(table);
CHECK_NODE_VIEW_REF_TYPE(array);
CHECK_NODE_VIEW_REF_TYPE(std::string);
CHECK_NODE_VIEW_REF_TYPE(int64_t);
CHECK_NODE_VIEW_REF_TYPE(double);
CHECK_NODE_VIEW_REF_TYPE(bool);
CHECK_NODE_VIEW_REF_TYPE(date);
CHECK_NODE_VIEW_REF_TYPE(time);
CHECK_NODE_VIEW_REF_TYPE(date_time);
#define CHECK_CONST_NODE_VIEW_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_CONST_NODE_VIEW_REF_TYPE(table);
CHECK_CONST_NODE_VIEW_REF_TYPE(array);
CHECK_CONST_NODE_VIEW_REF_TYPE(std::string);
CHECK_CONST_NODE_VIEW_REF_TYPE(int64_t);
CHECK_CONST_NODE_VIEW_REF_TYPE(double);
CHECK_CONST_NODE_VIEW_REF_TYPE(bool);
CHECK_CONST_NODE_VIEW_REF_TYPE(date);
CHECK_CONST_NODE_VIEW_REF_TYPE(time);
CHECK_CONST_NODE_VIEW_REF_TYPE(date_time);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<double>()), double&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<double>()), const double&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<value<double>>()), double&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<value<double>>()), const double&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<table>()), table&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<table>()), const table&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<array>()), array&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<array>()), const array&>);
}

View File

@ -10,10 +10,10 @@ namespace leakproof
void value_destroyed() noexcept;
}
#define TOML_LIFETIME_HOOKS 1
#define TOML_TABLE_CREATED ::leakproof::table_created()
#define TOML_TABLE_DESTROYED ::leakproof::table_destroyed()
#define TOML_ARRAY_CREATED ::leakproof::array_created()
#define TOML_ARRAY_DESTROYED ::leakproof::array_destroyed()
#define TOML_VALUE_CREATED ::leakproof::value_created()
#define TOML_VALUE_DESTROYED ::leakproof::value_destroyed()
#define TOML_LIFETIME_HOOKS 1
#define TOML_TABLE_CREATED ::leakproof::table_created()
#define TOML_TABLE_DESTROYED ::leakproof::table_destroyed()
#define TOML_ARRAY_CREATED ::leakproof::array_created()
#define TOML_ARRAY_DESTROYED ::leakproof::array_destroyed()
#define TOML_VALUE_CREATED ::leakproof::value_created()
#define TOML_VALUE_DESTROYED ::leakproof::value_destroyed()

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