diff --git a/.gitattributes b/.gitattributes index 53f3476..bae5291 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/README.md b/README.md index 3f6fd81..a5b38e8 100644 --- a/README.md +++ b/README.md @@ -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 "] +authors = ["Mark Gillard "] [dependencies] cpp = 17 @@ -69,19 +71,25 @@ You'll find some more code examples in the `examples` directory, and plenty more
# 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 ` - -### 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 ` -### 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! + +
+ +# 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._
# 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.
@@ -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 diff --git a/docs/Doxyfile b/docs/Doxyfile index 10a0a1b..fd52cc1 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -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 diff --git a/docs/Doxyfile-mcss b/docs/Doxyfile-mcss index d9162e3..f54e4aa 100644 --- a/docs/Doxyfile-mcss +++ b/docs/Doxyfile-mcss @@ -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 = \ ##! Report an issue \ ##!

Documentation generated using m.css ##! M_HTML_HEADER = \ -##! \ +##! \ ##! ##! M_FAVICON = favicon.ico diff --git a/docs/badge-C++17.svg b/docs/badge-C++17.svg new file mode 100644 index 0000000..14d427e --- /dev/null +++ b/docs/badge-C++17.svg @@ -0,0 +1 @@ + standardC++17 \ No newline at end of file diff --git a/docs/badge-C++20.svg b/docs/badge-C++20.svg new file mode 100644 index 0000000..92e9684 --- /dev/null +++ b/docs/badge-C++20.svg @@ -0,0 +1 @@ + standardC++20 \ No newline at end of file diff --git a/docs/badge-TOML.svg b/docs/badge-TOML.svg new file mode 100644 index 0000000..44f161e --- /dev/null +++ b/docs/badge-TOML.svg @@ -0,0 +1 @@ + TOMLv1.0.0 rc.1 \ No newline at end of file diff --git a/docs/badge-awesome.svg b/docs/badge-awesome.svg new file mode 100644 index 0000000..5d9da96 --- /dev/null +++ b/docs/badge-awesome.svg @@ -0,0 +1 @@ +Mentioned in an Awesome list diff --git a/docs/badge-license-MIT.svg b/docs/badge-license-MIT.svg new file mode 100644 index 0000000..52456a7 --- /dev/null +++ b/docs/badge-license-MIT.svg @@ -0,0 +1 @@ + licenseMIT \ No newline at end of file diff --git a/docs/banner.ai b/docs/banner.ai new file mode 100644 index 0000000..8bb8a4f Binary files /dev/null and b/docs/banner.ai differ diff --git a/docs/banner_large.png b/docs/banner_large.png new file mode 100644 index 0000000..108e662 Binary files /dev/null and b/docs/banner_large.png differ diff --git a/docs/banner_small.png b/docs/banner_small.png new file mode 100644 index 0000000..78640f6 Binary files /dev/null and b/docs/banner_small.png differ diff --git a/docs/toml.ai b/docs/logo.ai similarity index 100% rename from docs/toml.ai rename to docs/logo.ai diff --git a/docs/tomlplusplus-logo.png b/docs/logo.png similarity index 100% rename from docs/tomlplusplus-logo.png rename to docs/logo.png diff --git a/docs/toml-banner.ai b/docs/toml-banner.ai deleted file mode 100644 index 6b5c56c..0000000 Binary files a/docs/toml-banner.ai and /dev/null differ diff --git a/docs/tomlplusplus-banner-small.png b/docs/tomlplusplus-banner-small.png deleted file mode 100644 index eb1fc66..0000000 Binary files a/docs/tomlplusplus-banner-small.png and /dev/null differ diff --git a/docs/tomlplusplus-banner.png b/docs/tomlplusplus-banner.png deleted file mode 100644 index 5acfa65..0000000 Binary files a/docs/tomlplusplus-banner.png and /dev/null differ diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css index 8a811b3..32e7efa 100644 --- a/docs/tomlplusplus.css +++ b/docs/tomlplusplus.css @@ -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); +} diff --git a/include/toml++/toml.h b/include/toml++/toml.h index 3ac49c2..dbf7b78 100644 --- a/include/toml++/toml.h +++ b/include/toml++/toml.h @@ -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 "] +/// authors = ["Mark Gillard "] /// /// [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(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 diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index bbb7b4e..480372f 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -7,14 +7,14 @@ namespace toml::impl { - template + template class array_iterator final { private: friend class toml::array; using raw_iterator = std::conditional_t< - is_const, + IsConst, std::vector>::const_iterator, std::vector>::iterator >; @@ -31,7 +31,7 @@ namespace toml::impl public: - using value_type = std::conditional_t; + using value_type = std::conditional_t; 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; - extern template class array_iterator; - #endif - template [[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 - std::basic_ostream& operator << (std::basic_ostream&, const array&); + template + std::basic_ostream& operator << (std::basic_ostream&, 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 - iterator insert(const_iterator pos, ITER first, ITER last) noexcept + template + 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 - friend std::basic_ostream& operator << (std::basic_ostream&, const array&); + template + friend std::basic_ostream& operator << (std::basic_ostream&, const array&); }; } - -#if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION -namespace std -{ - extern template class unique_ptr; -} -#endif diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index 29fbb9b..c28f2f6 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -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 #endif -#if TOML_USE_STREAMS_FOR_FLOATS - #include -#endif #if TOML_EXCEPTIONS #include #endif @@ -503,7 +497,7 @@ namespace toml /// (typically the line numbers will be accurate but column numbers will be too high). /// This is not an error. 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 using string_map = std::map>; //heterogeneous lookup - #if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20) && _HAS_CXX20) - - template - using remove_cvref_t = std::remove_cvref_t; - - #else - template using remove_cvref_t = std::remove_cv_t>; - #endif - template struct is_one_of_ : std::integral_constant) @@ -727,12 +712,6 @@ namespace toml::impl template inline constexpr bool is_one_of = is_one_of_::value; - template - using enable_if_one_of = std::enable_if_t>; - - template - using enable_if_not_one_of = std::enable_if_t>; - template [[nodiscard]] TOML_ALWAYS_INLINE constexpr std::underlying_type_t unbox_enum(T val) noexcept @@ -843,10 +822,10 @@ namespace toml::impl template <> struct value_promoter { using type = int64_t; }; template <> struct value_promoter { using type = double; }; #ifdef TOML_SMALL_FLOAT_TYPE - template <> struct value_promoter { using type = double; }; + template <> struct value_promoter { using type = double; }; #endif #ifdef TOML_SMALL_INT_TYPE - template <> struct value_promoter { using type = int64_t; }; + template <> struct value_promoter { using type = int64_t; }; #endif template using promoted = typename impl::value_promoter::type; @@ -914,10 +893,9 @@ namespace toml::impl "date-time"sv }; - #define TOML_P2S_DECL(linkage, type) \ - template \ - linkage void print_to_stream(type, std::basic_ostream&) + template \ + linkage void print_to_stream(type, std::basic_ostream&) 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, node_type rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, node_type rhs) { using underlying_t = std::underlying_type_t; const auto str = impl::node_type_friendly_names[static_cast(rhs)]; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) return lhs << str; else { - if constexpr (sizeof(CHAR) == 1) - return lhs << std::basic_string_view{ reinterpret_cast(str.data()), str.length() }; + if constexpr (sizeof(Char) == 1) + return lhs << std::basic_string_view{ reinterpret_cast(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 } diff --git a/include/toml++/toml_date_time.h b/include/toml++/toml_date_time.h index ba4acbd..2837035 100644 --- a/include/toml++/toml_date_time.h +++ b/include/toml++/toml_date_time.h @@ -84,13 +84,18 @@ namespace toml /// \out /// 1987-03-16 /// \eout - template - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const date& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const time& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const time_offset& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const date_time& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& 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 } diff --git a/include/toml++/toml_default_formatter.h b/include/toml++/toml_default_formatter.h index 4185b32..2bd6b3b 100644 --- a/include/toml++/toml_default_formatter.h +++ b/include/toml++/toml_default_formatter.h @@ -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(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) - { - 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) - { - 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) - { - return n.get().length() + 2_sz; // + "" - } - else if constexpr (is_number) - { - 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) - { - 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) - { - 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) - { - return 5_sz; - } - else if constexpr (is_date || is_time) - { - return 10_sz; - } - else if constexpr (is_date_time) - { - 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 - class default_formatter final : impl::formatter + /// \tparam Char The underlying character type of the output stream. Must be 1 byte in size. + template + class TOML_API default_formatter final : impl::formatter { private: - using base = impl::formatter; + using base = impl::formatter; std::vector key_path; void print_key_segment(const toml::string& str) @@ -459,12 +327,16 @@ namespace toml friend std::basic_ostream& operator << (std::basic_ostream&, default_formatter&&); }; + #if !TOML_ALL_INLINE + extern template class TOML_API default_formatter; + #endif + default_formatter(const table&) -> default_formatter; default_formatter(const array&) -> default_formatter; template default_formatter(const value&) -> default_formatter; - template - inline void default_formatter::print_inline(const toml::table& tbl) + template + inline void default_formatter::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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, default_formatter& rhs) + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, default_formatter& 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, default_formatter&& rhs) + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, default_formatter&& rhs) { return lhs << rhs; //as lvalue } - template - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const table& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, const table& rhs) { - return lhs << default_formatter{ rhs }; + return lhs << default_formatter{ rhs }; } - template - inline std::basic_ostream& operator << (std::basic_ostream& lhs, const array& rhs) + template + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, const array& rhs) { - return lhs << default_formatter{ rhs }; + return lhs << default_formatter{ rhs }; } + + #if !TOML_ALL_INLINE + extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter&); + extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter&&); + extern template TOML_API std::ostream& operator << (std::ostream&, const table&); + extern template TOML_API std::ostream& operator << (std::ostream&, const array&); + #endif } diff --git a/include/toml++/toml_default_formatter_impl.h b/include/toml++/toml_default_formatter_impl.h new file mode 100644 index 0000000..d9352b2 --- /dev/null +++ b/include/toml++/toml_default_formatter_impl.h @@ -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 +//# 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(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) + { + 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) + { + 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) + { + return n.get().length() + 2_sz; // + "" + } + else if constexpr (is_number) + { + 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) + { + 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) + { + 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) + { + return 5_sz; + } + else if constexpr (is_date || is_time) + { + return 10_sz; + } + else if constexpr (is_date_time) + { + 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; + } +} diff --git a/include/toml++/toml_formatter.h b/include/toml++/toml_formatter.h index 34866dc..cd7799c 100644 --- a/include/toml++/toml_formatter.h +++ b/include/toml++/toml_formatter.h @@ -26,12 +26,12 @@ namespace toml namespace toml::impl { - template - class formatter + template + class TOML_API formatter { private: const toml::node* source_; - std::basic_ostream* stream_ = nullptr; + std::basic_ostream* 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& stream() const noexcept { return *stream_; } + [[nodiscard]] std::basic_ostream& 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& stream) noexcept + void attach(std::basic_ostream& 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; + #endif } diff --git a/include/toml++/toml_instantiations.h b/include/toml++/toml_instantiations.h index 15fd893..a513fff 100644 --- a/include/toml++/toml_instantiations.h +++ b/include/toml++/toml_instantiations.h @@ -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 +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; template class TOML_API node_view; - // table and array iterators - #if !TOML_ALL_INLINE && !TOML_HAS_API_ANNOTATION + // formatters namespace impl { - template struct table_proxy_pair; - template struct table_proxy_pair; - template class table_iterator; - template class table_iterator; - template class array_iterator; - template class array_iterator; + template class TOML_API formatter; + } + template class TOML_API default_formatter; + template class TOML_API json_formatter; + + // 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&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, const value&); + template TOML_API std::ostream& operator << (std::ostream&, default_formatter&); + template TOML_API std::ostream& operator << (std::ostream&, default_formatter&&); + template TOML_API std::ostream& operator << (std::ostream&, json_formatter&); + template TOML_API std::ostream& operator << (std::ostream&, json_formatter&&); + 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&); + template TOML_API std::ostream& operator << (std::ostream&, const node_view&); + 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; - template class unique_ptr; - template class unique_ptr; - template class unique_ptr>; - template class unique_ptr>; - template class unique_ptr>; - template class unique_ptr>; - template class unique_ptr>; - template class unique_ptr>; - template class unique_ptr>; -} -#endif - +#endif // !TOML_ALL_INLINE diff --git a/include/toml++/toml_json_formatter.h b/include/toml++/toml_json_formatter.h index 23d8c08..144319c 100644 --- a/include/toml++/toml_json_formatter.h +++ b/include/toml++/toml_json_formatter.h @@ -43,12 +43,12 @@ namespace toml /// } /// \eout /// - /// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size. - template - class json_formatter final : impl::formatter + /// \tparam Char The underlying character type of the output stream. Must be 1 byte in size. + template + class TOML_API json_formatter final : impl::formatter { private: - using base = impl::formatter; + using base = impl::formatter; inline void print(const toml::table& tbl); @@ -112,13 +112,17 @@ namespace toml template friend std::basic_ostream& operator << (std::basic_ostream&, json_formatter&&); }; + + #if !TOML_ALL_INLINE + extern template class TOML_API json_formatter; + #endif json_formatter(const table&) -> json_formatter; json_formatter(const array&) -> json_formatter; template json_formatter(const value&) -> json_formatter; - template - inline void json_formatter::print(const toml::table& tbl) + template + inline void json_formatter::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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter& rhs) + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter& 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 - inline std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter&& rhs) + TOML_FUNC_EXTERNAL_LINKAGE + std::basic_ostream& operator << (std::basic_ostream& lhs, json_formatter&& rhs) { return lhs << rhs; //as lvalue } + + #if !TOML_ALL_INLINE + extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter&); + extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter&&); + #endif } diff --git a/include/toml++/toml_node.h b/include/toml++/toml_node.h index d353243..316f47c 100644 --- a/include/toml++/toml_node.h +++ b/include/toml++/toml_node.h @@ -263,57 +263,57 @@ namespace toml private: - template - static constexpr bool can_visit = std::is_invocable_v>; + template + static constexpr bool can_visit = std::is_invocable_v>; - template + template static constexpr bool can_visit_any = - can_visit - || can_visit - || can_visit - || can_visit - || can_visit - || can_visit - || can_visit - || can_visit - || can_visit; + can_visit + || can_visit + || can_visit + || can_visit + || can_visit + || can_visit + || can_visit + || can_visit + || can_visit; - template + template static constexpr bool can_visit_all = - can_visit - && can_visit - && can_visit - && can_visit - && can_visit - && can_visit - && can_visit - && can_visit - && can_visit; + can_visit + && can_visit + && can_visit + && can_visit + && can_visit + && can_visit + && can_visit + && can_visit + && can_visit; - template + template static constexpr bool visit_is_nothrow_one = - !can_visit - || std::is_nothrow_invocable_v>; + !can_visit + || std::is_nothrow_invocable_v>; - template + template static constexpr bool visit_is_nothrow = - visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one - && visit_is_nothrow_one; + visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one + && visit_is_nothrow_one; - template > + template > struct visit_return_type final { - using type = decltype(std::declval()(std::declval>())); + using type = decltype(std::declval()(std::declval>())); }; - template - struct visit_return_type final + template + struct visit_return_type 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 - static decltype(auto) do_visit(N&& n, FUNC&& visitor) - noexcept(visit_is_nothrow) + template + static decltype(auto) do_visit(N&& n, Func&& visitor) + noexcept(visit_is_nothrow) { static_assert( - can_visit_any, + can_visit_any, "Visitors must be invocable for at least one of the toml::node specializations" ); switch (n.type()) { case node_type::table: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast
()); break; case node_type::array: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::string: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::integer: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::floating_point: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::boolean: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::date: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::time: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast
()), table&>); + static_assert(is_same_v().ref
()), table&&>); + static_assert(is_same_v().ref
()), const table&>); + static_assert(is_same_v().ref()), array&>); + static_assert(is_same_v().ref()), array&&>); + static_assert(is_same_v().ref()), const array&>); + + static_assert(is_same_v>().ref()), double&>); + static_assert(is_same_v>().ref()), const double&>); + static_assert(is_same_v>().ref>()), double&>); + static_assert(is_same_v>().ref>()), const double&>); + static_assert(is_same_v>().ref
()), table&>); + static_assert(is_same_v>().ref
()), const table&>); + static_assert(is_same_v>().ref()), array&>); + static_assert(is_same_v>().ref()), const array&>); +} diff --git a/tests/main.cpp b/tests/main.cpp deleted file mode 100644 index e026e4a..0000000 --- a/tests/main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifdef TARTANLLAMA_OPTIONAL - #if __has_include() - #include - #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); -} diff --git a/tests/meson.build b/tests/meson.build index 30f953c..ed31bec 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,5 +1,6 @@ test_sources = [ - 'main.cpp', + 'impl_toml.cpp', + 'impl_catch2.cpp', 'parsing_arrays.cpp', 'parsing_booleans.cpp', 'parsing_comments.cpp', diff --git a/tests/parsing_arrays.cpp b/tests/parsing_arrays.cpp index 40638c6..a5ae9cf 100644 --- a/tests/parsing_arrays.cpp +++ b/tests/parsing_arrays.cpp @@ -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 diff --git a/tests/parsing_comments.cpp b/tests/parsing_comments.cpp index 8712659..dc13b26 100644 --- a/tests/parsing_comments.cpp +++ b/tests/parsing_comments.cpp @@ -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 + )); + } } diff --git a/tests/parsing_dates_and_times.cpp b/tests/parsing_dates_and_times.cpp index 189a6af..40a6c4a 100644 --- a/tests/parsing_dates_and_times.cpp +++ b/tests/parsing_dates_and_times.cpp @@ -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 } ); { diff --git a/tests/parsing_floats.cpp b/tests/parsing_floats.cpp index 6aca954..2a11dc1 100644 --- a/tests/parsing_floats.cpp +++ b/tests/parsing_floats.cpp @@ -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 } diff --git a/tests/parsing_key_value_pairs.cpp b/tests/parsing_key_value_pairs.cpp index 84f85ef..bdf2733 100644 --- a/tests/parsing_key_value_pairs.cpp +++ b/tests/parsing_key_value_pairs.cpp @@ -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 } diff --git a/tests/parsing_strings.cpp b/tests/parsing_strings.cpp index 02523bf..39396b3 100644 --- a/tests/parsing_strings.cpp +++ b/tests/parsing_strings.cpp @@ -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 diff --git a/tests/parsing_tables.cpp b/tests/parsing_tables.cpp index a3e8856..1f67e3b 100644 --- a/tests/parsing_tables.cpp +++ b/tests/parsing_tables.cpp @@ -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", diff --git a/tests/tests.cpp b/tests/tests.cpp index 3f7c2cd..e91ce2f 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -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; + template class unique_ptr; } - - -namespace toml -{ - template class default_formatter; - - template std::ostream& operator<< (std::ostream&, const table&); - template std::ostream& operator<< (std::ostream&, const array&); - template std::ostream& operator<< (std::ostream&, const value&); - template std::ostream& operator<< (std::ostream&, const value&); - template std::ostream& operator<< (std::ostream&, const value&); - template std::ostream& operator<< (std::ostream&, const value&); - template std::ostream& operator<< (std::ostream&, const value&); - template std::ostream& operator<< (std::ostream&, const value
()), table&>); - static_assert(is_same_v().ref
()), table&&>); - static_assert(is_same_v().ref
()), const table&>); - static_assert(is_same_v().ref()), array&>); - static_assert(is_same_v().ref()), array&&>); - static_assert(is_same_v().ref()), const array&>); - - static_assert(is_same_v>().ref()), double&>); - static_assert(is_same_v>().ref()), const double&>); - static_assert(is_same_v>().ref>()), double&>); - static_assert(is_same_v>().ref>()), const double&>); - static_assert(is_same_v>().ref
()), table&>); - static_assert(is_same_v>().ref
()), const table&>); - static_assert(is_same_v>().ref()), array&>); - static_assert(is_same_v>().ref()), const array&>); - -} diff --git a/tests/tests.h b/tests/tests.h index fc95b18..4473e7e 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -30,8 +30,8 @@ using namespace Catch::literals; #define S(str) TOML_STRING_PREFIX(str) -template -inline void parsing_should_succeed(std::basic_string_view toml_str, FUNC&& func, std::string_view source_path = {}) noexcept +template +inline void parsing_should_succeed(std::basic_string_view toml_str, Func&& func = {}, std::string_view source_path = {}) noexcept { INFO("String being parsed: '"sv << std::string_view( reinterpret_cast(toml_str.data()), toml_str.length() ) << "'"sv) @@ -50,19 +50,27 @@ inline void parsing_should_succeed(std::basic_string_view toml_str, FUNC&& return std::move(tabl); }; + static constexpr auto is_functor = !std::is_same_v, std::false_type>; + #if TOML_EXCEPTIONS try { { INFO("Parsing string directly"sv) - std::forward(func)(validate_table(toml::parse(toml_str, source_path), source_path)); + if constexpr (is_functor) + std::forward(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, std::allocator> ss; + std::basic_stringstream, std::allocator> ss; ss.write(toml_str.data(), static_cast(toml_str.length())); - std::forward(func)(validate_table(toml::parse(ss, source_path), source_path)); + if constexpr (is_functor) + std::forward(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 toml_str, FUNC&& INFO("Parsing string directly"sv) parse_result result = toml::parse(toml_str, source_path); if (result) - std::forward(func)(validate_table(std::move(result), source_path)); + { + if constexpr (is_functor) + std::forward(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 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, std::allocator> ss; + std::basic_stringstream, std::allocator> ss; ss.write(toml_str.data(), static_cast(toml_str.length())); parse_result result = toml::parse(ss, source_path); if (result) - std::forward(func)(validate_table(std::move(result), source_path)); + { + if constexpr (is_functor) + std::forward(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 toml_str, FUNC&& << ", column "sv << result.error().source().begin.column << ":\n"sv << result.error().description() ); - return; + std::exit(-1); + TOML_UNREACHABLE; } } #endif } -template -inline void parsing_should_fail(std::basic_string_view toml_str) noexcept +template +inline void parsing_should_fail(std::basic_string_view toml_str) noexcept { INFO("String being parsed: '"sv << std::string_view(reinterpret_cast(toml_str.data()), toml_str.length()) << "'"sv) @@ -145,7 +165,7 @@ inline void parsing_should_fail(std::basic_string_view toml_str) noexcept if (run_tests([=]() { (void)toml::parse(toml_str); })) run_tests([=]() { - std::basic_stringstream, std::allocator> ss; + std::basic_stringstream, std::allocator> ss; ss.write(toml_str.data(), static_cast(toml_str.length())); (void)toml::parse(ss); }); @@ -158,7 +178,8 @@ inline void parsing_should_fail(std::basic_string_view 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 toml_str) noexcept if (run_tests([=]() noexcept { return toml::parse(toml_str); })) run_tests([=]() noexcept { - std::basic_stringstream, std::allocator> ss; + std::basic_stringstream, std::allocator> ss; ss.write(toml_str.data(), static_cast(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); CHECK(nv.as()->get() == expected); - CHECK(nv.value_or(T{}) == expected); + CHECK(nv.ref() == expected); val_reparsed = std::move(*nv.as()); }); @@ -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; + extern template class unique_ptr; } - - -namespace toml -{ - extern template class default_formatter; - - 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&); - extern template std::ostream& operator<< (std::ostream&, const value&); - extern template std::ostream& operator<< (std::ostream&, const value&); - extern template std::ostream& operator<< (std::ostream&, const value&); - extern template std::ostream& operator<< (std::ostream&, const value&); - extern template std::ostream& operator<< (std::ostream&, const value
()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast
()); break; case node_type::array: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::string: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::integer: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::floating_point: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::boolean: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::date: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast()); + if constexpr (can_visit) + return std::forward(visitor)(std::forward(n).template ref_cast()); break; case node_type::time: - if constexpr (can_visit) - return std::forward(visitor)(std::forward(n).template ref_cast