support for upcoming TOML v1.0.0 release

see https://github.com/toml-lang/toml/issues/698 for info about TOML v1.0.0

also:
- fixed some parser error-paths not returning early enough when exceptions were disabled
- added more specific error messages for parsing errors relating to prohibited codepoints
- added compilation speed improvements (particularly for platforms lacking floating-point `std::to_chars`)
- added many minor documentation improvements
- added additional tests
This commit is contained in:
Mark Gillard 2020-04-03 00:39:21 +03:00
parent e260f2df79
commit cb000809b0
73 changed files with 2139 additions and 1751 deletions

1
.gitattributes vendored
View File

@ -18,3 +18,4 @@
*.css text encoding=UTF-8 eol=lf
meson.build text encoding=UTF-8 eol=lf
Doxyfile text encoding=UTF-8 eol=lf
Doxyfile-mcss text encoding=UTF-8 eol=lf

View File

@ -1,13 +1,15 @@
![banner](docs/tomlplusplus-banner-small.png)
[![C++](https://img.shields.io/badge/c%2B%2B-17%2C%2020-informational)][cpp_compilers]
[![TOML](https://img.shields.io/badge/TOML-v0.5.0-informational)][v0.5.0]
[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![Releases](https://img.shields.io/github/release/marzer/tomlplusplus.svg)](https://github.com/marzer/tomlplusplus/releases)
[![Mentioned in Awesome C++](https://awesome.re/mentioned-badge.svg)](https://github.com/fffaraz/awesome-cpp)
[![CircleCI](https://circleci.com/gh/marzer/tomlplusplus.svg?style=shield)](https://circleci.com/gh/marzer/tomlplusplus)
====
[![banner](docs/banner_small.png)][homepage]
[![Releases](https://img.shields.io/github/v/release/marzer/tomlplusplus?style=flat-square)](https://github.com/marzer/tomlplusplus/releases)
[![C++17](docs/badge-C++17.svg)][cpp_compilers]
[![C++20](docs/badge-C++20.svg)][cpp_compilers]
[![TOML](docs/badge-TOML.svg)][v1.0.0-rc.1]
[![MIT license](docs/badge-license-MIT.svg)](./LICENSE)
[![CircleCI](https://img.shields.io/circleci/build/github/marzer/tomlplusplus?label=circle%20ci&logo=circleci&logoColor=white&style=flat-square)](https://circleci.com/gh/marzer/tomlplusplus)
[![Mentioned in Awesome C++](docs/badge-awesome.svg)](https://github.com/fffaraz/awesome-cpp)
====
- Header-only
- [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md), plus optional support for some [unreleased TOML language features]
- [TOML v1.0.0-rc.1], plus optional support for some [unreleased TOML language features]
- C++17 (plus some C++20 features where available, e.g. experimental support for char8_t strings)
- Proper UTF-8 handling (incl. BOM)
- Works with or without exceptions
@ -24,7 +26,7 @@ Given a TOML file `configuration.toml` containing the following:
```toml
[library]
name = "toml++"
authors = ["Mark Gillard <mark@notarealwebsite.com>"]
authors = ["Mark Gillard <mark.gillard@outlook.com.au>"]
[dependencies]
cpp = 17
@ -69,19 +71,25 @@ You'll find some more code examples in the `examples` directory, and plenty more
<br>
# Adding toml++ to your project
`toml++` comes in two flavours: Regular and Single-header.
`toml++` comes in two flavours: Single-header and Regular. The API is the same for both.
### Regular mode
1. Add `tomlplusplus/include` to your include paths
2. `#include <toml++/toml.h>`
### Single-header mode
## 🍦 Single-header flavour
1. Drop `toml.hpp` wherever you like in your source tree
2. There is no step two
The API is the same regardless of how you consume the library.
## 🍨 Regular flavour
1. Add `tomlplusplus/include` to your include paths
2. `#include <toml++/toml.h>`
### Configuration
## _"What about build system X, or package manager Y?"_
Currently there's support for use as a meson submodule, which I _think_ means it can be used with Conan. That's the
extent of my knowledge in this area; clearly an area of opportunity! If you would like me to add support for a
particular build system or package manager please let me know by making a [feature request]. Better still, if you have
the skills and motivation to add support yourself, I'd welcome a pull request with a smile and open arms!
<br>
# Configuration
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++.
@ -101,35 +109,39 @@ won't need to mess with these at all, but if you do, set them before including t
| `TOML_UNDEF_MACROS` | boolean | `1` | `#undefs` the library's internal macros at the end of the header. |
| `TOML_UNRELEASED_FEATURES` | boolean | `1` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
_A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally linking incompatible combinations together._
> _A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally
linking incompatible combinations together._
<br>
# TOML Language Support
At any given time `toml++` aims to implement whatever the [numbered version] of TOML is, with the
At any given time `toml++` aims to implement whatever the [most recently-released version] of TOML is, with the
addition of unreleased features from the [TOML master] and some sane cherry-picks from the
[TOML issues list] where the discussion strongly indicates inclusion in a near-future release.
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`.
### **🔸Unreleased TOML features:**
- [#356]: Allow leading zeros in the exponent part of a float
## 🔶 **Unreleased features:**
- [#516]: Allow newlines and trailing commas in inline tables
- [#562]: Allow hex floatingpoint values
- [#567]: Clarify that control characters are not permitted in comments
- [#571]: Allow raw tabs inside strings
- [#562]: Allow hex floating-point values
- [#644]: Support `+` in key names
- [#665]: Make arrays heterogeneous
- [#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
_These can be disabled (and thus strict [TOML v0.5.0] compliance enforced) by specifying
> _Unreleased features can be disabled (and thus strict [TOML v1.0.0-rc.1] compliance enforced) by specifying
`TOML_UNRELEASED_FEATURES = 0` (see [Configuration](#Configuration))._
### **🔹TOML v0.5.0 and earlier:**
- All features supported.
## 🟢 **TOML v1.0.0-rc.1:**
All features supported, including:
- [#356]: Allow leading zeros in the exponent part of a float
- [#567]: Control characters are not permitted in comments
- [#571]: Allow raw tabs inside strings
- [#665]: Make arrays heterogeneous
## 🟢 **TOML v0.5.0:**
All features supported.
<br>
@ -158,18 +170,20 @@ 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-toml-features
[numbered version]: https://github.com/toml-lang/toml/releases
[most recently-released version]: https://github.com/toml-lang/toml/releases
[char8_t]: https://en.cppreference.com/w/cpp/keyword/char8_t
[TOML master]: https://github.com/toml-lang/toml/blob/master/README.md
[TOML issues list]: https://github.com/toml-lang/toml/issues
[TOML v0.5.0]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md
[v0.5.0]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md
[TOML v1.0.0-rc.1]: https://github.com/toml-lang/toml/blob/master/README.md
[v1.0.0-rc.1]: https://github.com/toml-lang/toml/blob/master/README.md
[CONTRIBUTING]: ./CONTRIBUTING.md
[LICENSE]: ./LICENSE
[Flexible and Economical UTF-8 Decoder]: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
[cpp_compilers]: https://en.cppreference.com/w/cpp/compiler_support
[reporting issues]: https://github.com/marzer/tomlplusplus/issues
[reporting issues]: https://github.com/marzer/tomlplusplus/issues/new/choose
[feature request]: https://github.com/marzer/tomlplusplus/issues/new/choose
[issues]: https://github.com/marzer/tomlplusplus/issues
[#356]: https://github.com/toml-lang/toml/issues/356
[#516]: https://github.com/toml-lang/toml/issues/516

View File

@ -7,7 +7,7 @@ DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = toml++
PROJECT_NUMBER =
PROJECT_BRIEF = TOML for modern C++
PROJECT_LOGO = tomlplusplus-logo.png
PROJECT_LOGO = logo.png
OUTPUT_DIRECTORY = ./
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO

View File

@ -7,10 +7,15 @@ HTML_EXTRA_STYLESHEET = \
HTML_EXTRA_FILES = \
tomlplusplus.js \
tomlplusplus-logo.png \
tomlplusplus-banner.png \
tomlplusplus-banner-small.png \
github-icon.png
logo.png \
banner_small.png \
github-icon.png \
badge-awesome.svg \
badge-C++17.svg \
badge-C++20.svg \
badge-license-MIT.svg \
badge-TOML.svg
##! M_THEME_COLOR = #22272e
##! M_LINKS_NAVBAR1 = \
@ -25,6 +30,6 @@ HTML_EXTRA_FILES = \
##! <a target="_blank" href="https://github.com/marzer/tomlplusplus/issues">Report an issue</a> \
##! <br><br>Documentation generated using <a href="https://mcss.mosra.cz/">m.css</a>
##! M_HTML_HEADER = <meta name="google-site-verification" content="gbtcNgKlNiPSMKkYMw4zWFVWGPH_oU93m9n_-nb4qK8" />\
##! <meta name="description" content="TOML parser and serializer for C++17, C++20, and whatever comes after.">\
##! <meta name="description" content="Header-only TOML config file parser and serializer for modern C++.">\
##! <script src="tomlplusplus.js"></script>
##! M_FAVICON = favicon.ico

1
docs/badge-C++17.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="125" height="20"><g shape-rendering="crispEdges"><path fill="#555" d="M0 0h76v20H0z"/><path fill="#007ec6" d="M76 0h49v20H76z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QysrIGljb248L3RpdGxlPjxwYXRoIGQ9Ik0yMi4zOTMgNmMtLjE2Ny0uMjktLjM5OC0uNTQzLS42NTItLjY5TDEyLjkyNS4yMmMtLjUwOC0uMjkzLTEuMzM5LS4yOTMtMS44NDcgMEwyLjI2IDUuMzFjLS41MDguMjkzLS45MjMgMS4wMTMtLjkyMyAxLjZ2MTAuMThjMCAuMjk0LjEwNC42Mi4yNzEuOTEuMTY3LjI5LjM5OC41NDMuNjUyLjY4OWw4LjgxNiA1LjA5MWMuNTA4LjI5MyAxLjMzOS4yOTMgMS44NDcgMGw4LjgxNi01LjA5MWMuMjU0LS4xNDYuNDg1LS4zOTkuNjUyLS42ODlzLjI3MS0uNjE2LjI3MS0uOTFWNi45MWMuMDAyLS4yOTQtLjEwMi0uNjItLjI2OS0uOTF6TTEyIDE5LjEwOWMtMy45MiAwLTcuMTA5LTMuMTg5LTcuMTA5LTcuMTA5UzguMDggNC44OTEgMTIgNC44OTFhNy4xMzMgNy4xMzMgMCAwIDEgNi4xNTYgMy41NTJsLTMuMDc2IDEuNzgxQTMuNTY3IDMuNTY3IDAgMCAwIDEyIDguNDQ1Yy0xLjk2IDAtMy41NTQgMS41OTUtMy41NTQgMy41NTVTMTAuMDQgMTUuNTU1IDEyIDE1LjU1NWEzLjU3IDMuNTcgMCAwIDAgMy4wOC0xLjc3OGwzLjA3NyAxLjc4QTcuMTM1IDcuMTM1IDAgMCAxIDEyIDE5LjEwOXptNy4xMDktNi43MTRoLS43OXYuNzloLS43OXYtLjc5aC0uNzl2LS43OWguNzl2LS43OWguNzl2Ljc5aC43OXYuNzl6bTIuOTYyIDBoLS43OXYuNzloLS43OXYtLjc5aC0uNzg5di0uNzloLjc4OXYtLjc5aC43OXYuNzloLjc5di43OXoiLz48L3N2Zz4="/> <text x="475" y="140" transform="scale(.1)" textLength="490">standard</text><text x="995" y="140" transform="scale(.1)" textLength="390">C++17</text></g> </svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
docs/badge-C++20.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="125" height="20"><g shape-rendering="crispEdges"><path fill="#555" d="M0 0h76v20H0z"/><path fill="#007ec6" d="M76 0h49v20H76z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QysrIGljb248L3RpdGxlPjxwYXRoIGQ9Ik0yMi4zOTMgNmMtLjE2Ny0uMjktLjM5OC0uNTQzLS42NTItLjY5TDEyLjkyNS4yMmMtLjUwOC0uMjkzLTEuMzM5LS4yOTMtMS44NDcgMEwyLjI2IDUuMzFjLS41MDguMjkzLS45MjMgMS4wMTMtLjkyMyAxLjZ2MTAuMThjMCAuMjk0LjEwNC42Mi4yNzEuOTEuMTY3LjI5LjM5OC41NDMuNjUyLjY4OWw4LjgxNiA1LjA5MWMuNTA4LjI5MyAxLjMzOS4yOTMgMS44NDcgMGw4LjgxNi01LjA5MWMuMjU0LS4xNDYuNDg1LS4zOTkuNjUyLS42ODlzLjI3MS0uNjE2LjI3MS0uOTFWNi45MWMuMDAyLS4yOTQtLjEwMi0uNjItLjI2OS0uOTF6TTEyIDE5LjEwOWMtMy45MiAwLTcuMTA5LTMuMTg5LTcuMTA5LTcuMTA5UzguMDggNC44OTEgMTIgNC44OTFhNy4xMzMgNy4xMzMgMCAwIDEgNi4xNTYgMy41NTJsLTMuMDc2IDEuNzgxQTMuNTY3IDMuNTY3IDAgMCAwIDEyIDguNDQ1Yy0xLjk2IDAtMy41NTQgMS41OTUtMy41NTQgMy41NTVTMTAuMDQgMTUuNTU1IDEyIDE1LjU1NWEzLjU3IDMuNTcgMCAwIDAgMy4wOC0xLjc3OGwzLjA3NyAxLjc4QTcuMTM1IDcuMTM1IDAgMCAxIDEyIDE5LjEwOXptNy4xMDktNi43MTRoLS43OXYuNzloLS43OXYtLjc5aC0uNzl2LS43OWguNzl2LS43OWguNzl2Ljc5aC43OXYuNzl6bTIuOTYyIDBoLS43OXYuNzloLS43OXYtLjc5aC0uNzg5di0uNzloLjc4OXYtLjc5aC43OXYuNzloLjc5di43OXoiLz48L3N2Zz4="/> <text x="475" y="140" transform="scale(.1)" textLength="490">standard</text><text x="995" y="140" transform="scale(.1)" textLength="390">C++20</text></g> </svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
docs/badge-TOML.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="112" height="20"><g shape-rendering="crispEdges"><path fill="#555" d="M0 0h41v20H0z"/><path fill="#007ec6" d="M41 0h71v20H41z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="215" y="140" transform="scale(.1)" textLength="310">TOML</text><text x="755" y="140" transform="scale(.1)" textLength="610">v1.0.0 rc.1</text></g> </svg>

After

Width:  |  Height:  |  Size: 489 B

1
docs/badge-awesome.svg Normal file
View File

@ -0,0 +1 @@
<svg width="110" height="20" viewBox="0 0 110 20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>Mentioned in an Awesome list</title><defs><path d="M53.57 3.52h-4.446V7h.648V4.3c0-.072.06-.132.132-.132h1.38c.072 0 .132.06.132.132V7h.648V4.3c0-.072.06-.132.132-.132h1.374c.078 0 .138.06.138.132V7h.642V4.3a.778.778 0 0 0-.78-.78zm4.704 0c.432 0 .78.348.78.78v1.284h-2.892v.636c0 .072.06.132.132.132h2.76V7h-2.76a.778.778 0 0 1-.78-.78V4.3c0-.432.348-.78.78-.78h1.98zm-2.112 1.416h2.244V4.3a.133.133 0 0 0-.132-.132h-1.98a.133.133 0 0 0-.132.132v.636zm6.822-1.416h-2.76V7h.648V4.3c0-.072.06-.132.132-.132h1.98c.072 0 .132.06.132.132V7h.648V4.3a.778.778 0 0 0-.78-.78zm4.026.648V3.52h-1.428V2.38h-.648v3.84c0 .432.348.78.78.78h1.296v-.648h-1.296a.133.133 0 0 1-.132-.132V4.168h1.428zM67.928 7h.648V3.52h-.648V7zm0-4.62v.648h.648V2.38h-.648zm2.562 1.14h1.98c.432 0 .78.348.78.78v1.92c0 .432-.348.78-.78.78h-1.98a.778.778 0 0 1-.78-.78V4.3c0-.432.348-.78.78-.78zm1.98.648h-1.98a.133.133 0 0 0-.132.132v1.92c0 .072.06.132.132.132h1.98c.072 0 .132-.06.132-.132V4.3a.133.133 0 0 0-.132-.132zm4.62-.648h-2.76V7h.648V4.3c0-.072.06-.132.132-.132h1.98c.072 0 .132.06.132.132V7h.648V4.3a.778.778 0 0 0-.78-.78zm4.698 0c.432 0 .78.348.78.78v1.284h-2.892v.636c0 .072.06.132.132.132h2.76V7h-2.76a.778.778 0 0 1-.78-.78V4.3c0-.432.348-.78.78-.78h1.98zm-2.112 1.416h2.244V4.3a.133.133 0 0 0-.132-.132h-1.98a.133.133 0 0 0-.132.132v.636zm6.768-2.556h.648V7h-2.76a.778.778 0 0 1-.78-.78V4.3c0-.432.348-.78.78-.78h2.112V2.38zm-2.112 3.972h1.98c.072 0 .132-.06.132-.132V4.3a.133.133 0 0 0-.132-.132h-1.98a.133.133 0 0 0-.132.132v1.92c0 .072.06.132.132.132zM90.548 7h.648V3.52h-.648V7zm0-4.62v.648h.648V2.38h-.648zm4.56 1.14h-2.76V7h.648V4.3c0-.072.06-.132.132-.132h1.98c.072 0 .132.06.132.132V7h.648V4.3a.778.778 0 0 0-.78-.78z" id="a"/></defs><g fill="none" fill-rule="evenodd"><g fill-rule="nonzero"><path fill="#CCA6C4" d="M0 0h34v20H0z"/><path fill="#494368" d="M34 0h77v20H34z"/></g><g fill-rule="nonzero"><path d="M46.97 9.92c.42 0 .75.13 1.05.4.28.27.43.59.43.98v4.79h-5.24c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-2.27h5.5v-1.15c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-5.24V9.92h5.23zm.26 5.02v-1.36h-4.26v1.13c0 .07.03.12.08.16.05.04.11.07.17.07h4.01zm11.86-5.02h1.3l-2.49 6.17h-1l-2.22-4.59-2.1 4.59-.03-.01.01.01h-1l-2.6-6.17h1.3l1.79 4.09 1.91-4.09h1.4l2.02 4.09 1.71-4.09zm6.95 0c.42 0 .77.13 1.05.4s.43.59.43.98v2.27h-5.5v1.13c0 .07.03.12.08.16.05.04.11.07.17.07h5.24v1.14h-5.24c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-3.4c0-.38.15-.71.43-.98s.63-.4 1.05-.4h3.77v.01zm-4.01 2.5h4.26v-1.13c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-3.77a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v1.13h.01zm13.35-1.13v.23h-1.22v-.23c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-3.77a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v.9c0 .07.03.12.08.16.05.04.11.07.17.07h3.77c.42 0 .75.13 1.05.4.28.27.43.59.43.98v.89c0 .38-.15.71-.43.98s-.63.4-1.05.4h-3.77c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-.23h1.24v.23c0 .07.03.12.08.16.05.04.11.07.17.07h3.77c.07 0 .12-.03.17-.07.05-.04.08-.11.08-.16v-.89c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-3.77c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-.9c0-.38.15-.71.43-.98s.63-.4 1.05-.4h3.77c.42 0 .75.13 1.05.4.27.28.41.61.41.98zm2.6-1.37h3.77c.42 0 .77.13 1.05.4s.43.59.43.98v3.4c0 .38-.15.71-.43.98s-.63.4-1.05.4h-3.77c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-3.41c0-.38.15-.71.43-.98.3-.26.65-.39 1.05-.39zm3.77 1.14h-3.77a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v3.4c0 .07.03.12.08.16.05.04.11.07.17.07h3.77c.07 0 .12-.03.17-.07.05-.04.08-.11.08-.16v-3.4c0-.07-.03-.12-.08-.16a.241.241 0 0 0-.17-.07zm11.12-1.14c.42 0 .75.13 1.05.4.28.27.43.59.43.98v4.79h-1.22v-4.8c0-.07-.03-.12-.08-.16a.294.294 0 0 0-.19-.07h-2.61a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v4.79h-1.24v-4.79c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-2.62a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v4.79H84.4V9.92h8.47zm7.92 0c.42 0 .77.13 1.05.4s.43.59.43.98v2.27h-5.5v1.13c0 .07.03.12.08.16.05.04.11.07.17.07h5.24v1.14h-5.24c-.42 0-.77-.13-1.05-.4a1.31 1.31 0 0 1-.43-.98v-3.4c0-.38.15-.71.43-.98s.63-.4 1.05-.4h3.77v.01zm-4.02 2.5h4.26v-1.13c0-.07-.03-.12-.08-.16a.284.284 0 0 0-.17-.07h-3.77a.26.26 0 0 0-.17.07c-.05.04-.08.11-.08.16v1.13h.01z" fill="#FFF"/></g><use fill-opacity=".9" fill="#FFF" xlink:href="#a"/><g fill-rule="nonzero"><path d="M26.57 9.76l-4.91-4.5-.69.75 4.09 3.75H8.94l4.09-3.75-.69-.75-4.91 4.5v2.97c0 1.34 1.29 2.43 2.88 2.43h3.03c1.59 0 2.88-1.09 2.88-2.43v-1.95h1.57v1.95c0 1.34 1.29 2.43 2.88 2.43h3.03c1.59 0 2.88-1.09 2.88-2.43l-.01-2.97z" fill="#DDA4CA"/><path d="M26.57 9.34l-4.91-4.5-.69.75 4.09 3.75H8.94l4.09-3.75-.69-.75-4.91 4.5v2.97c0 1.34 1.29 2.43 2.88 2.43h3.03c1.59 0 2.88-1.09 2.88-2.43v-1.95h1.57v1.95c0 1.34 1.29 2.43 2.88 2.43h3.03c1.59 0 2.88-1.09 2.88-2.43l-.01-2.97z" fill="#261120"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="78" height="20"><g shape-rendering="crispEdges"><path fill="#555" d="M0 0h47v20H0z"/><path fill="purple" d="M47 0h31v20H47z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="245" y="140" transform="scale(.1)" textLength="370">license</text><text x="615" y="140" transform="scale(.1)" textLength="210">MIT</text></g> </svg>

After

Width:  |  Height:  |  Size: 482 B

BIN
docs/banner.ai Normal file

Binary file not shown.

BIN
docs/banner_large.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/banner_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -193,10 +193,12 @@ pre.m-code + pre.m-console span
.gh-badges
{
padding-bottom: 0.75rem;
margin-left: -0.9rem;
margin-right: -0.9rem;
}
.gh-badges a
{
margin-right: 0.5rem;
margin-right: 0.3rem;
}
/* page category subheading ("module" etc) */
@ -204,3 +206,14 @@ h1 span.m-thin
{
color: #747474;
}
/* banner on index page */
main > article > .m-container.m-container-inflatable > .m-row > div.m-col-l-10.m-push-l-1 > img.m-image
{
border-color: #405363;
border-style: solid;
border-width: 0.1rem;
margin-left: -1rem;
margin-right: -1rem;
max-width: calc(100% + 2rem);
}

View File

@ -30,12 +30,13 @@
#include "toml_array_impl.h"
#include "toml_table_impl.h"
#include "toml_parser_impl.h"
#include "toml_default_formatter_impl.h"
#endif
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_USE_STREAMS_FOR_FLOATS
#undef TOML_FLOATING_POINT_CHARCONV
#undef TOML_GNU_ATTR
#undef TOML_PUSH_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
@ -60,7 +61,7 @@
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EXACTLY
#undef TOML_LANG_UNRELEASED
#undef TOML_STRING_PREFIX_1
#undef TOML_STRING_PREFIX
#undef TOML_UNDEF_MACROS
@ -74,19 +75,18 @@
#undef TOML_TRIVIAL_ABI
#undef TOML_ABI_NAMESPACES
#undef TOML_PARSER_TYPENAME
#undef TOML_HAS_API_ANNOTATION
#endif
/// \mainpage toml++
///
/// \image html tomlplusplus-banner-small.png width=1280px
/// \image html banner_small.png width=1280px
///
/// \tableofcontents
///
///////////////////////////////////////////////////////////////////////
///
/// \section mainpage-features Features
/// - [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md), plus optional support for some
/// - [TOML v1.0.0-rc.1](https://github.com/toml-lang/toml/blob/master/README.md), plus optional support for some
/// unreleased TOML features
/// - C++17 (plus some C++20 features where available, e.g. experimental support for char8_t strings)
/// - Proper UTF-8 handling (incl. BOM)
@ -137,10 +137,9 @@
/// catch (const toml::parse_error& err)
/// {
/// std::cerr
/// << "Error parsing file '"sv << *err.source().path
/// << "':\n"sv << err.description()
/// << "\n ("sv << err.source().begin << ")"sv
/// << std::endl;
/// << "Error parsing file '" << *err.source().path
/// << "':\n" << err.description()
/// << "\n (" << err.source().begin << ")\n";
/// return 1;
/// }
///
@ -164,10 +163,9 @@
/// if (!tbl)
/// {
/// std::cerr
/// << "Error parsing file '"sv << *tbl.error().source().path
/// << "':\n"sv << tbl.error().description()
/// << "\n ("sv << tbl.error().source().begin << ")"sv
/// << std::endl;
/// << "Error parsing file '" << *tbl.error().source().path
/// << "':\n" << tbl.error().description()
/// << "\n (" << tbl.error().source().begin << ")\n";
/// return 1;
/// }
///
@ -184,7 +182,7 @@
/// }
/// catch (const toml::parse_error & err)
/// {
/// std::cerr << "Parsing failed:\n"sv << err << std::endl;
/// std::cerr << "Parsing failed:\n" << err << "\n";
/// return 1;
/// }
/// \ecpp
@ -220,7 +218,7 @@
/// static constexpr auto source = R"(
/// [library]
/// name = "toml++"
/// authors = ["Mark Gillard <mark@notarealwebsite.com>"]
/// authors = ["Mark Gillard <mark.gillard@outlook.com.au>"]
///
/// [dependencies]
/// cpp = 17
@ -229,14 +227,14 @@
/// // parse directly from a string view:
/// {
/// auto tbl = toml::parse(source);
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
/// }
///
/// // parse from a string stream:
/// {
/// std::stringstream ss{ std::string{ source } };
/// auto tbl = toml::parse(ss);
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
/// }
///
/// return 0;
@ -284,9 +282,9 @@
///
/// // get a view of the element 'numbers'
/// auto numbers = tbl["numbers"];
/// std::cout << "table has 'numbers': "sv << !!numbers << std::endl;
/// std::cout << "numbers is a: "sv << numbers.type() << std::endl;
/// std::cout << "numbers: "sv << numbers << std::endl;
/// std::cout << "table has 'numbers': " << !!numbers << "\n";
/// std::cout << "numbers is a: " << numbers.type() << "\n";
/// std::cout << "numbers: " << numbers << "\n";
///
/// // get the underlying array object to do some more advanced stuff
/// if (auto arr = numbers.as_array())
@ -306,15 +304,15 @@
/// // arrays are very similar to std::vector
/// arr->push_back(7);
/// arr->emplace_back<toml::array>(8, 9);
/// std::cout << "numbers: "sv << numbers << std::endl;
/// std::cout << "numbers: " << numbers << "\n";
/// }
///
/// // node-views can be chained to quickly query deeper
/// std::cout << "cats: "sv << tbl["animals"]["cats"] << std::endl;
/// std::cout << "fish[1]: "sv << tbl["animals"]["fish"][1] << std::endl;
/// std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
/// std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
///
/// // ...even if the element doesn't exist
/// std::cout << "dinosaurs: "sv << tbl["animals"]["dinosaurs"] << std::endl; //no dinosaurs :(
/// std::cout << "dinosaurs: " << tbl["animals"]["dinosaurs"] << "\n"; //no dinosaurs :(
///
/// return 0;
/// }
@ -349,7 +347,7 @@
/// auto tbl = toml::table{{
/// { "lib", "toml++" },
/// { "cpp", toml::array{ 17, 20, "and beyond" } },
/// { "toml", toml::array{ "0.5.0", "and beyond" } },
/// { "toml", toml::array{ "1.0.0", "and beyond" } },
/// { "repo", "https://github.com/marzer/tomlplusplus/" },
/// { "author", toml::table{{
/// { "name", "Mark Gillard" },
@ -360,22 +358,23 @@
/// }};
///
/// // serializing as TOML is just writing it to a stream
/// std::cout << "###### TOML ######"sv << std::endl;
/// std::cout << tbl << std::endl << std::endl;
/// std::cout << "###### TOML ######" << "\n\n";
/// std::cout << tbl << "\n\n";
///
/// // serializing as JSON is _also_ just writing it to a stream, but via a json_formatter:
/// std::cout << "###### JSON ######"sv << std::endl;
/// std::cout << toml::json_formatter{ tbl } << std::endl;
/// std::cout << "###### JSON ######" << "\n\n";
/// std::cout << toml::json_formatter{ tbl } << "\n\n";
/// return 0;
/// }
/// \ecpp
///
/// \out
/// ###### TOML ######
///
/// cpp = [17, 20, "and beyond"]
/// lib = "toml++"
/// repo = "https://github.com/marzer/tomlplusplus/"
/// toml = ["0.5.0", "and beyond"]
/// toml = ["1.0.0", "and beyond"]
///
/// [author]
/// github = "https://github.com/marzer"
@ -383,6 +382,7 @@
/// twitter = "https://twitter.com/marzer8789"
///
/// ###### JSON ######
///
/// {
/// "author" : {
/// "github" : "https://github.com/marzer",
@ -397,7 +397,7 @@
/// "lib" : "toml++",
/// "repo" : "https://github.com/marzer/tomlplusplus/",
/// "toml" : [
/// "0.5.0",
/// "1.0.0",
/// "and beyond"
/// ]
/// }
@ -434,11 +434,6 @@
/// #include "global_header_that_includes_toml++.h"
/// \ecpp
///
/// \m_class{m-note m-default}
///
/// Your project may already have a specific header/source file pair configured as a 'precompiled header'; if so,
/// that's the ideal place to put this machinery.
///
///////////////////////////////////////////////////////////////////////
///
/// \section mainpage-contributing Contributing

View File

@ -7,14 +7,14 @@
namespace toml::impl
{
template <bool is_const>
template <bool IsConst>
class array_iterator final
{
private:
friend class toml::array;
using raw_iterator = std::conditional_t<
is_const,
IsConst,
std::vector<std::unique_ptr<node>>::const_iterator,
std::vector<std::unique_ptr<node>>::iterator
>;
@ -31,7 +31,7 @@ namespace toml::impl
public:
using value_type = std::conditional_t<is_const, const node, node>;
using value_type = std::conditional_t<IsConst, const node, node>;
using reference = value_type&;
using pointer = value_type*;
using difference_type = ptrdiff_t;
@ -155,11 +155,6 @@ namespace toml::impl
}
};
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
extern template class array_iterator<true>;
extern template class array_iterator<false>;
#endif
template <typename T>
[[nodiscard]] TOML_ALWAYS_INLINE
auto make_node(T&& val) noexcept
@ -184,13 +179,12 @@ namespace toml::impl
}
}
namespace toml
{
[[nodiscard]] TOML_API bool operator == (const array& lhs, const array& rhs) noexcept;
[[nodiscard]] TOML_API bool operator != (const array& lhs, const array& rhs) noexcept;
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const array&);
template <typename Char>
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
/// \brief A TOML array.
///
@ -477,14 +471,14 @@ namespace toml
/// \brief Inserts a range of values into the array at a specific position.
///
/// \tparam ITER An iterator type. Must satisfy ForwardIterator.
/// \tparam Iter An iterator type. Must satisfy ForwardIterator.
/// \param pos The insertion position.
/// \param first Iterator to the first value being inserted.
/// \param last Iterator to the one-past-the-last value being inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if `first` == `last`).
template <typename ITER>
iterator insert(const_iterator pos, ITER first, ITER last) noexcept
template <typename Iter>
iterator insert(const_iterator pos, Iter first, Iter last) noexcept
{
const auto count = std::distance(first, last);
switch (count)
@ -832,14 +826,7 @@ namespace toml
/// \remarks Arrays inside child tables are not flattened.
void flatten();
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const array&);
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
};
}
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
namespace std
{
extern template class unique_ptr<toml::array>;
}
#endif

View File

@ -24,11 +24,8 @@
#define TOML_IMPLEMENTATION 0
#endif
#ifdef TOML_API
#define TOML_HAS_API_ANNOTATION 1
#else
#ifndef TOML_API
#define TOML_API
#define TOML_HAS_API_ANNOTATION 0
#endif
#ifndef TOML_CHAR_8_STRINGS
@ -94,8 +91,8 @@
#endif
//floating-point from_chars and to_chars are not implemented in any version of clang as of 1/1/2020
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 1
#ifndef TOML_FLOATING_POINT_CHARCONV
#define TOML_FLOATING_POINT_CHARCONV 0
#endif
#elif defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(__ICL))
@ -151,8 +148,8 @@
#define TOML_UNLIKELY
// floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 1
#ifndef TOML_FLOATING_POINT_CHARCONV
#define TOML_FLOATING_POINT_CHARCONV 0
#endif
#endif
@ -195,8 +192,8 @@
#ifndef TOML_DISABLE_INIT_WARNINGS
#define TOML_DISABLE_INIT_WARNINGS
#endif
#ifndef TOML_USE_STREAMS_FOR_FLOATS
#define TOML_USE_STREAMS_FOR_FLOATS 0
#ifndef TOML_FLOATING_POINT_CHARCONV
#define TOML_FLOATING_POINT_CHARCONV 1
#endif
#ifndef TOML_PUSH_WARNINGS
#define TOML_PUSH_WARNINGS
@ -293,8 +290,8 @@
#define TOML_LANG_AT_LEAST(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_EXACTLY(maj, min, rev) \
(TOML_LANG_EFFECTIVE_VERSION == TOML_MAKE_VERSION(maj, min, rev))
#define TOML_LANG_UNRELEASED \
TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
////////// INCLUDES
@ -325,9 +322,6 @@ TOML_DISABLE_ALL_WARNINGS
#ifndef TOML_OPTIONAL_TYPE
#include <optional>
#endif
#if TOML_USE_STREAMS_FOR_FLOATS
#include <sstream>
#endif
#if TOML_EXCEPTIONS
#include <stdexcept>
#endif
@ -503,7 +497,7 @@ namespace toml
/// (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_position
struct TOML_TRIVIAL_ABI source_position
{
/// \brief The line number.
/// \remarks Valid line numbers start at 1.
@ -707,18 +701,9 @@ namespace toml::impl
template <typename T>
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
#if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20) && _HAS_CXX20)
template <typename T>
using remove_cvref_t = std::remove_cvref_t<T>;
#else
template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
#endif
template <typename T, typename... U>
struct is_one_of_ : std::integral_constant<bool,
(false || ... || std::is_same_v<T, U>)
@ -727,12 +712,6 @@ namespace toml::impl
template <typename T, typename... U>
inline constexpr bool is_one_of = is_one_of_<T, U...>::value;
template <typename T, typename... U>
using enable_if_one_of = std::enable_if_t<is_one_of<T, U...>>;
template <typename T, typename... U>
using enable_if_not_one_of = std::enable_if_t<!is_one_of<T, U...>>;
template <typename T>
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr std::underlying_type_t<T> unbox_enum(T val) noexcept
@ -843,10 +822,10 @@ namespace toml::impl
template <> struct value_promoter<uint8_t> { using type = int64_t; };
template <> struct value_promoter<float> { using type = double; };
#ifdef TOML_SMALL_FLOAT_TYPE
template <> struct value_promoter<TOML_SMALL_FLOAT_TYPE> { using type = double; };
template <> struct value_promoter<TOML_SMALL_FLOAT_TYPE> { using type = double; };
#endif
#ifdef TOML_SMALL_INT_TYPE
template <> struct value_promoter<TOML_SMALL_INT_TYPE> { using type = int64_t; };
template <> struct value_promoter<TOML_SMALL_INT_TYPE> { using type = int64_t; };
#endif
template <typename T> using promoted = typename impl::value_promoter<T>::type;
@ -914,10 +893,9 @@ namespace toml::impl
"date-time"sv
};
#define TOML_P2S_DECL(linkage, type) \
template <typename CHAR> \
linkage void print_to_stream(type, std::basic_ostream<CHAR>&)
template <typename Char> \
linkage void print_to_stream(type, std::basic_ostream<Char>&)
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int8_t);
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int16_t);
@ -985,19 +963,24 @@ namespace toml
/// Element [2] is: string
/// Element [3] is: boolean
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, node_type rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, node_type rhs)
{
using underlying_t = std::underlying_type_t<node_type>;
const auto str = impl::node_type_friendly_names[static_cast<underlying_t>(rhs)];
if constexpr (std::is_same_v<CHAR, char>)
if constexpr (std::is_same_v<Char, char>)
return lhs << str;
else
{
if constexpr (sizeof(CHAR) == 1)
return lhs << std::basic_string_view<CHAR>{ reinterpret_cast<const CHAR*>(str.data()), str.length() };
if constexpr (sizeof(Char) == 1)
return lhs << std::basic_string_view<Char>{ reinterpret_cast<const Char*>(str.data()), str.length() };
else
return lhs << str.data();
}
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, node_type);
#endif
}

View File

@ -84,13 +84,18 @@ namespace toml
/// \out
/// 1987-03-16
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const date&);
#endif
/// \brief A local time-of-day.
struct TOML_TRIVIAL_ABI time final
{
@ -172,13 +177,18 @@ namespace toml
/// 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)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const time&);
#endif
/// \brief A timezone offset.
struct TOML_TRIVIAL_ABI time_offset final
{
@ -274,13 +284,18 @@ namespace toml
/// -01:30
/// -02:30
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time_offset& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
#endif
#if TOML_ABI_NAMESPACES
#ifdef TOML_OPTIONAL_TYPE
inline namespace abi_custopt {
@ -406,11 +421,16 @@ namespace toml
/// 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)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date_time& rhs)
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
#endif
}

View File

@ -10,146 +10,14 @@
namespace toml::impl
{
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
[[nodiscard]] TOML_API
toml::string default_formatter_make_key_segment(const toml::string& str) noexcept;
[[nodiscard]]
inline toml::string default_formatter_make_key_segment(const toml::string& str) noexcept
{
if (str.empty())
return TOML_STRING_PREFIX("''"s);
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);
}
}
[[nodiscard]] TOML_API
size_t default_formatter_inline_columns(const node& node) noexcept;
if (requiresQuotes)
{
toml::string s;
s.reserve(str.length() + 2_sz);
s += TOML_STRING_PREFIX('"');
for (auto c : str)
{
if (c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
s.append(low_character_escape_table[c]);
else if (c == TOML_STRING_PREFIX('\x7F')) TOML_UNLIKELY
s.append(TOML_STRING_PREFIX("\\u007F"sv));
else if (c == TOML_STRING_PREFIX('"')) TOML_UNLIKELY
s.append(TOML_STRING_PREFIX("\\\""sv));
else
s += c;
}
s += TOML_STRING_PREFIX('"');
return s;
}
else
return str;
}
}
TOML_POP_WARNINGS
[[nodiscard]]
inline size_t default_formatter_inline_columns(const node& node) noexcept
{
return node.visit([](const auto& n) noexcept
-> size_t
{
if constexpr (is_table<decltype(n)>)
{
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; // + ", "
return weight;
}
else if constexpr (is_array<decltype(n)>)
{
if (n.empty())
return 2_sz; // "[]"
size_t weight = 3_sz; // "[ ]"
for (auto& elem : n)
weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
return weight;
}
else if constexpr (is_string<decltype(n)>)
{
return n.get().length() + 2_sz; // + ""
}
else if constexpr (is_number<decltype(n)>)
{
static constexpr auto digit_count = [](auto num) noexcept
-> size_t
{
using number_t = decltype(num);
size_t digits = 1_sz;
while (num >= number_t{ 10 })
{
num /= number_t{ 10 };
digits++;
}
return digits;
};
if constexpr (is_integer<decltype(n)>)
{
auto v = n.get();
if (!v)
return 1_sz;
size_t weight = {};
if (v < 0)
{
weight += 1;
v *= -1;
}
return weight + digit_count(v);
}
else if constexpr (is_floating_point<decltype(n)>)
{
auto v = n.get();
if (v == 0.0)
return 3_sz;
size_t weight = 2_sz; // ".0"
if (v < 0.0)
{
weight += 1;
v *= -1.0;
}
return weight + digit_count(v);
}
}
else if constexpr (is_boolean<decltype(n)>)
{
return 5_sz;
}
else if constexpr (is_date<decltype(n)> || is_time<decltype(n)>)
{
return 10_sz;
}
else if constexpr (is_date_time<decltype(n)>)
{
return 30_sz;
}
TOML_UNREACHABLE;
});
}
[[nodiscard]]
inline bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias = 0) noexcept
{
return (default_formatter_inline_columns(node) + starting_column_bias) > 120_sz;
}
[[nodiscard]] TOML_API
bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias = 0) noexcept;
}
@ -188,12 +56,12 @@ namespace toml
/// foo = "bar"
/// \eout
///
/// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size.
template <typename CHAR = char>
class default_formatter final : impl::formatter<CHAR>
/// \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:
using base = impl::formatter<CHAR>;
using base = impl::formatter<Char>;
std::vector<toml::string> key_path;
void print_key_segment(const toml::string& str)
@ -459,12 +327,16 @@ namespace toml
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&);
};
#if !TOML_ALL_INLINE
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>;
template <typename CHAR>
inline void default_formatter<CHAR>::print_inline(const toml::table& tbl)
template <typename Char>
inline void default_formatter<Char>::print_inline(const toml::table& tbl)
{
if (tbl.empty())
impl::print_to_stream("{}"sv, base::stream());
@ -499,7 +371,8 @@ namespace toml
/// \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)
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>& rhs)
{
rhs.attach(lhs);
rhs.key_path.clear();
@ -510,21 +383,31 @@ namespace toml
/// \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)
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>&& rhs)
{
return lhs << rhs; //as lvalue
}
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const table& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const table& rhs)
{
return lhs << default_formatter<CHAR>{ rhs };
return lhs << default_formatter<Char>{ rhs };
}
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const array& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const array& rhs)
{
return lhs << default_formatter<CHAR>{ rhs };
return lhs << default_formatter<Char>{ rhs };
}
#if !TOML_ALL_INLINE
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&);
#endif
}

View File

@ -0,0 +1,156 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
#pragma once
#include "toml_default_formatter.h"
#if !defined(TOML_IMPLEMENTATION) || !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
namespace toml::impl
{
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
TOML_API
TOML_FUNC_EXTERNAL_LINKAGE
toml::string default_formatter_make_key_segment(const toml::string& str) noexcept
{
if (str.empty())
return TOML_STRING_PREFIX("''"s);
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)
{
toml::string s;
s.reserve(str.length() + 2_sz);
s += TOML_STRING_PREFIX('"');
for (auto c : str)
{
if (c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
s.append(low_character_escape_table[c]);
else if (c == TOML_STRING_PREFIX('\x7F')) TOML_UNLIKELY
s.append(TOML_STRING_PREFIX("\\u007F"sv));
else if (c == TOML_STRING_PREFIX('"')) TOML_UNLIKELY
s.append(TOML_STRING_PREFIX("\\\""sv));
else
s += c;
}
s += TOML_STRING_PREFIX('"');
return s;
}
else
return str;
}
}
TOML_POP_WARNINGS
TOML_API
TOML_FUNC_EXTERNAL_LINKAGE
size_t default_formatter_inline_columns(const node& node) noexcept
{
return node.visit([](const auto& n) noexcept
-> size_t
{
if constexpr (is_table<decltype(n)>)
{
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; // + ", "
return weight;
}
else if constexpr (is_array<decltype(n)>)
{
if (n.empty())
return 2_sz; // "[]"
size_t weight = 3_sz; // "[ ]"
for (auto& elem : n)
weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
return weight;
}
else if constexpr (is_string<decltype(n)>)
{
return n.get().length() + 2_sz; // + ""
}
else if constexpr (is_number<decltype(n)>)
{
static constexpr auto digit_count = [](auto num) noexcept
-> size_t
{
using number_t = decltype(num);
size_t digits = 1_sz;
while (num >= number_t{ 10 })
{
num /= number_t{ 10 };
digits++;
}
return digits;
};
if constexpr (is_integer<decltype(n)>)
{
auto v = n.get();
if (!v)
return 1_sz;
size_t weight = {};
if (v < 0)
{
weight += 1;
v *= -1;
}
return weight + digit_count(v);
}
else if constexpr (is_floating_point<decltype(n)>)
{
auto v = n.get();
if (v == 0.0)
return 3_sz;
size_t weight = 2_sz; // ".0"
if (v < 0.0)
{
weight += 1;
v *= -1.0;
}
return weight + digit_count(v);
}
}
else if constexpr (is_boolean<decltype(n)>)
{
return 5_sz;
}
else if constexpr (is_date<decltype(n)> || is_time<decltype(n)>)
{
return 10_sz;
}
else if constexpr (is_date_time<decltype(n)>)
{
return 30_sz;
}
TOML_UNREACHABLE;
});
}
TOML_API
TOML_FUNC_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) > 120_sz;
}
}

View File

@ -26,12 +26,12 @@ namespace toml
namespace toml::impl
{
template <typename CHAR = char>
class formatter
template <typename Char = char>
class TOML_API formatter
{
private:
const toml::node* source_;
std::basic_ostream<CHAR>* stream_ = nullptr;
std::basic_ostream<Char>* stream_ = nullptr;
format_flags flags_;
int8_t indent_;
bool naked_newline_;
@ -40,7 +40,7 @@ namespace toml::impl
[[nodiscard]] const toml::node& source() const noexcept { return *source_; }
[[nodiscard]] format_flags flags() const noexcept { return flags_; }
[[nodiscard]] std::basic_ostream<CHAR>& stream() const noexcept { return *stream_; }
[[nodiscard]] std::basic_ostream<Char>& stream() const noexcept { return *stream_; }
static constexpr size_t indent_columns = 4;
static constexpr toml::string_view indent_string = TOML_STRING_PREFIX(" "sv);
@ -51,7 +51,7 @@ namespace toml::impl
void clear_naked_newline() noexcept { naked_newline_ = false; }
void attach(std::basic_ostream<CHAR>& stream) noexcept
void attach(std::basic_ostream<Char>& stream) noexcept
{
indent_ = {};
naked_newline_ = true;
@ -146,5 +146,9 @@ namespace toml::impl
flags_{ flags }
{}
};
#if !TOML_ALL_INLINE
extern template class TOML_API formatter<char>;
#endif
}

View File

@ -3,12 +3,21 @@
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
#pragma once
#include "toml_value.h"
#include "toml_node_view.h"
#include "toml_common.h"
#if !defined(TOML_IMPLEMENTATION) || !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
#if !TOML_ALL_INLINE
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include <ostream>
TOML_POP_WARNINGS
#include "toml_node_view.h"
#include "toml_default_formatter.h"
#include "toml_json_formatter.h"
namespace toml
{
// value<>
@ -24,34 +33,44 @@ namespace toml
template class TOML_API node_view<node>;
template class TOML_API node_view<const node>;
// table and array iterators
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
// formatters
namespace impl
{
template struct table_proxy_pair<true>;
template struct table_proxy_pair<false>;
template class table_iterator<true>;
template class table_iterator<false>;
template class array_iterator<true>;
template class array_iterator<false>;
template class TOML_API formatter<char>;
}
template class TOML_API default_formatter<char>;
template class TOML_API json_formatter<char>;
// various ostream operators
template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
template TOML_API std::ostream& operator << (std::ostream&, const date&);
template TOML_API std::ostream& operator << (std::ostream&, const time&);
template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::string>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&);
template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&&);
template TOML_API std::ostream& operator << (std::ostream&, const table&);
template TOML_API std::ostream& operator << (std::ostream&, const array&);
template TOML_API std::ostream& operator << (std::ostream&, const node_view<node>&);
template TOML_API std::ostream& operator << (std::ostream&, const node_view<const node>&);
template TOML_API std::ostream& operator << (std::ostream&, node_type);
namespace impl
{
template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
}
#endif
}
// unique_ptrs to various things
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
namespace std
{
template class unique_ptr<toml::node>;
template class unique_ptr<toml::table>;
template class unique_ptr<toml::array>;
template class unique_ptr<toml::value<toml::string>>;
template class unique_ptr<toml::value<int64_t>>;
template class unique_ptr<toml::value<double>>;
template class unique_ptr<toml::value<bool>>;
template class unique_ptr<toml::value<toml::date>>;
template class unique_ptr<toml::value<toml::time>>;
template class unique_ptr<toml::value<toml::date_time>>;
}
#endif
#endif // !TOML_ALL_INLINE

View File

@ -43,12 +43,12 @@ namespace toml
/// }
/// \eout
///
/// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size.
template <typename CHAR = char>
class json_formatter final : impl::formatter<CHAR>
/// \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>
{
private:
using base = impl::formatter<CHAR>;
using base = impl::formatter<Char>;
inline void print(const toml::table& tbl);
@ -112,13 +112,17 @@ namespace toml
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&);
};
#if !TOML_ALL_INLINE
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>;
template <typename CHAR>
inline void json_formatter<CHAR>::print(const toml::table& tbl)
template <typename Char>
inline void json_formatter<Char>::print(const toml::table& tbl)
{
if (tbl.empty())
impl::print_to_stream("{}"sv, base::stream());
@ -158,7 +162,8 @@ namespace toml
/// \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)
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>& rhs)
{
rhs.attach(lhs);
rhs.print();
@ -168,9 +173,15 @@ namespace toml
/// \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)
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>&& rhs)
{
return lhs << rhs; //as lvalue
}
#if !TOML_ALL_INLINE
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
}

View File

@ -263,57 +263,57 @@ namespace toml
private:
template <typename FUNC, typename N, typename T>
static constexpr bool can_visit = std::is_invocable_v<FUNC, ref_cast_type<N, T>>;
template <typename Func, typename N, typename T>
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
template <typename FUNC, typename N>
template <typename Func, typename N>
static constexpr bool can_visit_any =
can_visit<FUNC, N, table>
|| can_visit<FUNC, N, array>
|| can_visit<FUNC, N, string>
|| can_visit<FUNC, N, int64_t>
|| can_visit<FUNC, N, double>
|| can_visit<FUNC, N, bool>
|| can_visit<FUNC, N, date>
|| can_visit<FUNC, N, time>
|| can_visit<FUNC, N, date_time>;
can_visit<Func, N, table>
|| can_visit<Func, N, array>
|| can_visit<Func, N, string>
|| can_visit<Func, N, int64_t>
|| can_visit<Func, N, double>
|| can_visit<Func, N, bool>
|| can_visit<Func, N, date>
|| can_visit<Func, N, time>
|| can_visit<Func, N, date_time>;
template <typename FUNC, typename N>
template <typename Func, typename N>
static constexpr bool can_visit_all =
can_visit<FUNC, N, table>
&& can_visit<FUNC, N, array>
&& can_visit<FUNC, N, string>
&& can_visit<FUNC, N, int64_t>
&& can_visit<FUNC, N, double>
&& can_visit<FUNC, N, bool>
&& can_visit<FUNC, N, date>
&& can_visit<FUNC, N, time>
&& can_visit<FUNC, N, date_time>;
can_visit<Func, N, table>
&& can_visit<Func, N, array>
&& can_visit<Func, N, string>
&& can_visit<Func, N, int64_t>
&& can_visit<Func, N, double>
&& can_visit<Func, N, bool>
&& can_visit<Func, N, date>
&& can_visit<Func, N, time>
&& can_visit<Func, N, date_time>;
template <typename FUNC, typename N, typename T>
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>>;
!can_visit<Func, N, T>
|| std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
template <typename FUNC, typename N>
template <typename Func, typename N>
static constexpr bool visit_is_nothrow =
visit_is_nothrow_one<FUNC, N, table>
&& visit_is_nothrow_one<FUNC, N, array>
&& visit_is_nothrow_one<FUNC, N, string>
&& visit_is_nothrow_one<FUNC, N, int64_t>
&& visit_is_nothrow_one<FUNC, N, double>
&& visit_is_nothrow_one<FUNC, N, bool>
&& visit_is_nothrow_one<FUNC, N, date>
&& visit_is_nothrow_one<FUNC, N, time>
&& visit_is_nothrow_one<FUNC, N, date_time>;
visit_is_nothrow_one<Func, N, table>
&& visit_is_nothrow_one<Func, N, array>
&& visit_is_nothrow_one<Func, N, string>
&& visit_is_nothrow_one<Func, N, int64_t>
&& visit_is_nothrow_one<Func, N, double>
&& visit_is_nothrow_one<Func, N, bool>
&& visit_is_nothrow_one<Func, N, date>
&& visit_is_nothrow_one<Func, N, time>
&& visit_is_nothrow_one<Func, N, date_time>;
template <typename FUNC, typename N, typename T, bool = can_visit<FUNC, N, T>>
template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
struct visit_return_type final
{
using type = decltype(std::declval<FUNC>()(std::declval<ref_cast_type<N, T>>()));
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
};
template <typename FUNC, typename N, typename T>
struct visit_return_type<FUNC, N, T, false> final
template <typename Func, typename N, typename T>
struct visit_return_type<Func, N, T, false> final
{
using type = void;
};
@ -325,79 +325,79 @@ namespace toml
//# (otherwise I'd have to implement them thrice)
//# ((propagation in C++: a modern horror story))
template <typename N, typename FUNC>
static decltype(auto) do_visit(N&& n, FUNC&& visitor)
noexcept(visit_is_nothrow<FUNC&&, N&&>)
template <typename N, typename Func>
static decltype(auto) do_visit(N&& n, Func&& visitor)
noexcept(visit_is_nothrow<Func&&, N&&>)
{
static_assert(
can_visit_any<FUNC&&, N&&>,
can_visit_any<Func&&, N&&>,
"Visitors must be invocable for at least one of the toml::node specializations"
);
switch (n.type())
{
case node_type::table:
if constexpr (can_visit<FUNC&&, N&&, table>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<table>());
if constexpr (can_visit<Func&&, N&&, table>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<table>());
break;
case node_type::array:
if constexpr (can_visit<FUNC&&, N&&, array>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<array>());
if constexpr (can_visit<Func&&, N&&, array>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<array>());
break;
case node_type::string:
if constexpr (can_visit<FUNC&&, N&&, string>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<string>());
if constexpr (can_visit<Func&&, N&&, string>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<string>());
break;
case node_type::integer:
if constexpr (can_visit<FUNC&&, N&&, int64_t>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<int64_t>());
if constexpr (can_visit<Func&&, N&&, int64_t>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<int64_t>());
break;
case node_type::floating_point:
if constexpr (can_visit<FUNC&&, N&&, double>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<double>());
if constexpr (can_visit<Func&&, N&&, double>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<double>());
break;
case node_type::boolean:
if constexpr (can_visit<FUNC&&, N&&, bool>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<bool>());
if constexpr (can_visit<Func&&, N&&, bool>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<bool>());
break;
case node_type::date:
if constexpr (can_visit<FUNC&&, N&&, date>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<date>());
if constexpr (can_visit<Func&&, N&&, date>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date>());
break;
case node_type::time:
if constexpr (can_visit<FUNC&&, N&&, time>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<time>());
if constexpr (can_visit<Func&&, N&&, time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<time>());
break;
case node_type::date_time:
if constexpr (can_visit<FUNC&&, N&&, date_time>)
return std::forward<FUNC>(visitor)(std::forward<N>(n).template ref_cast<date_time>());
if constexpr (can_visit<Func&&, N&&, date_time>)
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date_time>());
break;
TOML_NO_DEFAULT_CASE;
}
if constexpr (can_visit_all<FUNC&&, N&&>)
if constexpr (can_visit_all<Func&&, N&&>)
TOML_UNREACHABLE;
else
{
using return_type =
nonvoid<typename visit_return_type<FUNC&&, N&&, table>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, array>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, string>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, int64_t>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, double>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, bool>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, date>::type,
nonvoid<typename visit_return_type<FUNC&&, N&&, time>::type,
typename visit_return_type<FUNC&&, N&&, date_time>::type
nonvoid<typename visit_return_type<Func&&, N&&, table>::type,
nonvoid<typename visit_return_type<Func&&, N&&, array>::type,
nonvoid<typename visit_return_type<Func&&, N&&, string>::type,
nonvoid<typename visit_return_type<Func&&, N&&, int64_t>::type,
nonvoid<typename visit_return_type<Func&&, N&&, double>::type,
nonvoid<typename visit_return_type<Func&&, N&&, bool>::type,
nonvoid<typename visit_return_type<Func&&, N&&, date>::type,
nonvoid<typename visit_return_type<Func&&, N&&, time>::type,
typename visit_return_type<Func&&, N&&, date_time>::type
>>>>>>>>;
if constexpr (!std::is_void_v<return_type>)
@ -451,7 +451,7 @@ namespace toml
///
/// \ecpp
///
/// \tparam FUNC A callable type invocable with one or more of the
/// \tparam Func A callable type invocable with one or more of the
/// toml++ node types.
///
/// \param visitor The visitor object.
@ -460,22 +460,22 @@ namespace toml
/// Can be void. Non-exhaustive visitors must return a default-constructible type.
///
/// \see https://en.wikipedia.org/wiki/Visitor_pattern
template <typename FUNC>
decltype(auto) visit(FUNC&& visitor) & noexcept(visit_is_nothrow<FUNC&&, node&>)
template <typename Func>
decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>)
{
return do_visit(*this, std::forward<FUNC>(visitor));
return do_visit(*this, std::forward<Func>(visitor));
}
template <typename FUNC>
decltype(auto) visit(FUNC&& visitor) && noexcept(visit_is_nothrow<FUNC&&, node&&>)
template <typename Func>
decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>)
{
return do_visit(std::move(*this), std::forward<FUNC>(visitor));
return do_visit(std::move(*this), std::forward<Func>(visitor));
}
template <typename FUNC>
decltype(auto) visit(FUNC&& visitor) const& noexcept(visit_is_nothrow<FUNC&&, const node&>)
template <typename Func>
decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>)
{
return do_visit(*this, std::forward<FUNC>(visitor));
return do_visit(*this, std::forward<Func>(visitor));
}
/// \brief Gets a raw reference to a value node's underlying data.
@ -518,10 +518,3 @@ namespace toml
}
};
}
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
namespace std
{
extern template class unique_ptr<toml::node>;
}
#endif

View File

@ -9,8 +9,8 @@
namespace toml
{
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<T>&);
template <typename Char, typename T>
inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<T>&);
/// \brief A view of a node.
///
@ -72,9 +72,9 @@ namespace toml
: node_{ node }
{}
template <typename FUNC>
template <typename Func>
static constexpr bool visit_is_nothrow
= noexcept(std::declval<viewed_type*>()->visit(std::declval<FUNC&&>()));
= noexcept(std::declval<viewed_type*>()->visit(std::declval<Func&&>()));
public:
@ -202,13 +202,13 @@ namespace toml
/// \remarks Has no effect if the view does not reference a node.
///
/// \see node::visit()
template <typename FUNC>
decltype(auto) visit(FUNC&& visitor) const
noexcept(visit_is_nothrow<FUNC&&>)
template <typename Func>
decltype(auto) visit(Func&& visitor) const
noexcept(visit_is_nothrow<Func&&>)
{
using return_type = decltype(node_->visit(std::forward<FUNC>(visitor)));
using return_type = decltype(node_->visit(std::forward<Func>(visitor)));
if (node_)
return node_->visit(std::forward<FUNC>(visitor));
return node_->visit(std::forward<Func>(visitor));
if constexpr (!std::is_void_v<return_type>)
return return_type{};
}
@ -350,18 +350,14 @@ namespace toml
return { nullptr };
}
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<U>&);
template <typename Char, typename U>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<U>&);
};
#if !TOML_ALL_INLINE
extern template class TOML_API node_view<node>;
extern template class TOML_API node_view<const node>;
#endif
/// \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)
template <typename Char, typename T>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& os, const node_view<T>& nv)
{
if (nv.node_)
{
@ -372,5 +368,12 @@ namespace toml
}
return os;
}
#if !TOML_ALL_INLINE
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>&);
#endif
}

View File

@ -325,7 +325,7 @@ namespace toml
/// 3
/// \eout
///
/// \tparam CHAR The stream's underlying character type. Must be 1 byte in size.
/// \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)
@ -333,12 +333,12 @@ namespace toml
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
template <typename CHAR>
template <typename Char>
[[nodiscard]]
inline parse_result parse(std::basic_istream<CHAR>& doc, std::string_view source_path = {}) TOML_MAY_THROW
inline parse_result parse(std::basic_istream<Char>& doc, std::string_view source_path = {}) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
@ -360,18 +360,18 @@ namespace toml
/// 3
/// \eout
///
/// \tparam CHAR The stream's underlying character type. Must be 1 byte in size.
/// \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`.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
template <typename CHAR>
template <typename Char>
[[nodiscard]]
inline parse_result parse(std::basic_istream<CHAR>& doc, std::string&& source_path) TOML_MAY_THROW
inline parse_result parse(std::basic_istream<Char>& doc, std::string&& source_path) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
@ -389,7 +389,7 @@ namespace toml
/// }
/// \ecpp
///
/// \tparam CHAR The path's character type. Must be 1 byte in size.
/// \tparam Char The path's character type. Must be 1 byte in size.
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
@ -397,16 +397,16 @@ namespace toml
///
/// \attention You must `#include <fstream>` to use this function (toml++
/// does not transitively include it for you).
template <typename CHAR>
inline parse_result parse_file(std::basic_string_view<CHAR> file_path) TOML_MAY_THROW
template <typename Char>
inline parse_result parse_file(std::basic_string_view<Char> file_path) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The path's character type must be 1 byte in size."
);
auto str = std::string(reinterpret_cast<const char*>(file_path.data()), file_path.length());
auto ifs = std::basic_ifstream<CHAR>{ str };
auto ifs = std::basic_ifstream<Char>{ str };
return parse( ifs, std::move(str) );
}
@ -416,16 +416,16 @@ namespace toml
// until they're actually required, so only those users wanting to use parse_file()
// are burdened by the <fstream> overhead.
template <typename CHAR>
inline parse_result parse_file(const std::basic_string<CHAR>& file_path) TOML_MAY_THROW
template <typename Char>
inline parse_result parse_file(const std::basic_string<Char>& file_path) TOML_MAY_THROW
{
return parse_file(std::basic_string_view<CHAR>{ file_path });
return parse_file(std::basic_string_view<Char>{ file_path });
}
template <typename CHAR>
inline parse_result parse_file(const CHAR* file_path) TOML_MAY_THROW
template <typename Char>
inline parse_result parse_file(const Char* file_path) TOML_MAY_THROW
{
return parse_file(std::basic_string_view<CHAR>{ file_path });
return parse_file(std::basic_string_view<Char>{ file_path });
}
#if TOML_ABI_NAMESPACES
@ -438,7 +438,7 @@ namespace toml
/// without dragging in everything in the toml namespace: \cpp
///
/// #include <toml++/toml.h>
/// using namespace toml_literals;
/// using namespace toml::literals;
///
/// int main()
/// {

View File

@ -8,6 +8,13 @@
#error This is an implementation-only header.
#endif
#if !TOML_FLOATING_POINT_CHARCONV
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include <sstream>
TOML_POP_WARNINGS
#endif
namespace toml::impl
{
#if TOML_EXCEPTIONS
@ -136,7 +143,12 @@ namespace toml::impl
}
else if constexpr (std::is_floating_point_v<arg_t>)
{
#if TOML_USE_STREAMS_FOR_FLOATS
#if TOML_FLOATING_POINT_CHARCONV
{
const auto result = std::to_chars(ptr, buf + N, arg);
ptr = result.ptr;
}
#else
{
std::ostringstream ss;
ss.precision(std::numeric_limits<arg_t>::digits10 + 1);
@ -145,11 +157,6 @@ namespace toml::impl
std::memcpy(ptr, str.c_str(), str.length());
ptr += str.length();
}
#else
{
const auto result = std::to_chars(ptr, buf + N, arg);
ptr = result.ptr;
}
#endif
}
else if constexpr (std::is_integral_v<arg_t>)
@ -272,7 +279,7 @@ namespace toml::impl
if (!cp)
abort_with_error("Encountered EOF while consuming CRLF"sv);
if (*cp != U'\n')
else if (*cp != U'\n')
abort_with_error("Encountered unexpected character while consuming CRLF"sv);
}
advance(); // skip \n (or other single-character line ending)
@ -318,16 +325,22 @@ namespace toml::impl
if (consume_line_break())
return true;
if constexpr (TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/567
if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
{
if (*cp <= U'\u0008'
|| (*cp >= U'\u000A' && *cp <= U'\u001F')
|| *cp == U'\u007F')
// toml/issues/567 (disallow non-TAB control characters in comments)
if (is_nontab_control_character(*cp))
abort_with_error(
"Encountered unexpected character while parsing comment; control characters "
"U+0000-U+0008, U+000A-U+001F and U+007F are explicitly prohibited from appearing "
"other than TAB (U+0009) are explicitly prohibited from appearing "
"in comments."sv
);
// toml/pull/720 (disallow surrogates in comments)
else if (is_unicode_surrogate(*cp))
abort_with_error(
"Encountered unexpected character while parsing comment; unicode surrogates "
"(U+D800 to U+DFFF) are explicitly prohibited from appearing in comments."sv
);
}
advance();
@ -391,7 +404,7 @@ namespace toml::impl
return i;
}
template <bool MULTI_LINE>
template <bool MultiLine>
[[nodiscard]]
TOML_NEVER_INLINE
string parse_basic_string() TOML_MAY_THROW
@ -405,7 +418,7 @@ namespace toml::impl
if (!cp)
abort_with_error(
"Encountered EOF while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
node_type::string
);
};
@ -424,7 +437,7 @@ namespace toml::impl
escaped = false;
// handle 'line ending slashes' in multi-line mode
if constexpr (MULTI_LINE)
if constexpr (MultiLine)
{
if (is_line_break(*cp))
{
@ -447,39 +460,20 @@ namespace toml::impl
case U'f': str += TOML_STRING_PREFIX('\f'); break;
case U'n': str += TOML_STRING_PREFIX('\n'); break;
case U'r': str += TOML_STRING_PREFIX('\r'); break;
#if 0
case U's':
{
if constexpr (!TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/622
{
abort_with_error("Escape sequence '\\s' (Space, U+0020) is not supported "
"in TOML 0.5.0 and earlier."sv
);
break;
}
else
{
str += TOML_STRING_PREFIX(' ');
break;
}
}
#endif
case U't': str += TOML_STRING_PREFIX('\t'); break;
case U'"': str += TOML_STRING_PREFIX('"'); break;
case U'\\': str += TOML_STRING_PREFIX('\\'); break;
// unicode scalar sequences
case U'x':
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
[[fallthrough]];
#else
if constexpr (!TOML_LANG_UNRELEASED) // toml/pull/709 (\xHH unicode scalar sequences)
{
abort_with_error("Escape sequence '\\x' is not supported "
"in TOML 0.5.0 and earlier."sv
"in TOML 1.0.0 and earlier."sv
);
break;
#endif
}
[[fallthrough]];
case U'u': [[fallthrough]];
case U'U':
{
@ -491,12 +485,15 @@ namespace toml::impl
TOML_ERROR_CHECK({});
if (!is_hexadecimal_digit(*cp))
{
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; expected hex digit, saw '\\"sv, *cp, "'"sv
);
break;
}
sequence_value += place_value * (
*cp >= U'A'
? 10u + static_cast<uint32_t>(*cp - (*cp >= U'a' ? U'a' : U'A'))
@ -507,14 +504,21 @@ namespace toml::impl
TOML_ERROR_CHECK({});
}
if ((sequence_value > 0xD7FFu && sequence_value < 0xE000u) || sequence_value > 0x10FFFFu)
if (is_unicode_surrogate(sequence_value))
abort_with_error(
"Encountered unknown unicode scalar sequence while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
node_type::string
"Encountered illegal unicode scalar sequence while parsing "sv,
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited."sv
);
if (sequence_value <= 0x7Fu) //ascii
else if (sequence_value > 0x10FFFFu)
abort_with_error(
"Encountered illegal unicode scalar sequence while parsing "sv,
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; scalar values greater than U+10FFFF are invalid."sv
);
else if (sequence_value <= 0x7Fu) //ascii
str += static_cast<string_char>(sequence_value & 0x7Fu);
else if (sequence_value <= 0x7FFu)
{
@ -541,7 +545,7 @@ namespace toml::impl
default:
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; unknown escape sequence '\\"sv, *cp, "'"sv
);
@ -552,7 +556,7 @@ namespace toml::impl
// handle closing delimiters
if (*cp == U'"')
{
if constexpr (MULTI_LINE)
if constexpr (MultiLine)
{
advance();
eof_check();
@ -607,7 +611,7 @@ namespace toml::impl
}
// handle line endings in multi-line mode
if constexpr (MULTI_LINE)
if constexpr (MultiLine)
{
if (is_line_break(*cp))
{
@ -619,18 +623,31 @@ namespace toml::impl
}
}
// handle illegal characters
if (*cp <= U'\u0008'
|| (*cp >= U'\u000A' && *cp <= U'\u001F')
|| *cp == U'\u007F')
// handle control characters
if (is_nontab_control_character(*cp))
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; control characters must be escaped with back-slashes."sv
"; unescaped control characters other than TAB (U+0009) are explicitly "
"prohibited from appearing in strings."sv
);
if constexpr (MULTI_LINE)
// handle surrogates in strings (1.0.0 and later)
if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
{
if (is_unicode_surrogate(*cp))
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MultiLine ? "multi-line "sv : ""sv),
node_type::string,
"; unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly "
"prohibited from appearing in strings."sv
);
}
TOML_ERROR_CHECK({});
if constexpr (MultiLine)
{
if (!skipping_whitespace || !is_whitespace(*cp))
{
@ -648,14 +665,14 @@ namespace toml::impl
abort_with_error(
"Encountered EOF while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
node_type::string
);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
template <bool MULTI_LINE>
template <bool MultiLine>
[[nodiscard]]
TOML_NEVER_INLINE
string parse_literal_string() TOML_MAY_THROW
@ -669,7 +686,7 @@ namespace toml::impl
if (!cp)
abort_with_error(
"Encountered EOF while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
"literal "sv, node_type::string
);
};
@ -686,7 +703,7 @@ namespace toml::impl
// handle closing delimiters
if (*cp == U'\'')
{
if constexpr (MULTI_LINE)
if constexpr (MultiLine)
{
advance();
eof_check();
@ -720,7 +737,7 @@ namespace toml::impl
}
// handle line endings in multi-line mode
if constexpr (MULTI_LINE)
if constexpr (MultiLine)
{
if (is_line_break(*cp))
{
@ -731,24 +748,37 @@ namespace toml::impl
}
}
// handle illegal characters
if (*cp <= U'\u0008'
|| (*cp >= U'\u000A' && *cp <= U'\u001F')
|| *cp == U'\u007F')
// handle control characters
if (is_nontab_control_character(*cp))
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
"literal "sv, node_type::string,
"; control characters may not appear in literal strings"sv
"; control characters other than TAB (U+0009) are explicitly prohibited from appearing "
"in literal strings."sv
);
// handle surrogates in strings (1.0.0 and later)
if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
{
if (is_unicode_surrogate(*cp))
abort_with_error(
"Encountered unexpected character while parsing "sv,
(MultiLine ? "multi-line "sv : ""sv),
"literal "sv, node_type::string,
"; unicode surrogates (U+D800 - U+DFFF) are explicitly "
"prohibited from appearing in literal strings."sv
);
}
TOML_ERROR_CHECK({});
str.append(cp->as_view());
advance();
TOML_ERROR_CHECK({});
}
abort_with_error("Encountered EOF while parsing "sv,
(MULTI_LINE ? "multi-line "sv : ""sv),
(MultiLine ? "multi-line "sv : ""sv),
"literal "sv, node_type::string
);
TOML_ERROR_CHECK({});
@ -767,7 +797,11 @@ namespace toml::impl
advance();
TOML_ERROR_CHECK({});
if (!cp)
{
abort_with_error("Encountered EOF while parsing "sv, node_type::string);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
const auto second = cp->value;
advance();
TOML_ERROR_CHECK({});
@ -779,12 +813,15 @@ namespace toml::impl
{
if (second == first)
return string{};
abort_with_error("Encountered EOF while parsing "sv, node_type::string);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
// if the first three characters are all the same string delimiter then
// it's a multi-line string.
if (first == second && first == third)
else if (first == second && first == third)
{
return first == U'\''
? parse_literal_string<true>()
@ -946,10 +983,13 @@ namespace toml::impl
if (*cp == U'_')
{
if (!prev || !is_decimal_digit(*prev))
{
abort_with_error(
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; underscores may only follow digits"sv
);
break;
}
prev = cp;
advance();
TOML_ERROR_CHECK({});
@ -963,7 +1003,7 @@ namespace toml::impl
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; decimal points may appear only once"sv
);
if (seen_exponent)
else if (seen_exponent)
abort_with_error(
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; decimal points may not appear after exponents"sv
@ -986,7 +1026,7 @@ namespace toml::impl
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; exponent signs must immediately follow 'e'"sv
);
if (seen_exponent_sign)
else if (seen_exponent_sign)
abort_with_error(
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; exponents signs may appear only once"sv
@ -997,19 +1037,20 @@ namespace toml::impl
abort_with_error("Encountered unexpected character while parsing "sv,
node_type::floating_point, "; expected decimal digit, saw '"sv, *cp, '\''
);
if (length == sizeof(chars))
else if (length == sizeof(chars))
abort_with_error(
"Error parsing "sv, node_type::floating_point,
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
);
TOML_ERROR_CHECK({});
chars[length++] = static_cast<char>(cp->bytes[0]);
prev = cp;
advance();
TOML_ERROR_CHECK({});
}
TOML_ERROR_CHECK({});
if (prev && *prev == U'_')
{
eof_check();
@ -1017,25 +1058,13 @@ namespace toml::impl
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; expected decimal digit, saw '"sv, *cp, '\''
);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
TOML_ERROR_CHECK({});
// convert to double
double result;
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::stringstream ss;
ss.write(chars, static_cast<std::streamsize>(length));
if ((ss >> result))
return result * sign;
else
abort_with_error(
"Error parsing "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
}
#else
#if TOML_FLOATING_POINT_CHARCONV
{
auto fc_result = std::from_chars(chars, chars + length, result);
switch (fc_result.ec)
@ -1065,12 +1094,24 @@ namespace toml::impl
);
}
}
#else
{
std::stringstream ss;
ss.write(chars, static_cast<std::streamsize>(length));
if ((ss >> result))
return result * sign;
else
abort_with_error(
"Error parsing "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
}
#endif
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
#if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
[[nodiscard]]
TOML_NEVER_INLINE
@ -1119,10 +1160,14 @@ namespace toml::impl
if (*cp == U'_')
{
if (!prev || !is_hexadecimal_digit(*prev))
{
abort_with_error(
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; underscores may only follow digits"sv
);
break;
}
prev = cp;
advance();
TOML_ERROR_CHECK({});
@ -1136,7 +1181,7 @@ namespace toml::impl
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; decimal points may appear only once"sv
);
if (seen_exponent)
else if (seen_exponent)
abort_with_error(
"Encountered unexpected character while parsing "sv, node_type::floating_point,
"; decimal points may not appear after exponents"sv
@ -1150,7 +1195,7 @@ namespace toml::impl
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; exponents may appear only once"sv
);
if (!seen_decimal)
else if (!seen_decimal)
abort_with_error(
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; exponents may not appear before decimal points"sv
@ -1164,36 +1209,35 @@ namespace toml::impl
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; exponent signs must immediately follow 'p'"sv
);
if (seen_exponent_sign)
else if (seen_exponent_sign)
abort_with_error(
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; exponents signs may appear only once"sv
);
seen_exponent_sign = true;
}
else
{
if (!seen_exponent && !is_hexadecimal_digit(*cp))
abort_with_error("Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; expected hexadecimal digit, saw '"sv, *cp, '\''
);
else if (seen_exponent && !is_decimal_digit(*cp))
abort_with_error("Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, " exponent; expected decimal digit, saw '"sv, *cp, '\''
);
}
if (length == sizeof(chars))
else if (!seen_exponent && !is_hexadecimal_digit(*cp))
abort_with_error("Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; expected hexadecimal digit, saw '"sv, *cp, '\''
);
else if (seen_exponent && !is_decimal_digit(*cp))
abort_with_error("Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, " exponent; expected decimal digit, saw '"sv, *cp, '\''
);
else if (length == sizeof(chars))
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
);
);
TOML_ERROR_CHECK({});
chars[length++] = static_cast<char>(cp->bytes[0]);
prev = cp;
advance();
TOML_ERROR_CHECK({});
}
TOML_ERROR_CHECK({});
if (prev && *prev == U'_')
{
eof_check();
@ -1207,33 +1251,14 @@ namespace toml::impl
"Encountered unexpected character while parsing hexadecimal "sv,
node_type::floating_point, "; expected hexadecimal digit, saw '"sv, *cp, '\''
);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
TOML_ERROR_CHECK({});
// convert to double
double result;
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::string str;
{
std::ostringstream ss;
ss.write("0x", 2_sz);
ss.write(chars, static_cast<std::streamsize>(length));
str = std::move(ss).str();
}
char* end = {};
result = std::strtod(str.c_str(), &end);
if (result == 0.0 && end == str.c_str())
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
else
return result;
}
#else
#if TOML_FLOATING_POINT_CHARCONV
{
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
@ -1263,12 +1288,32 @@ namespace toml::impl
);
}
}
#else
{
std::string str;
{
std::ostringstream ss;
ss.write("0x", 2_sz);
ss.write(chars, static_cast<std::streamsize>(length));
str = std::move(ss).str();
}
char* end = {};
result = std::strtod(str.c_str(), &end);
if (result == 0.0 && end == str.c_str())
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
else
return result;
}
#endif
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
#endif //TOML_LANG_HIGHER_THAN(0, 5, 0)
#endif // TOML_LANG_UNRELEASED
template <int base>
[[nodiscard]]
@ -1361,7 +1406,7 @@ namespace toml::impl
' ', node_type::integer, "; expected "sv, traits::qualifier,
" digit, saw '"sv, *cp, '\''
);
if (length == sizeof(chars))
else if (length == sizeof(chars))
abort_with_error(
"Error parsing "sv, traits::qualifier, ' ', node_type::integer,
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
@ -1632,16 +1677,15 @@ namespace toml::impl
static_cast<uint8_t>(minute),
};
if constexpr (!TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/671
// ':'
if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
{
// ':'
eof_check();
if (*cp != U':')
abort_with_error(
"Encountered unexpected character while parsing "sv, type,
"; expected ':', saw '"sv, *cp, '\''
);
advance();
}
else
{
@ -1657,11 +1701,8 @@ namespace toml::impl
TOML_ERROR_CHECK({});
if (!cp || *cp != U':')
return time;
// ':'
advance();
}
advance();
TOML_ERROR_CHECK({});
// "SS"
@ -1712,11 +1753,12 @@ namespace toml::impl
"; expected fractional digits, saw '"sv,
*cp, '\''
);
if (digit_count == max_fractional_digits && cp && is_decimal_digit(*cp))
else if (digit_count == max_fractional_digits && cp && is_decimal_digit(*cp))
abort_with_error(
"Error parsing "sv, type,
"Fractional component exceeds maximum precision of "sv, max_fractional_digits
);
TOML_ERROR_CHECK({});
uint32_t value = 0u;
uint32_t place = 1u;
@ -1884,12 +1926,11 @@ namespace toml::impl
else if (*cp == U'[')
{
val = parse_array();
if constexpr (!TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/665
if constexpr (!TOML_LANG_AT_LEAST(1, 0, 0)) // toml/issues/665 (heterogeneous arrays)
{
// arrays must be homogeneous in toml 0.5.0 and earlier
if (!val->ref_cast<array>().is_homogeneous())
TOML_ERROR(
"Arrays cannot contain values of different types in TOML 0.5.0 and earlier.",
"Arrays cannot contain values of different types before TOML 1.0.0.",
begin_pos,
reader.source_path()
);
@ -2075,16 +2116,16 @@ namespace toml::impl
{
if (chars[i] == U'p' || chars[i] == U'P')
{
#if !TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
#if TOML_LANG_UNRELEASED // toml/issues/562 - hexfloats
val = std::make_unique<value<double>>(parse_hex_float());
break;
#else
TOML_ERROR(
"Hexadecimal floating-point values are not supported "
"in TOML 0.5.0 and earlier.",
"in TOML 1.0.0 and earlier.",
begin_pos,
reader.source_path()
);
#else
val = std::make_unique<value<double>>(parse_hex_float());
break;
#endif
}
}
@ -2221,6 +2262,7 @@ namespace toml::impl
{
abort_with_error("Could not determine value type"sv);
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
val->source_ = { begin_pos, current_position(1), reader.source_path() };
@ -2247,15 +2289,15 @@ namespace toml::impl
abort_with_error("Encountered EOF while parsing key"sv);
// bare_key_segment
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
if (is_unicode_combining_mark(*cp))
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
else if (is_unicode_combining_mark(*cp))
abort_with_error(
"Encountered unexpected character while parsing key; expected bare key starting character "
"or string delimiter, saw combining mark '"sv, *cp, '\''
);
else
#endif
if (is_bare_key_start_character(*cp))
else if (is_bare_key_start_character(*cp))
key.segments.push_back(parse_bare_key_segment());
// "quoted key segment"
@ -2270,6 +2312,7 @@ namespace toml::impl
);
consume_leading_whitespace();
TOML_ERROR_CHECK({});
// eof or no more key to come
if (!cp)
@ -2325,6 +2368,7 @@ namespace toml::impl
"expected '=', saw '"sv, *cp, '\''
);
advance();
TOML_ERROR_CHECK({});
// skip past any whitespace that followed the '='
consume_leading_whitespace();
@ -2378,7 +2422,7 @@ namespace toml::impl
eof_check();
// sanity-check the key start
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
if (is_unicode_combining_mark(*cp))
abort_with_error(
"Encountered unexpected character while parsing table key; "
@ -2634,7 +2678,7 @@ namespace toml::impl
// bare_keys
// dotted.keys
// "quoted keys"
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
else if (is_unicode_combining_mark(*cp))
abort_with_error(
"Encountered unexpected character while parsing key; "
@ -2871,7 +2915,7 @@ namespace toml::impl
{
TOML_ERROR_CHECK({});
if constexpr (TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/516
if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
{
while (consume_leading_whitespace()
|| consume_line_break()
@ -2904,7 +2948,7 @@ namespace toml::impl
// closing '}'
else if (*cp == U'}')
{
if constexpr (!TOML_LANG_HIGHER_THAN(0, 5, 0)) // toml/issues/516
if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
{
if (prev == comma)
{
@ -2921,7 +2965,7 @@ namespace toml::impl
}
// key-value pair
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
else if (is_unicode_combining_mark(*cp))
{
abort_with_error(

View File

@ -12,63 +12,63 @@ namespace toml::impl
// - 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 lot of reinterpret_casting here, is any of it UB?"
// 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.
// - Strings in C++. Honestly.
template <typename CHAR1, typename CHAR2>
template <typename Char1, typename Char2>
TOML_ALWAYS_INLINE
void print_to_stream(std::basic_string_view<CHAR1> str, std::basic_ostream<CHAR2>& stream)
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()));
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>
template <typename Char1, typename Char2>
TOML_ALWAYS_INLINE
void print_to_stream(const std::basic_string<CHAR1>& str, std::basic_ostream<CHAR2>& stream)
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()));
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>
template <typename Char>
TOML_ALWAYS_INLINE
void print_to_stream(char character, std::basic_ostream<CHAR>& stream)
void print_to_stream(char character, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
stream.put(static_cast<CHAR>(character));
static_assert(sizeof(Char) == 1);
stream.put(static_cast<Char>(character));
}
template <typename CHAR>
template <typename Char>
TOML_GNU_ATTR(nonnull) TOML_ALWAYS_INLINE
void print_to_stream(const char* str, size_t len, std::basic_ostream<CHAR>& stream)
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));
static_assert(sizeof(Char) == 1);
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
}
#if defined(__cpp_lib_char8_t)
template <typename CHAR>
template <typename Char>
TOML_ALWAYS_INLINE
void print_to_stream(char8_t character, std::basic_ostream<CHAR>& stream)
void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
stream.put(static_cast<CHAR>(character));
static_assert(sizeof(Char) == 1);
stream.put(static_cast<Char>(character));
}
template <typename CHAR>
template <typename Char>
TOML_GNU_ATTR(nonnull) TOML_ALWAYS_INLINE
void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<CHAR>& stream)
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));
static_assert(sizeof(Char) == 1);
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
}
#endif
@ -85,11 +85,11 @@ namespace toml::impl
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)
template <typename T, typename Char>
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream)
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
@ -99,11 +99,11 @@ namespace toml::impl
}
#define TOML_P2S_OVERLOAD(type) \
template <typename CHAR> \
template <typename Char> \
TOML_ALWAYS_INLINE \
void print_to_stream(type val, std::basic_ostream<CHAR>& stream) \
void print_to_stream(type val, std::basic_ostream<Char>& stream) \
{ \
static_assert(sizeof(CHAR) == 1); \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream); \
}
@ -118,11 +118,12 @@ namespace toml::impl
#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)
template <typename T, typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
void print_floating_point_to_stream(T val, std::basic_ostream<Char>& stream, bool hexfloat = false)
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
@ -134,19 +135,7 @@ namespace toml::impl
return true;
};
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream ss;
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 (needs_decimal_point(str))
print_to_stream(".0"sv, stream);
}
#else
#if TOML_FLOATING_POINT_CHARCONV
{
char buf[charconv_buffer_length<T>];
const auto res = hexfloat
@ -154,18 +143,43 @@ namespace toml::impl
: 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 (needs_decimal_point(str))
if (!hexfloat && needs_decimal_point(str))
print_to_stream(".0"sv, stream);
}
#else
{
char buf[charconv_buffer_length<T> + 1_sz];
int len = -1;
if (hexfloat)
len = snprintf(buf, charconv_buffer_length<T> + 1_sz, "%a", static_cast<double>(val));
else
len = snprintf(
buf, charconv_buffer_length<T> + 1_sz, "%.*g",
std::numeric_limits<T>::digits10 + 1, static_cast<double>(val)
);
TOML_ASSERT(len > 0);
len = static_cast<int>(charconv_buffer_length<T>) < len
? static_cast<int>(charconv_buffer_length<T>)
: len;
const auto str = std::string_view{ buf, static_cast<size_t>(len) };
print_to_stream(str, stream);
if (!hexfloat && needs_decimal_point(str))
print_to_stream(".0"sv, stream);
}
#endif
}
#if !TOML_ALL_INLINE
extern template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
extern template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
#endif
#define TOML_P2S_OVERLOAD(type) \
template <typename CHAR> \
template <typename Char> \
TOML_ALWAYS_INLINE \
void print_to_stream(type val, std::basic_ostream<CHAR>& stream) \
void print_to_stream(type val, std::basic_ostream<Char>& stream) \
{ \
static_assert(sizeof(CHAR) == 1); \
static_assert(sizeof(Char) == 1); \
print_floating_point_to_stream(val, stream); \
}
@ -174,18 +188,18 @@ namespace toml::impl
#undef TOML_P2S_OVERLOAD
template <typename CHAR>
template <typename Char>
TOML_ALWAYS_INLINE
void print_to_stream(bool val, std::basic_ostream<CHAR>& stream)
void print_to_stream(bool val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
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)
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);
static_assert(sizeof(Char) == 1);
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);
@ -194,10 +208,10 @@ namespace toml::impl
print_to_stream(buf, static_cast<size_t>(res.ptr - buf), stream);
}
template <typename CHAR>
inline void print_to_stream(const toml::date& val, std::basic_ostream<CHAR>& stream)
template <typename Char>
inline void print_to_stream(const toml::date& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
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);
@ -205,10 +219,10 @@ namespace toml::impl
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)
template <typename Char>
inline void print_to_stream(const toml::time& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
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);
@ -228,10 +242,10 @@ namespace toml::impl
}
}
template <typename CHAR>
inline void print_to_stream(toml::time_offset val, std::basic_ostream<CHAR>& stream)
template <typename Char>
inline void print_to_stream(toml::time_offset val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
static_assert(sizeof(Char) == 1);
if (!val.minutes)
print_to_stream('Z', stream);
else
@ -257,10 +271,10 @@ namespace toml::impl
}
}
template <typename CHAR>
inline void print_to_stream(const toml::date_time& val, std::basic_ostream<CHAR>& stream)
template <typename Char>
inline void print_to_stream(const toml::date_time& val, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
static_assert(sizeof(Char) == 1);
print_to_stream(val.date, stream);
print_to_stream('T', stream);
print_to_stream(val.time, stream);
@ -271,10 +285,10 @@ namespace toml::impl
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
template <typename T, typename CHAR>
void print_to_stream_with_escapes(T && str, std::basic_ostream<CHAR>& stream)
template <typename T, typename Char>
void print_to_stream_with_escapes(T && str, std::basic_ostream<Char>& stream)
{
static_assert(sizeof(CHAR) == 1);
static_assert(sizeof(Char) == 1);
for (auto c : str)
{
if (c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
@ -311,16 +325,17 @@ namespace toml
/// 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.
/// \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>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_position& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_position& rhs)
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
impl::print_to_stream("line "sv, lhs);
@ -345,16 +360,17 @@ namespace toml
/// 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.
/// \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>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_region& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_region& rhs)
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
lhs << rhs.begin;
@ -386,13 +402,14 @@ namespace toml
/// (error occurred at line 1, column 13)
/// \eout
///
/// \tparam CHAR The output stream's underlying character type. Must be 1 byte in size.
/// \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>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const parse_error& rhs)
template <typename Char>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const parse_error& rhs)
{
impl::print_to_stream(rhs.description(), lhs);
impl::print_to_stream("\n\t(error occurred at "sv, lhs);
@ -400,5 +417,10 @@ namespace toml
impl::print_to_stream(")"sv, lhs);
return lhs;
}
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
extern template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
extern template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
#endif
}

View File

@ -7,28 +7,23 @@
namespace toml::impl
{
template <bool is_const>
template <bool IsConst>
struct table_proxy_pair final
{
using value_type = std::conditional_t<is_const, const node, node>;
using value_type = std::conditional_t<IsConst, const node, node>;
const string& key;
value_type& value;
};
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
extern template struct table_proxy_pair<true>;
extern template struct table_proxy_pair<false>;
#endif
template <bool is_const>
template <bool IsConst>
class table_iterator final
{
private:
friend class toml::table;
using raw_iterator = std::conditional_t<
is_const,
IsConst,
string_map<std::unique_ptr<node>>::const_iterator,
string_map<std::unique_ptr<node>>::iterator
>;
@ -47,7 +42,7 @@ namespace toml::impl
table_iterator() noexcept = default;
using reference = table_proxy_pair<is_const>;
using reference = table_proxy_pair<IsConst>;
using difference_type = ptrdiff_t;
table_iterator& operator++() noexcept // ++pre
@ -94,11 +89,6 @@ namespace toml::impl
}
};
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
extern template class table_iterator<true>;
extern template class table_iterator<false>;
#endif
struct table_init_pair final
{
string key;
@ -129,8 +119,8 @@ namespace toml
{
[[nodiscard]] TOML_API bool operator == (const table& lhs, const table& rhs) noexcept;
[[nodiscard]] TOML_API bool operator != (const table& lhs, const table& rhs) noexcept;
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const table&);
template <typename Char>
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
/// \brief A TOML table.
///
@ -368,17 +358,17 @@ namespace toml
/// { a = 1, b = 2, c = 3, d = 42 } //"a" already existed
/// \eout
///
/// \tparam ITER An InputIterator to a collection of key-value pairs.
/// \tparam Iter An InputIterator to a collection of key-value pairs.
/// \param first An iterator to the first value in the input collection.
/// \param last An iterator to one-past-the-last value in the input collection.
///
/// \remarks This function is morally equivalent to calling `insert(key, value)` for each
/// key-value pair covered by the iterator range, so any values with keys already found in the
/// table will not be replaced.
template <typename ITER, typename = std::enable_if_t<
!std::is_convertible_v<ITER&&, string_view>
template <typename Iter, typename = std::enable_if_t<
!std::is_convertible_v<Iter&&, string_view>
>>
void insert(ITER first, ITER last) noexcept
void insert(Iter first, Iter last) noexcept
{
if (first == last)
return;
@ -609,11 +599,11 @@ namespace toml
private:
template <typename MAP, typename KEY>
[[nodiscard]] static auto do_get(MAP& vals, const KEY& key) noexcept
template <typename Map, typename Key>
[[nodiscard]] static auto do_get(Map& vals, const Key& key) noexcept
{
using return_type = std::conditional_t<
std::is_const_v<MAP>,
std::is_const_v<Map>,
const node*,
node*
>;
@ -623,16 +613,16 @@ namespace toml
return return_type{};
}
template <typename T, typename MAP, typename KEY>
[[nodiscard]] static auto do_get_as(MAP& vals, const KEY& key) noexcept
template <typename T, typename Map, typename Key>
[[nodiscard]] static auto do_get_as(Map& vals, const Key& key) noexcept
{
const auto node = do_get(vals, key);
return node ? node->template as<T>() : nullptr;
}
template <typename MAP, typename KEY>
template <typename Map, typename Key>
[[nodiscard]] TOML_ALWAYS_INLINE
static bool do_contains(MAP& vals, const KEY& key) noexcept
static bool do_contains(Map& vals, const Key& key) noexcept
{
#if TOML_CPP >= 20
return vals.contains(key);
@ -737,14 +727,7 @@ namespace toml
/// \returns True if the tables did not contain the same keys and values.
friend bool operator != (const table& lhs, const table& rhs) noexcept;
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const table&);
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
};
}
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
namespace std
{
extern template class unique_ptr<toml::table>;
}
#endif

View File

@ -36,11 +36,11 @@ namespace toml::impl
return is_ascii_whitespace(codepoint) || is_unicode_whitespace(codepoint);
}
template <bool CR = true>
template <bool IncludeCarriageReturn = true>
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
{
constexpr auto low_range_end = CR ? U'\r' : U'\f';
constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end);
}
@ -56,11 +56,11 @@ namespace toml::impl
;
}
template <bool CR = true>
template <bool IncludeCarriageReturn = true>
[[nodiscard]]
constexpr bool is_line_break(char32_t codepoint) noexcept
{
return is_ascii_line_break<CR>(codepoint) || is_unicode_line_break(codepoint);
return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_unicode_line_break(codepoint);
}
[[nodiscard]] TOML_ALWAYS_INLINE
@ -110,7 +110,7 @@ namespace toml::impl
|| is_decimal_digit(codepoint)
|| codepoint == U'-'
|| codepoint == U'_'
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/644 & toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
|| codepoint == U'+'
|| is_unicode_letter(codepoint)
|| is_unicode_number(codepoint)
@ -122,7 +122,7 @@ namespace toml::impl
constexpr bool is_bare_key_character(char32_t codepoint) noexcept
{
return is_bare_key_start_character(codepoint)
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
|| is_unicode_combining_mark(codepoint)
#endif
;
@ -142,6 +142,20 @@ namespace toml::impl
;
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
{
return codepoint <= U'\u0008'
|| (codepoint >= U'\u000A' && codepoint <= U'\u001F')
|| codepoint == U'\u007F';
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
{
return codepoint >= 0xD800u && codepoint <= 0xDFFF;
}
struct utf8_decoder final
{
//# This decoder is based on the 'Flexible and Economical UTF-8 Decoder'
@ -206,17 +220,17 @@ namespace toml::impl
template <typename T>
class utf8_byte_stream;
template <typename CHAR>
class utf8_byte_stream<std::basic_string_view<CHAR>> final
template <typename Char>
class utf8_byte_stream<std::basic_string_view<Char>> final
{
static_assert(sizeof(CHAR) == 1_sz);
static_assert(sizeof(Char) == 1_sz);
private:
std::basic_string_view<CHAR> source;
std::basic_string_view<Char> source;
size_t position = {};
public:
explicit constexpr utf8_byte_stream(std::basic_string_view<CHAR> sv) noexcept
explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept
: source{ sv }
{
if (source.length() >= 3_sz
@ -249,16 +263,16 @@ namespace toml::impl
}
};
template <typename CHAR>
class utf8_byte_stream<std::basic_istream<CHAR>> final
template <typename Char>
class utf8_byte_stream<std::basic_istream<Char>> final
{
static_assert(sizeof(CHAR) == 1_sz);
static_assert(sizeof(Char) == 1_sz);
private:
std::basic_istream<CHAR>* source;
std::basic_istream<Char>* source;
public:
explicit utf8_byte_stream(std::basic_istream<CHAR>& stream)
explicit utf8_byte_stream(std::basic_istream<Char>& stream)
: source{ &stream }
{
if (*source)
@ -299,7 +313,7 @@ namespace toml::impl
optional<uint8_t> operator() ()
{
auto val = source->get();
if (val == std::basic_istream<CHAR>::traits_type::eof())
if (val == std::basic_istream<Char>::traits_type::eof())
return {};
return static_cast<uint8_t>(val);
}
@ -311,18 +325,18 @@ namespace toml::impl
string_char bytes[4];
source_position position;
template <typename CHAR = string_char>
template <typename Char = string_char>
[[nodiscard]] TOML_ALWAYS_INLINE
std::basic_string_view<CHAR> as_view() const noexcept
std::basic_string_view<Char> as_view() const noexcept
{
static_assert(
sizeof(CHAR) == 1,
sizeof(Char) == 1,
"The string view's underlying character type must be 1 byte in size."
);
return bytes[3]
? std::basic_string_view<CHAR>{ reinterpret_cast<const CHAR*>(bytes), 4_sz }
: std::basic_string_view<CHAR>{ reinterpret_cast<const CHAR*>(bytes) };
? std::basic_string_view<Char>{ reinterpret_cast<const Char*>(bytes), 4_sz }
: std::basic_string_view<Char>{ reinterpret_cast<const Char*>(bytes) };
}
[[nodiscard]]
@ -389,8 +403,8 @@ namespace toml::impl
public:
template <typename U, typename STR = std::string_view>
explicit utf8_reader(U && source, STR&& source_path = {})
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{ std::forward<U>(source) }
{
@ -399,7 +413,7 @@ namespace toml::impl
codepoints[1].position = { 1, 1 };
if (!source_path.empty())
source_path_ = std::make_shared<const std::string>(std::forward<STR>(source_path));
source_path_ = std::make_shared<const std::string>(std::forward<String>(source_path));
}
[[nodiscard]]
@ -504,17 +518,17 @@ namespace toml::impl
#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_view) -> 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_view) -> utf8_reader<std::basic_istream<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_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
template <typename CHAR>
utf8_reader(std::basic_istream<CHAR>&, std::string&&) -> utf8_reader<std::basic_istream<CHAR>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
#if !TOML_EXCEPTIONS
#undef TOML_ERROR_CHECK

View File

@ -7,7 +7,7 @@
#pragma once
#include "toml_common.h"
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last) \
TOML_ASSUME(codepoint >= first); \
@ -915,4 +915,4 @@ namespace toml::impl
#undef TOML_ASSUME_CODEPOINT_BETWEEN
#endif // TOML_LANG_HIGHER_THAN(0, 5, 0)
#endif // TOML_LANG_UNRELEASED

View File

@ -8,8 +8,8 @@
namespace toml
{
template <typename CHAR, typename T>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const value<T>&);
template <typename Char, typename T>
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const value<T>&);
/// \brief A TOML value.
///
@ -167,8 +167,8 @@ namespace toml
/// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<U>& rhs);
template <typename Char, typename U>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<U>& rhs);
/// \brief Value-assignment operator.
value& operator= (value_arg rhs) noexcept
@ -312,23 +312,7 @@ namespace toml
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
}
#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION
namespace std
{
extern template class unique_ptr<toml::value<toml::string>>;
extern template class unique_ptr<toml::value<int64_t>>;
extern template class unique_ptr<toml::value<double>>;
extern template class unique_ptr<toml::value<bool>>;
extern template class unique_ptr<toml::value<toml::date>>;
extern template class unique_ptr<toml::value<toml::time>>;
extern template class unique_ptr<toml::value<toml::date_time>>;
}
#endif
namespace toml
{
template <size_t N> value(const string_char(&)[N]) -> value<string>;
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
value(const string_char*) -> value<string>;
@ -358,8 +342,9 @@ namespace toml
#endif
/// \brief Prints the value out to a stream.
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<T>& rhs)
template <typename Char, typename T>
TOML_FUNC_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs)
{
// this is the same behaviour as default_formatter, but it's so simple that there's
// no need to spin up a new instance of it just for individual values.
@ -376,6 +361,16 @@ namespace toml
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::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 T>
inline optional<T> node::value() const noexcept
{

View File

@ -5,9 +5,9 @@
#pragma once
#define TOML_LIB_MAJOR 1
#define TOML_LIB_MINOR 0
#define TOML_LIB_PATCH 1
#define TOML_LIB_MINOR 1
#define TOML_LIB_PATCH 0
#define TOML_LANG_MAJOR 0
#define TOML_LANG_MINOR 5
#define TOML_LANG_MAJOR 1
#define TOML_LANG_MINOR 0
#define TOML_LANG_PATCH 0

View File

@ -1,7 +1,7 @@
project(
'tomlplusplus',
'cpp',
version : '1.0.1',
version : '1.1.0',
license : 'MIT',
default_options : [
'cpp_std=c++17',

View File

@ -457,12 +457,42 @@ class ModifiersFix2(ModifiersFixBase):
class IndexPageFix(object):
__badges = [
('C++', 'https://img.shields.io/badge/c%2B%2B-17%2C%2020-informational', 'https://en.cppreference.com/w/cpp/compiler_support'),
('TOML', 'https://img.shields.io/badge/TOML-v0.5.0-informational', 'https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md'),
('MIT License', 'https://img.shields.io/badge/license-MIT-blue.svg', 'https://github.com/marzer/tomlplusplus/blob/master/LICENSE'),
('Releases', 'https://img.shields.io/github/release/marzer/tomlplusplus.svg', 'https://github.com/marzer/tomlplusplus/releases'),
('Mentioned in Awesome C++', 'https://awesome.re/mentioned-badge.svg', 'https://github.com/fffaraz/awesome-cpp'),
('CircleCI', 'https://circleci.com/gh/marzer/tomlplusplus.svg?style=shield', 'https://circleci.com/gh/marzer/tomlplusplus')
(
'Releases',
'https://img.shields.io/github/v/release/marzer/tomlplusplus?style=flat-square',
'https://github.com/marzer/tomlplusplus/releases'
),
(
'C++17',
'badge-C++17.svg',
'https://en.cppreference.com/w/cpp/compiler_support'
),
(
'C++20',
'badge-C++20.svg',
'https://en.cppreference.com/w/cpp/compiler_support'
),
(
'TOML',
'badge-TOML.svg',
'https://github.com/toml-lang/toml/blob/master/README.md'
),
(
'MIT License',
'badge-license-MIT.svg',
'https://github.com/marzer/tomlplusplus/blob/master/LICENSE'
),
(
'CircleCI',
'https://img.shields.io/circleci/build/github/marzer/tomlplusplus'
+ '?label=circle%20ci&logo=circleci&logoColor=white&style=flat-square',
'https://circleci.com/gh/marzer/tomlplusplus'
),
(
'Mentioned in Awesome C++',
'badge-awesome.svg',
'https://github.com/fffaraz/awesome-cpp'
)
]
def __call__(self, file, doc):
@ -474,7 +504,7 @@ class IndexPageFix(object):
parent = doc.new_tag('div', class_='gh-badges', after=banner)
for (alt, src, href) in self.__badges:
anchor = doc.new_tag('a', parent=parent, href=href, target='_blank')
doc.new_tag('img', parent=anchor, src=src, alt='caption')
doc.new_tag('img', parent=anchor, src=src, alt=alt)
return True

View File

@ -133,8 +133,9 @@ file was assembled from a number of smaller files by a python script, and code c
against it directly. You should instead make your changes in the relevant source file(s). The file names of the files
that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file.''')
preamble.append('''
TOML language specification:
TOML language specifications:
Latest: https://github.com/toml-lang/toml/blob/master/README.md
v1.0.0: https://github.com/toml-lang/toml/blob/master/README.md
v0.5.0: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md''')
preamble.append(read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE')))

View File

@ -514,7 +514,7 @@ def emit_function(name, categories, file, codepoints):
def get_script_folder():
return path.dirname(path.realpath(sys.argv[0]))
return path.dirname(path.realpath(sys.argv[0]))
@ -589,7 +589,7 @@ def main():
#pragma once
#include "toml_common.h"
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/687
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last) \\
TOML_ASSUME(codepoint >= first); \\
@ -606,7 +606,7 @@ namespace toml::impl
#undef TOML_ASSUME_CODEPOINT_BETWEEN
#endif // TOML_LANG_HIGHER_THAN(0, 5, 0)
#endif // TOML_LANG_UNRELEASED
''', file=output_file, end='')
if __name__ == '__main__':

11
tests/impl_catch2.cpp Normal file
View File

@ -0,0 +1,11 @@
#define CATCH_CONFIG_RUNNER
#include "catch2.h"
int main(int argc, char* argv[])
{
#ifdef _WIN32
SetConsoleOutputCP(65001);
#endif
return Catch::Session().run(argc, argv);
}

42
tests/impl_toml.cpp Normal file
View File

@ -0,0 +1,42 @@
#ifdef TARTANLLAMA_OPTIONAL
#if __has_include(<tloptional/include/tl/optional.hpp>)
#include <tloptional/include/tl/optional.hpp>
#else
#error TartanLlama/optional is missing! You probably need to fetch submodules ("git submodule update --init extern/tloptional")
#endif
#define TOML_OPTIONAL_TYPE tl::optional
#endif
#include <ostream>
#if !defined(_MSC_VER) || !defined(_M_IX86)
#define TOML_ALL_INLINE 0
#define TOML_IMPLEMENTATION
#endif
#include "../include/toml++/toml.h"
namespace toml
{
using std::declval;
using std::is_same_v;
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&>);
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

@ -1,25 +0,0 @@
#ifdef TARTANLLAMA_OPTIONAL
#if __has_include(<tloptional/include/tl/optional.hpp>)
#include <tloptional/include/tl/optional.hpp>
#else
#error TartanLlama/optional is missing! You probably need to fetch submodules ("git submodule update --init extern/tloptional")
#endif
#define TOML_OPTIONAL_TYPE tl::optional
#endif
#if !defined(_MSC_VER) || !defined(_M_IX86)
#define TOML_ALL_INLINE 0
#define TOML_IMPLEMENTATION
#endif
#include "../include/toml++/toml.h"
#define CATCH_CONFIG_RUNNER
#include "catch2.h"
int main(int argc, char* argv[])
{
#ifdef _WIN32
SetConsoleOutputCP(65001);
#endif
return Catch::Session().run(argc, argv);
}

View File

@ -1,5 +1,6 @@
test_sources = [
'main.cpp',
'impl_toml.cpp',
'impl_catch2.cpp',
'parsing_arrays.cpp',
'parsing_booleans.cpp',
'parsing_comments.cpp',

View File

@ -91,8 +91,8 @@ string_array = [ "all", 'strings', """are the same""", '''type''' ]
}
);
// toml/issues/665 - heterogeneous arrays
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
// toml/issues/665 (heterogeneous arrays)
#if TOML_LANG_AT_LEAST(1, 0, 0)
parsing_should_succeed(S(R"(
# Mixed-type arrays are allowed

View File

@ -14,4 +14,95 @@ another = "# This is not a comment"
CHECK(tbl[S("another")] == S("# This is not a comment"sv));
}
);
parsing_should_succeed(S(R"(# this = "looks like a KVP but is commented out)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 0);
}
);
if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
{
// toml/issues/567 (disallow non-TAB control characters in comments)
// 00 - 08
parsing_should_fail(S("# \u0000"sv));
parsing_should_fail(S("# \u0001"sv));
parsing_should_fail(S("# \u0002"sv));
parsing_should_fail(S("# \u0003"sv));
parsing_should_fail(S("# \u0004"sv));
parsing_should_fail(S("# \u0005"sv));
parsing_should_fail(S("# \u0006"sv));
parsing_should_fail(S("# \u0007"sv));
parsing_should_fail(S("# \u0008"sv));
// skip tab and line breaks (real and otherwise)
// \u0009 is \t
// \u000A is \n
// \u000B is \v (vertical tab)
// \u000C is \f (form feed)
// \u000D is \r
// 0E - 1F
parsing_should_fail(S("# \u000E"sv));
parsing_should_fail(S("# \u000F"sv));
parsing_should_fail(S("# \u0010"sv));
parsing_should_fail(S("# \u0011"sv));
parsing_should_fail(S("# \u0012"sv));
parsing_should_fail(S("# \u0013"sv));
parsing_should_fail(S("# \u0014"sv));
parsing_should_fail(S("# \u0015"sv));
parsing_should_fail(S("# \u0016"sv));
parsing_should_fail(S("# \u0017"sv));
parsing_should_fail(S("# \u0018"sv));
parsing_should_fail(S("# \u0019"sv));
parsing_should_fail(S("# \u001A"sv));
parsing_should_fail(S("# \u001B"sv));
parsing_should_fail(S("# \u001C"sv));
parsing_should_fail(S("# \u001D"sv));
parsing_should_fail(S("# \u001E"sv));
parsing_should_fail(S("# \u001F"sv));
// 7F
parsing_should_fail(S("# \u007F"sv));
}
else
{
parsing_should_succeed(S(
"## 00 - 08"
"# \u0000 "
"# \u0001 "
"# \u0002 "
"# \u0003 "
"# \u0004 "
"# \u0005 "
"# \u0006 "
"# \u0007 "
"# \u0008 "
"## 0A - 1F"
"# \u000A "
"# \u000B "
"# \u000C "
"# \u000D "
"# \u000E "
"# \u000F "
"# \u0010 "
"# \u0011 "
"# \u0012 "
"# \u0013 "
"# \u0014 "
"# \u0015 "
"# \u0016 "
"# \u0017 "
"# \u0018 "
"# \u0019 "
"# \u001A "
"# \u001B "
"# \u001C "
"# \u001D "
"# \u001E "
"# \u001F "
"## 7F "
"# \u007F "sv
));
}
}

View File

@ -84,8 +84,8 @@ lt2 = 00:32:00.999999
parse_expected_value("1987-03-16 10:20:30.04Z"sv, val);
}
// toml/issues/671 - omitting seconds
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
// toml/issues/671 (allow omission of seconds)
#if TOML_LANG_UNRELEASED
parse_expected_value( "10:20"sv, toml::time{ 10, 20 } );
{

View File

@ -102,15 +102,15 @@ flt8 = 224_617.445_991_228
parse_expected_value( "6.02e+23"sv, 6.02e+23 );
parse_expected_value( "1.112_650_06e-17"sv, 1.11265006e-17 );
//toml/issues/562 - hexfloat literals
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
parse_expected_value(" 0x10.1p0"sv, 0x10.1p0 );
parse_expected_value(" 0x0.3p10"sv, 0x0.3p10 );
parse_expected_value(" 0x12.2P2"sv, 0x12.2P2 );
//toml/issues/562 (hexfloats)
#if TOML_LANG_UNRELEASED
parse_expected_value(" 0x10.1p0"sv, 0x10.1p0 );
parse_expected_value(" 0x0.3p10"sv, 0x0.3p10 );
parse_expected_value(" 0x12.2P2"sv, 0x12.2P2 );
#else
parsing_should_fail(S("val = 0x10.1p0"sv));
parsing_should_fail(S("val = 0x0.3p10"sv));
parsing_should_fail(S("val = 0x12.2P2"sv));
parsing_should_fail(S("val = 0x10.1p0"sv));
parsing_should_fail(S("val = 0x0.3p10"sv));
parsing_should_fail(S("val = 0x12.2P2"sv));
#endif
}

View File

@ -7,14 +7,16 @@ key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"
"" = "blank"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 4);
CHECK(tbl.size() == 5);
CHECK(tbl[S("key")] == S("value"sv));
CHECK(tbl[S("bare_key")] == S("value"sv));
CHECK(tbl[S("bare-key")] == S("value"sv));
CHECK(tbl[S("1234")] == S("value"sv));
CHECK(tbl[S("")] == S("blank"sv));
}
);
@ -26,6 +28,7 @@ bare-key = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"
'' = 'blank'
)"sv),
[](table&& tbl) noexcept
{
@ -34,6 +37,7 @@ bare-key = "value"
CHECK(tbl[S("ʎǝʞ")] == S("value"sv));
CHECK(tbl[S("key2")] == S("value"sv));
CHECK(tbl[S("quoted \"value\"")] == S("value"sv));
CHECK(tbl[S("")] == S("blank"sv));
}
);
@ -55,14 +59,16 @@ name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
3.14159 = "pi"
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 3);
CHECK(tbl.size() == 4);
CHECK(tbl[S("name")] == S("Orange"sv));
CHECK(tbl[S("physical")][S("color")] == S("orange"sv));
CHECK(tbl[S("physical")][S("shape")] == S("round"sv));
CHECK(tbl[S("site")][S("google.com")] == true);
CHECK(tbl[S("3")][S("14159")] == S("pi"sv));
}
);
@ -130,22 +136,21 @@ orange.color = "orange"
}
);
// allow + in bare keys - toml/issues/644
// allow unicode in bare keys - toml/issues/687
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
parsing_should_succeed(S(R"(
key+1 = 0
ʎǝʞ2 = 0
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 2);
CHECK(tbl[S("key+1")] == 0);
CHECK(tbl[S("ʎǝʞ2")] == 0);
}
);
// toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
#if TOML_LANG_UNRELEASED
parsing_should_succeed(S(R"(
key+1 = 0
ʎǝʞ2 = 0
)"sv),
[](table&& tbl) noexcept
{
CHECK(tbl.size() == 2);
CHECK(tbl[S("key+1")] == 0);
CHECK(tbl[S("ʎǝʞ2")] == 0);
}
);
#else
parsing_should_fail(R"(key+1 = 0)"sv);
parsing_should_fail(R"(ʎǝʞ2 = 0)"sv);
parsing_should_fail(R"(key+1 = 0)"sv);
parsing_should_fail(R"(ʎǝʞ2 = 0)"sv);
#endif
}

View File

@ -130,22 +130,13 @@ str = ''''That's still pointless', she said.'''
R"("\"\u03B1\u03B2\u03B3\"")"sv,
S("\"\u03B1\u03B2\u03B3\""sv));
// toml/issues/622 - escaping alias for spaces
#if 0 && TOML_LANG_HIGHER_THAN(0, 5, 0)
parse_expected_value(
R"("The\squick\sbrown\sfox\sjumps\sover\sthe\slazy\sdog")"sv,
S("The quick brown fox jumps over the lazy dog"sv));
// toml/pull/709 (\xHH unicode scalars)
#if TOML_LANG_UNRELEASED
parse_expected_value(
R"("\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\x11\xFF\xEE")"sv,
S("\u0000\u0010\u0020\u0030\u0040\u0050\u0060\u0070\u0080\u0090\u0011\u00FF\u00EE"sv));
#else
parsing_should_fail(R"(str = "The\squick\sbrown\sfox\sjumps\sover\sthe\slazy\sdog")"sv);
#endif
// toml/pull/709 - \xHH short-form unicode scalars
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
parse_expected_value(
R"("\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\x11\xFF\xEE")"sv,
S("\u0000\u0010\u0020\u0030\u0040\u0050\u0060\u0070\u0080\u0090\u0011\u00FF\u00EE"sv));
#else
parsing_should_fail(R"(str = "\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\x11\xFF\xEE")"sv);
parsing_should_fail(R"(str = "\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\x11\xFF\xEE")"sv);
#endif
//check 8-digit \U scalars with insufficient digits

View File

@ -227,9 +227,9 @@ test = { val1 = "foo", val2 = [
}
);
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
// toml/issues/516 (newlines/trailing commas in inline tables)
#if TOML_LANG_UNRELEASED
{
// toml/issues/516 - allow newlines and trailing commas in inline tables
parsing_should_succeed(S(R"(
name = {
first = "Tom",

View File

@ -1,7 +1,5 @@
#include "tests.h"
#if TESTS_MANUAL_INSTANTIATIONS
template void parse_expected_value(std::string_view, const int&) noexcept;
template void parse_expected_value(std::string_view, const unsigned int&) noexcept;
template void parse_expected_value(std::string_view, const bool&) noexcept;
@ -9,41 +7,10 @@ template void parse_expected_value(std::string_view, const float&) noexcept;
template void parse_expected_value(std::string_view, const double&) noexcept;
template void parse_expected_value(std::string_view, const toml::string_view&) noexcept;
namespace toml::impl
namespace std
{
template class formatter<char>;
template class unique_ptr<const Catch::IExceptionTranslator>;
}
namespace toml
{
template class default_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 value<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<date>&);
template std::ostream& operator<< (std::ostream&, const value<time>&);
template std::ostream& operator<< (std::ostream&, const value<date_time>&);
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);
template std::ostream& operator<< (std::ostream&, const source_region&);
template std::ostream& operator<< (std::ostream&, const source_position&);
template std::ostream& operator<< (std::ostream&, const parse_error&);
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&, default_formatter<char>&);
template std::ostream& operator<< (std::ostream&, default_formatter<char>&&);
}
template class std::unique_ptr<const Catch::IExceptionTranslator>;
namespace Catch
{
template struct StringMaker<node_view<node>>;
@ -57,34 +24,4 @@ namespace Catch
}
}
#endif // TESTS_MANUAL_INSTANTIATIONS
namespace toml
{
using std::declval;
using std::is_same_v;
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&>);
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

@ -30,8 +30,8 @@ using namespace Catch::literals;
#define S(str) TOML_STRING_PREFIX(str)
template <typename CHAR, typename FUNC>
inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func, std::string_view source_path = {}) noexcept
template <typename Char, typename Func = std::false_type>
inline void parsing_should_succeed(std::basic_string_view<Char> toml_str, Func&& func = {}, std::string_view source_path = {}) noexcept
{
INFO("String being parsed: '"sv << std::string_view( reinterpret_cast<const char*>(toml_str.data()), toml_str.length() ) << "'"sv)
@ -50,19 +50,27 @@ inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&&
return std::move(tabl);
};
static constexpr auto is_functor = !std::is_same_v<impl::remove_cvref_t<Func>, std::false_type>;
#if TOML_EXCEPTIONS
try
{
{
INFO("Parsing string directly"sv)
std::forward<FUNC>(func)(validate_table(toml::parse(toml_str, source_path), source_path));
if constexpr (is_functor)
std::forward<Func>(func)(validate_table(toml::parse(toml_str, source_path), source_path));
else
validate_table(toml::parse(toml_str, source_path), source_path);
}
{
INFO("Parsing from a string stream"sv)
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
std::basic_stringstream<Char, std::char_traits<Char>, std::allocator<Char>> ss;
ss.write(toml_str.data(), static_cast<std::streamsize>(toml_str.length()));
std::forward<FUNC>(func)(validate_table(toml::parse(ss, source_path), source_path));
if constexpr (is_functor)
std::forward<Func>(func)(validate_table(toml::parse(ss, source_path), source_path));
else
validate_table(toml::parse(ss, source_path), source_path);
}
}
catch (const parse_error& err)
@ -80,7 +88,12 @@ inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&&
INFO("Parsing string directly"sv)
parse_result result = toml::parse(toml_str, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
{
if constexpr (is_functor)
std::forward<Func>(func)(validate_table(std::move(result), source_path));
else
validate_table(std::move(result), source_path);
}
else
{
FAIL(
@ -88,17 +101,23 @@ inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&&
<< ", column "sv << result.error().source().begin.column
<< ":\n"sv << result.error().description()
);
return;
std::exit(-1);
TOML_UNREACHABLE;
}
}
{
INFO("Parsing from a string stream"sv)
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
std::basic_stringstream<Char, std::char_traits<Char>, std::allocator<Char>> ss;
ss.write(toml_str.data(), static_cast<std::streamsize>(toml_str.length()));
parse_result result = toml::parse(ss, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
{
if constexpr (is_functor)
std::forward<Func>(func)(validate_table(std::move(result), source_path));
else
validate_table(std::move(result), source_path);
}
else
{
FAIL(
@ -106,15 +125,16 @@ inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&&
<< ", column "sv << result.error().source().begin.column
<< ":\n"sv << result.error().description()
);
return;
std::exit(-1);
TOML_UNREACHABLE;
}
}
#endif
}
template <typename CHAR>
inline void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
template <typename Char>
inline void parsing_should_fail(std::basic_string_view<Char> toml_str) noexcept
{
INFO("String being parsed: '"sv << std::string_view(reinterpret_cast<const char*>(toml_str.data()), toml_str.length()) << "'"sv)
@ -145,7 +165,7 @@ inline void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
if (run_tests([=]() { (void)toml::parse(toml_str); }))
run_tests([=]()
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
std::basic_stringstream<Char, std::char_traits<Char>, std::allocator<Char>> ss;
ss.write(toml_str.data(), static_cast<std::streamsize>(toml_str.length()));
(void)toml::parse(ss);
});
@ -158,7 +178,8 @@ inline void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
if (result)
{
FAIL("Expected parsing failure"sv);
return false;
std::exit(-1);
TOML_UNREACHABLE;
}
else
{
@ -170,7 +191,7 @@ inline void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
if (run_tests([=]() noexcept { return toml::parse(toml_str); }))
run_tests([=]() noexcept
{
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
std::basic_stringstream<Char, std::char_traits<Char>, std::allocator<Char>> ss;
ss.write(toml_str.data(), static_cast<std::streamsize>(toml_str.length()));
return toml::parse(ss);
});
@ -291,7 +312,7 @@ inline void parse_expected_value(std::string_view value_str, const T& expected)
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
CHECK(nv.as<value_type>()->get() == expected);
CHECK(nv.value_or(T{}) == expected);
CHECK(nv.ref<value_type>() == expected);
val_reparsed = std::move(*nv.as<value_type>());
});
@ -301,51 +322,16 @@ inline void parse_expected_value(std::string_view value_str, const T& expected)
}
// manually instantiate some templates to reduce test compilation time (chosen using ClangBuildAnalyzer)
#define TESTS_MANUAL_INSTANTIATIONS 1
#if TESTS_MANUAL_INSTANTIATIONS
extern template void parse_expected_value(std::string_view, const int&) noexcept;
extern template void parse_expected_value(std::string_view, const unsigned int&) noexcept;
extern template void parse_expected_value(std::string_view, const bool&) noexcept;
extern template void parse_expected_value(std::string_view, const float&) noexcept;
extern template void parse_expected_value(std::string_view, const double&) noexcept;
extern template void parse_expected_value(std::string_view, const toml::string_view&) noexcept;
namespace toml::impl
namespace std
{
extern template class formatter<char>;
extern template class unique_ptr<const Catch::IExceptionTranslator>;
}
namespace toml
{
extern template class default_formatter<char>;
extern template std::ostream& operator<< (std::ostream&, const table&);
extern template std::ostream& operator<< (std::ostream&, const array&);
extern template std::ostream& operator<< (std::ostream&, const value<string>&);
extern template std::ostream& operator<< (std::ostream&, const value<int64_t>&);
extern template std::ostream& operator<< (std::ostream&, const value<double>&);
extern template std::ostream& operator<< (std::ostream&, const value<bool>&);
extern template std::ostream& operator<< (std::ostream&, const value<date>&);
extern template std::ostream& operator<< (std::ostream&, const value<time>&);
extern template std::ostream& operator<< (std::ostream&, const value<date_time>&);
extern template std::ostream& operator<< (std::ostream&, const node_view<node>&);
extern template std::ostream& operator<< (std::ostream&, const node_view<const node>&);
extern template std::ostream& operator<< (std::ostream&, node_type);
extern template std::ostream& operator<< (std::ostream&, const source_region&);
extern template std::ostream& operator<< (std::ostream&, const source_position&);
extern template std::ostream& operator<< (std::ostream&, const parse_error&);
extern template std::ostream& operator<< (std::ostream&, const date&);
extern template std::ostream& operator<< (std::ostream&, const time&);
extern template std::ostream& operator<< (std::ostream&, const time_offset&);
extern template std::ostream& operator<< (std::ostream&, const date_time&);
extern template std::ostream& operator<< (std::ostream&, default_formatter<char>&);
extern template std::ostream& operator<< (std::ostream&, default_formatter<char>&&);
}
extern template class std::unique_ptr<const Catch::IExceptionTranslator>;
namespace Catch
{
extern template struct StringMaker<node_view<node>>;
@ -358,6 +344,3 @@ namespace Catch
extern template std::string stringify(const node_view<const node>&);
}
}
#endif // TESTS_MANUAL_INSTANTIATIONS

1559
toml.hpp

File diff suppressed because it is too large Load Diff

View File

@ -60,11 +60,14 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -60,7 +60,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -62,7 +62,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -61,7 +61,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -63,7 +63,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -62,7 +62,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -61,7 +61,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -63,7 +63,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -60,7 +60,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -60,7 +60,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -62,7 +62,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -61,7 +61,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -63,7 +63,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -62,7 +62,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -61,7 +61,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -63,7 +63,10 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<ClCompile Include="..\tests\impl_catch2.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\impl_toml.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />

View File

@ -62,6 +62,7 @@
<ClInclude Include="..\include\toml++\toml_common.h" />
<ClInclude Include="..\include\toml++\toml_date_time.h" />
<ClInclude Include="..\include\toml++\toml_default_formatter.h" />
<ClInclude Include="..\include\toml++\toml_default_formatter_impl.h" />
<ClInclude Include="..\include\toml++\toml_formatter.h" />
<ClInclude Include="..\include\toml++\toml_json_formatter.h" />
<ClInclude Include="..\include\toml++\toml_node.h" />

View File

@ -67,6 +67,9 @@
<ClInclude Include="..\tests\catch2.h">
<Filter>tests</Filter>
</ClInclude>
<ClInclude Include="..\include\toml++\toml_default_formatter_impl.h">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />