mirror of
https://github.com/marzer/tomlplusplus.git
synced 2026-01-19 04:52:09 +00:00
release 0.1.0
- added `toml::is_number<>` - added `toml::node_type::none` - added initializer_list and vector relops to `toml::array` - added constructors for `time_offset` and `date_time` - added much to `node_view` - added tests for `node_view` value relops - added lots more documentation - removed `time_offset::from_hh_mm` - removed the handling of `\s` literals (looks like it's not going be accepted as-is)
This commit is contained in:
@@ -96,7 +96,7 @@ addition of unreleased features from the [TOML master] and some sane cherry-pick
|
||||
[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_REVISION`.
|
||||
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
|
||||
@@ -104,7 +104,6 @@ defines `TOML_LANG_MAJOR`, `TOML_LANG_MINOR` and `TOML_LANG_REVISION`.
|
||||
- [#562]: Allow hex floatingpoint values
|
||||
- [#567]: Clarify that control characters are not permitted in comments
|
||||
- [#571]: Allow raw tabs inside strings
|
||||
- [#622]: Add short escaping alias `\s` for space (`\u0020`)
|
||||
- [#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`
|
||||
@@ -167,7 +166,7 @@ cd ../build-clang && ninja && ninja test
|
||||
UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[Flexible and Economical UTF-8 Decoder]',
|
||||
which is also subject to the terms of the MIT license - see [LICENSE-utf8-decoder].
|
||||
|
||||
[API documentation]: https://marzer.github.io/tomlplusplus/namespacetoml.html
|
||||
[API documentation]: https://marzer.github.io/tomlplusplus/
|
||||
[unreleased TOML language features]: https://github.com/marzer/tomlplusplus#unreleased-features
|
||||
[numbered version]: https://github.com/toml-lang/toml/releases
|
||||
[char8_t]: https://en.cppreference.com/w/cpp/keyword/char8_t
|
||||
|
||||
@@ -89,7 +89,8 @@ pre.m-code + pre
|
||||
{
|
||||
margin-top: -1.0rem;
|
||||
color: #bababa; /* is yououou */
|
||||
background-color: #282e36aa;
|
||||
background-color: #383e46;
|
||||
border-top: 2px solid #181e26;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,24 +52,217 @@
|
||||
#undef TOML_STRING_PREFIX
|
||||
#undef TOML_UNDEF_MACROS
|
||||
#undef TOML_DOXYGEN
|
||||
#undef TOML_RELOPS_REORDERING
|
||||
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
|
||||
#endif
|
||||
|
||||
/// \mainpage toml++
|
||||
///
|
||||
/// This is the home of the API documentation for toml++, a [TOML](https://github.com/toml-lang/toml) parser for C++17 and later.
|
||||
/// If you're looking for information about how to add toml++ to your project etc, see the
|
||||
/// see [README](https://github.com/marzer/tomlplusplus/blob/master/README.md) on GitHub.
|
||||
/// Otherwise, browse the docs using the links at the top of the page. You can search from anywhere by pressing the TAB key.
|
||||
/// This is the home of toml++, a header-only [TOML](https://github.com/toml-lang/toml) parser and serializer for C++17 and later.
|
||||
///
|
||||
/// \tableofcontents
|
||||
///
|
||||
/// <em>Obviously this page is pretty sparse and could do with some more content. If you have concrete suggestions for what
|
||||
/// should go here, please [let me know](https://github.com/marzer/tomlplusplus/issues)!</em>
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-features Features
|
||||
/// - C++17 (plus some C++20 features where supported, e.g. char8_t strings)
|
||||
/// - Proper UTF-8 handling (incl. BOM)
|
||||
/// - Works with or without exceptions
|
||||
/// - Doesn't require RTTI
|
||||
/// - First-class support for serializing to JSON
|
||||
/// - Fully [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)-compliant
|
||||
/// - Supports a number of 'unreleased' TOML features (optional; these can be disabled)
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-adding-lib Adding toml++ to your project
|
||||
/// Clone [the repository](https://github.com/marzer/tomlplusplus/) from GitHub. It's header-only so there's not much you have to do after that,
|
||||
/// other than some very minor (optional) configuration. See the [README](https://github.com/marzer/tomlplusplus/blob/master/README.md) for more info.
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-api-documentation API Documentation
|
||||
/// You're looking at it! Browse the docs using the links at the top of the page. You can search from anywhere by pressing the TAB key.
|
||||
///
|
||||
/// <em>toml++ is still pretty hot off the presses so there's going to be some omissions, typos and general sparseness throughout the docs.
|
||||
/// If you spot something or have a suggestion, please [let me know](https://github.com/marzer/tomlplusplus/issues)!</em>
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-example Basic examples
|
||||
///
|
||||
///////////////////////////////////
|
||||
///
|
||||
/// \subsection mainpage-example-parsing-files Parsing TOML files
|
||||
/// toml++ works whether you have exceptions enabled or not. For the most part the usage is the same,
|
||||
/// the main difference being how parsing errors are reported to the caller. When exceptions are enabled
|
||||
/// a toml::parse_error is thrown directly from the site of the error:
|
||||
/// \cpp
|
||||
/// #include <iostream>
|
||||
/// #include <fstream> //required for parse_file()
|
||||
/// #include <toml++/toml.h>
|
||||
/// using namespace std::string_view_literals;
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// toml::table tbl;
|
||||
/// try
|
||||
/// {
|
||||
/// tbl = toml::parse_file("configuration.toml");
|
||||
/// }
|
||||
/// 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;
|
||||
/// return 1;
|
||||
/// }
|
||||
///
|
||||
/// do_stuff_with_your_config(tbl);
|
||||
/// return 0;
|
||||
/// }
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// When exceptions are disabled parsing methods return a toml::parse_error and it is up to the caller
|
||||
/// to check if parsing has been successful by examining the return value:
|
||||
/// \cpp
|
||||
/// #include <iostream>
|
||||
/// #include <fstream> //required for parse_file()
|
||||
/// #include <toml++/toml.h>
|
||||
/// using namespace std::string_view_literals;
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// toml::parse_result tbl = toml::parse_file("configuration.toml");
|
||||
/// 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;
|
||||
/// return 1;
|
||||
/// }
|
||||
///
|
||||
/// do_stuff_with_your_config(tbl); //toml::parse_result is convertible to toml::table
|
||||
/// return 0;
|
||||
/// }
|
||||
/// \ecpp
|
||||
/// \see toml::parse_file()
|
||||
///
|
||||
///////////////////////////////////
|
||||
///
|
||||
/// \subsection mainpage-example-parsing-strings Parsing TOML directly from strings
|
||||
///
|
||||
/// \cpp
|
||||
/// #include <iostream>
|
||||
/// #include <toml++/toml.h>
|
||||
/// using namespace std::string_view_literals;
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// // parse error handling omitted for brevity.
|
||||
/// static constexpr auto source = R"(
|
||||
/// [library]
|
||||
/// name = "toml++"
|
||||
/// version = "0.1.0"
|
||||
/// authors = ["Mark Gillard <mark@notarealwebsite.com>"]
|
||||
///
|
||||
/// [dependencies]
|
||||
/// cpp = 17
|
||||
/// )"sv;
|
||||
/// auto tbl = toml::parse(source);
|
||||
/// std::cout << tbl << std::endl;
|
||||
/// return 0;
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [dependencies]
|
||||
/// cpp = 17
|
||||
///
|
||||
/// [library]
|
||||
/// authors = ["Mark Gillard <mark@notarealwebsite.com>"]
|
||||
/// name = "toml++"
|
||||
/// version = "0.1.0"
|
||||
/// \eout
|
||||
/// \see toml::parse()
|
||||
///
|
||||
///////////////////////////////////
|
||||
///
|
||||
/// \subsection mainpage-example-manipulations Traversing and manipulating data
|
||||
///
|
||||
/// \cpp
|
||||
/// #include <iostream>
|
||||
/// #include <toml++/toml.h>
|
||||
/// using namespace std::string_view_literals;
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// static constexpr auto source = R"(
|
||||
/// numbers = [ 1, 2, 3, "four", 5.0 ]
|
||||
/// vegetables = [ "tomato", "onion", "mushroom", "lettuce" ]
|
||||
/// minerals = [ "quartz", "iron", "copper", "diamond" ]
|
||||
///
|
||||
/// [animals]
|
||||
/// cats = [ "tiger", "lion", "puma" ]
|
||||
/// birds = [ "macaw", "pigeon", "canary" ]
|
||||
/// fish = [ "salmon", "trout", "carp" ]
|
||||
///
|
||||
/// )"sv;
|
||||
/// auto tbl = toml::parse(source);
|
||||
///
|
||||
/// auto numbers = tbl["numbers"];
|
||||
/// std::cout << "table has 'numbers': "sv << !!numbers << std::endl;
|
||||
/// if (numbers)
|
||||
/// {
|
||||
/// std::cout << "'numbers' is a: "sv << numbers.type() << std::endl;
|
||||
/// std::cout << "'numbers': "sv << numbers << std::endl;
|
||||
/// for (auto& node : *numbers.as_array())
|
||||
/// {
|
||||
/// node.visit([=](auto&& n) noexcept
|
||||
/// {
|
||||
/// if constexpr (toml::is_number<decltype(n)>)
|
||||
/// (*n)++;
|
||||
/// else if constexpr (toml::is_string<decltype(n)>)
|
||||
/// n = "five"sv;
|
||||
/// });
|
||||
/// }
|
||||
/// numbers.as_array()->push_back(7);
|
||||
/// numbers.as_array()->emplace_back<toml::array>(8, 9);
|
||||
/// std::cout << "'numbers': "sv << numbers << std::endl;
|
||||
/// }
|
||||
///
|
||||
/// std::cout << "'cats': "sv << tbl["animals"]["cats"] << std::endl;
|
||||
/// std::cout << "'dinosaurs': "sv << tbl["animals"]["dinosaurs"] << std::endl; //no dinosaurs :(
|
||||
///
|
||||
/// return 0;
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// table has 'numbers': true
|
||||
/// 'numbers' is an: array
|
||||
/// 'numbers': [1, 2, 3, "four", 5.0]
|
||||
/// 'numbers': [2, 3, 4, "five", 6.0, 7, [8, 9]]
|
||||
/// 'cats': ["tiger", "lion", "puma"]
|
||||
/// 'dinosaurs':
|
||||
/// \eout
|
||||
///
|
||||
/// \see toml::node, toml::node_view, toml::array, toml::table
|
||||
///
|
||||
///////////////////////////////////
|
||||
///
|
||||
/// \subsection mainpage-example-serialization Serializing as TOML and JSON
|
||||
/// \cpp
|
||||
/// #include <iostream>
|
||||
/// #include <toml++/toml.h>
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "lib", "toml++" },
|
||||
/// { "cpp", toml::array{ 17, 20, "and beyond" } },
|
||||
@@ -82,21 +275,62 @@
|
||||
/// }}
|
||||
/// },
|
||||
/// }};
|
||||
///
|
||||
/// std::cout << "###### TOML ######"sv << std::endl;
|
||||
/// std::cout << tbl << std::endl << std::endl;
|
||||
///
|
||||
/// std::cout << tbl << std::endl;
|
||||
/// std::cout << "###### JSON ######"sv << std::endl;
|
||||
/// std::cout << toml::json_formatter{ tbl } << std::endl;
|
||||
/// return 0;
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
///
|
||||
/// \out
|
||||
/// cpp = [ 17, 20, "and beyond" ]
|
||||
/// ###### TOML ######
|
||||
/// cpp = [17, 20, "and beyond"]
|
||||
/// lib = "toml++"
|
||||
/// repo = "https://github.com/marzer/tomlplusplus/"
|
||||
/// toml = [ "0.5.0", "and beyond" ]
|
||||
/// toml = ["0.5.0", "and beyond"]
|
||||
///
|
||||
/// [author]
|
||||
/// github = "https://github.com/marzer"
|
||||
/// name = "Mark Gillard"
|
||||
/// twitter = "https://twitter.com/marzer8789"
|
||||
/// \eout
|
||||
///
|
||||
/// ###### JSON ######
|
||||
/// {
|
||||
/// "author" : {
|
||||
/// "github" : "https://github.com/marzer",
|
||||
/// "name" : "Mark Gillard",
|
||||
/// "twitter" : "https://twitter.com/marzer8789"
|
||||
/// },
|
||||
/// "cpp" : [
|
||||
/// 17,
|
||||
/// 20,
|
||||
/// "and beyond"
|
||||
/// ],
|
||||
/// "lib" : "toml++",
|
||||
/// "repo" : "https://github.com/marzer/tomlplusplus/",
|
||||
/// "toml" : [
|
||||
/// "0.5.0",
|
||||
/// "and beyond"
|
||||
/// ]
|
||||
/// }
|
||||
/// \eout
|
||||
/// \see toml::default_formatter, toml::json_formatter
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-contributing Contributing
|
||||
/// See the [Contributing](https://github.com/marzer/tomlplusplus/blob/master/README.md#contributing) section of the repository README.
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \section mainpage-license License
|
||||
///
|
||||
/// toml++ is licensed under the terms of the MIT license - see [LICENSE](https://github.com/marzer/tomlplusplus/blob/master/LICENSE).
|
||||
///
|
||||
/// UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's 'Flexible and Economical UTF - 8 Decoder', which is also subject
|
||||
/// to the terms of the MIT license - see [LICENSE-utf8-decoder](https://github.com/marzer/tomlplusplus/blob/master/LICENSE-utf8-decoder).
|
||||
///
|
||||
///
|
||||
|
||||
@@ -178,15 +178,12 @@ namespace toml::impl
|
||||
namespace toml
|
||||
{
|
||||
[[nodiscard]] bool operator == (const table& lhs, const table& rhs) noexcept;
|
||||
[[nodiscard]] bool operator != (const table& lhs, const table& rhs) noexcept;
|
||||
|
||||
/// \brief A TOML array.
|
||||
///
|
||||
/// \remarks The interface of this type is modeled after std::vector, with some
|
||||
/// \detail The interface of this type is modeled after std::vector, with some
|
||||
/// additional considerations made for the heterogeneous nature of a
|
||||
/// TOML array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// TOML array. \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse("arr = [1, 2, 3, 4, 'five']"sv);
|
||||
/// auto& arr = *tbl.get_as<toml::array>("arr");
|
||||
@@ -196,9 +193,9 @@ namespace toml
|
||||
/// {
|
||||
/// arr[i].visit([=](auto&& el) noexcept
|
||||
/// {
|
||||
/// if constexpr (toml::is_integer<decltype(el)>)
|
||||
/// if constexpr (toml::is_number<decltype(el)>)
|
||||
/// (*el)++;
|
||||
/// else
|
||||
/// else if constexpr (toml::is_string<decltype(el)>)
|
||||
/// el = "six"sv;
|
||||
/// });
|
||||
/// }
|
||||
@@ -303,6 +300,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
array(const array&) = delete;
|
||||
array& operator= (const array&) = delete;
|
||||
|
||||
/// \brief Always returns node_type::array for array nodes.
|
||||
[[nodiscard]] node_type type() const noexcept override { return node_type::array; }
|
||||
/// \brief Always returns `false` for array nodes.
|
||||
@@ -807,6 +807,31 @@ namespace toml
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = lhs.get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || *elem != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t total_leaf_count() const noexcept
|
||||
{
|
||||
size_t leaves{};
|
||||
@@ -836,6 +861,22 @@ namespace toml
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Initializer list equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::initializer_list<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>)
|
||||
|
||||
/// \brief Vector equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::vector<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>)
|
||||
|
||||
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
|
||||
///
|
||||
/// \detail \cpp
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
#define TOML_INTERFACE __declspec(novtable)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#ifndef __cpp_exceptions
|
||||
@@ -114,6 +118,10 @@
|
||||
#define TOML_USE_STREAMS_FOR_FLOATS 1
|
||||
#endif
|
||||
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOML_CPP_VERSION
|
||||
@@ -209,6 +217,17 @@
|
||||
#ifndef TOML_NODISCARD_CTOR
|
||||
#define TOML_NODISCARD_CTOR
|
||||
#endif
|
||||
#ifndef TOML_RELOPS_REORDERING
|
||||
#define TOML_RELOPS_REORDERING 0
|
||||
#endif
|
||||
#if TOML_RELOPS_REORDERING
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(...)
|
||||
#else
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator == (RHS rhs, LHS lhs) noexcept { return lhs == rhs; } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
|
||||
#endif
|
||||
|
||||
#include "toml_version.h"
|
||||
|
||||
@@ -217,10 +236,10 @@
|
||||
|
||||
#if TOML_UNRELEASED_FEATURES
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION+1)
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
|
||||
#else
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION)
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
#endif
|
||||
|
||||
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
|
||||
@@ -232,6 +251,7 @@
|
||||
#define TOML_LANG_EXACTLY(maj, min, rev) \
|
||||
(TOML_LANG_EFFECTIVE_VERSION == TOML_MAKE_VERSION(maj, min, rev))
|
||||
|
||||
|
||||
////////// INCLUDES
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
@@ -321,6 +341,7 @@ namespace toml
|
||||
/// \brief TOML node type identifiers.
|
||||
enum class node_type : uint8_t
|
||||
{
|
||||
none, ///< Not-a-node.
|
||||
table, ///< The node is a toml::table.
|
||||
array, ///< The node is a toml::array.
|
||||
string, ///< The node is a toml::value<toml::string>.
|
||||
@@ -745,7 +766,7 @@ namespace toml::impl
|
||||
template <> struct node_type_of_<date_time> { static constexpr auto value = node_type::date_time; };
|
||||
|
||||
template <typename T>
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<T>::type>>::value;
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<remove_cvref_t<T>>::type>>::value;
|
||||
|
||||
inline constexpr toml::string_view low_character_escape_table[] =
|
||||
{
|
||||
@@ -785,6 +806,7 @@ namespace toml::impl
|
||||
|
||||
inline constexpr std::string_view node_type_friendly_names[] =
|
||||
{
|
||||
"none"sv,
|
||||
"table"sv,
|
||||
"array"sv,
|
||||
"string"sv,
|
||||
@@ -836,6 +858,9 @@ namespace toml
|
||||
/// \brief Metafunction for determining if a type is a double or toml::value<double>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_floating_point = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<double>>;
|
||||
/// \brief Metafunction for determining if a type satisfies `toml::is_integer || toml::is_floating_point`.
|
||||
template <typename T>
|
||||
inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
|
||||
/// \brief Metafunction for determining if a type is a bool toml::value<bool>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_boolean = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<bool>>;
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace toml
|
||||
/// \brief The day component, from 1 - 31.
|
||||
uint8_t day;
|
||||
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS date.
|
||||
@@ -44,6 +43,13 @@ namespace toml
|
||||
|
||||
|
||||
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date{ 1987, 3, 16 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16
|
||||
/// \eout
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
|
||||
TOML_MAY_THROW
|
||||
@@ -93,6 +99,15 @@ namespace toml
|
||||
}
|
||||
|
||||
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time{ 10, 20, 34 } << std::endl;
|
||||
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 10:20:34
|
||||
/// 10:20:34.5
|
||||
/// \eout
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs)
|
||||
TOML_MAY_THROW
|
||||
@@ -108,13 +123,19 @@ namespace toml
|
||||
/// \brief Offset from UTC+0, in minutes.
|
||||
int16_t minutes;
|
||||
|
||||
/// \brief Creates a timezone offset from separate hour and minute totals.
|
||||
/// \brief Default-constructs a zero time-offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset() noexcept
|
||||
: minutes{}
|
||||
{}
|
||||
|
||||
/// \brief Constructs a timezone offset from separate hour and minute totals.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::cout << time_offset::from_hh_mm(2, 30) << std::endl;
|
||||
/// std::cout << time_offset::from_hh_mm(-2, 30) << std::endl;
|
||||
/// std::cout << time_offset::from_hh_mm(-2, -30) << std::endl;
|
||||
/// std::cout << time_offset::from_hh_mm(0,0) << std::endl;
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ 0, 0 } << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
@@ -129,11 +150,10 @@ namespace toml
|
||||
/// \param minutes The total minutes.
|
||||
///
|
||||
/// \returns A time_offset.
|
||||
[[nodiscard]]
|
||||
static constexpr time_offset from_hh_mm(int8_t hours, int8_t minutes) noexcept
|
||||
{
|
||||
return time_offset{ static_cast<int16_t>(hours * 60 + minutes) };
|
||||
}
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset(int8_t hours, int8_t minutes) noexcept
|
||||
: minutes{ static_cast<int16_t>(hours * 60 + minutes) }
|
||||
{}
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
@@ -160,6 +180,21 @@ namespace toml
|
||||
}
|
||||
|
||||
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ 2, -30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{} << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// +02:30
|
||||
/// +01:30
|
||||
/// Z
|
||||
/// -01:30
|
||||
/// -02:30
|
||||
/// \eout
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
|
||||
TOML_MAY_THROW
|
||||
@@ -181,6 +216,35 @@ namespace toml
|
||||
/// \remarks The date_time is said to be 'local' if the time_offset is empty.
|
||||
std::optional<toml::time_offset> time_offset;
|
||||
|
||||
/// \brief Default-constructs a zero date-time.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time() noexcept
|
||||
: date{},
|
||||
time{}
|
||||
{}
|
||||
|
||||
/// \brief Constructs a local date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t) noexcept
|
||||
: date{ d },
|
||||
time{ t }
|
||||
{}
|
||||
|
||||
/// \brief Constructs an offset date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
/// \param offset The timezone offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t, toml::time_offset offset) noexcept
|
||||
: date{ d },
|
||||
time{ t },
|
||||
time_offset{ offset }
|
||||
{}
|
||||
|
||||
/// \brief Returns true if this date_time does not contain timezone offset information.
|
||||
[[nodiscard]]
|
||||
constexpr bool is_local() const noexcept
|
||||
@@ -217,6 +281,17 @@ namespace toml
|
||||
}
|
||||
|
||||
/// \brief Prints a date_time out to a stream in RFC 3339 format.
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << std::endl;
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << std::endl;
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16T10:20:34
|
||||
/// 1987-03-16T10:20:34-02:30
|
||||
/// 1987-03-16T10:20:34Z
|
||||
/// \eout
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs)
|
||||
TOML_MAY_THROW
|
||||
|
||||
@@ -82,9 +82,9 @@ namespace toml
|
||||
|
||||
/// \brief Checks if a node is a specific type.
|
||||
///
|
||||
/// \tparam T The
|
||||
/// \tparam T A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if this node is an instance
|
||||
/// \returns Returns true if this node is an instance of the specified type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool is() const noexcept
|
||||
|
||||
@@ -3,191 +3,173 @@
|
||||
#include "toml_array.h"
|
||||
#include "toml_value.h"
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename T>
|
||||
struct node_view_traits;
|
||||
|
||||
template <>
|
||||
struct node_view_traits<const table>
|
||||
{
|
||||
using haystack_type = const table*;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static const node* get(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<U>(key);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct node_view_traits<table>
|
||||
{
|
||||
using haystack_type = table*;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static node* get(table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static node_of<T>* as(table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<T>(key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static const node_of<T>* as(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<T>(key);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename K>
|
||||
struct sub_view final { };
|
||||
|
||||
template <typename T>
|
||||
struct node_view_traits<sub_view<T, string_view>>
|
||||
{
|
||||
using haystack_type = T;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static auto get(haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->get(key) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->get(key) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static auto as(haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->template get_as<U>(key) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->template get_as<U>(key) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct node_view_traits<sub_view<T, size_t>>
|
||||
{
|
||||
using haystack_type = T;
|
||||
using key_type = size_t;
|
||||
|
||||
[[nodiscard]] static auto get(haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->get(index) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->get(index) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static auto as(haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->template get_as<U>(index) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->template get_as<U>(index) : nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief A read-only view into a node.
|
||||
/// \brief A view of a node.
|
||||
///
|
||||
/// \detail A node_view is like a std::optional<toml::node> with lots of toml-specific stuff built-in.
|
||||
/// It _may_ represent a node, and allows you to do many of the same operations that you'd do
|
||||
/// on nodes directly, as well as easily traversing the node tree by creating
|
||||
/// subviews (via node_view::operator[]). \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
///
|
||||
/// title = "my hardware store"
|
||||
///
|
||||
/// [[products]]
|
||||
/// name = "Hammer"
|
||||
/// sku = 738594937
|
||||
/// keywords = [ "hammer", "construction", "build" ]
|
||||
///
|
||||
/// \warning This type is experimental. Functionality may change radically between versions
|
||||
/// until I decide that I'm happy with it. Use it at your own risk.
|
||||
/// [[products]]
|
||||
/// name = "Nail"
|
||||
/// sku = 284758393
|
||||
/// color = "gray"
|
||||
///
|
||||
/// )"sv);
|
||||
///
|
||||
/// std::cout << tbl["title"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["name"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["keywords"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["keywords"][2] << std::endl;
|
||||
///
|
||||
/// tbl["products"][0]["keywords"].as_array()->push_back("heavy");
|
||||
/// std::cout << tbl["products"][0]["keywords"] << std::endl;
|
||||
/// std::cout << "has third product: "sv << !!tbl["products"][2] << std::endl;
|
||||
/// std::cout << tbl["products"][2] << std::endl; // no-op
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// "my hardware store"
|
||||
/// "Hammer"
|
||||
/// [ "hammer", "construction", "build" ]
|
||||
/// [ "hammer", "construction", "build", "heavy" ]
|
||||
/// has third product: false
|
||||
/// \eout
|
||||
template <typename T>
|
||||
class node_view final
|
||||
{
|
||||
public:
|
||||
using traits = impl::node_view_traits<T>;
|
||||
using key_type = typename traits::key_type;
|
||||
using viewed_type = T;
|
||||
|
||||
private:
|
||||
using haystack_type = typename traits::haystack_type;
|
||||
haystack_type haystack_;
|
||||
key_type key_;
|
||||
friend class toml::table;
|
||||
|
||||
viewed_type* node_;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(viewed_type* node) noexcept
|
||||
: node_{ node }
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(haystack_type obj, key_type key) noexcept
|
||||
: haystack_{ obj },
|
||||
key_{ key }
|
||||
{}
|
||||
/// \brief Returns true if the view references a node.
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
|
||||
/// \brief Returns the node that's being referenced by the view.
|
||||
[[nodiscard]] viewed_type* get() noexcept { return node_; }
|
||||
/// \brief Returns the node that's being referenced by the view (const overload).
|
||||
[[nodiscard]] const viewed_type* get() const noexcept { return node_; }
|
||||
|
||||
[[nodiscard]] auto get() noexcept { return traits::get(haystack_, key_); }
|
||||
[[nodiscard]] const node* get() const noexcept { return traits::get(haystack_, key_); }
|
||||
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return !!get(); }
|
||||
/// \brief Returns the type identifier for the viewed node.
|
||||
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
|
||||
|
||||
/// \brief Returns true if the viewed node is a toml::table.
|
||||
[[nodiscard]] bool is_table() const noexcept { return type() == node_type::table; }
|
||||
/// \brief Returns true if the viewed node is a toml::array.
|
||||
[[nodiscard]] bool is_array() const noexcept { return type() == node_type::array; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<>.
|
||||
[[nodiscard]] bool is_value() const noexcept { return type() > node_type::array; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<string>.
|
||||
[[nodiscard]] bool is_string() const noexcept { return type() == node_type::string; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
|
||||
[[nodiscard]] bool is_integer() const noexcept { return type() == node_type::integer; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<double>.
|
||||
[[nodiscard]] bool is_floating_point() const noexcept { return type() == node_type::floating_point; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<bool>.
|
||||
[[nodiscard]] bool is_boolean() const noexcept { return type() == node_type::boolean; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<date>.
|
||||
[[nodiscard]] bool is_date() const noexcept { return type() == node_type::date; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<time>.
|
||||
[[nodiscard]] bool is_time() const noexcept { return type() == node_type::time; }
|
||||
/// \brief Returns true if the viewed node is a toml::value<date_time>.
|
||||
[[nodiscard]] bool is_date_time() const noexcept { return type() == node_type::date_time; }
|
||||
|
||||
/// \brief Returns true if the viewed node is a toml::array that contains only tables.
|
||||
[[nodiscard]] bool is_array_of_tables() const noexcept
|
||||
{
|
||||
return node_ ? node_->is_array_of_tables() : false;
|
||||
}
|
||||
|
||||
/// \brief Checks if this view references a node of a specific type.
|
||||
///
|
||||
/// \tparam U A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if the viewed node is an instance of the specified type.
|
||||
///
|
||||
/// \see toml::node::is()
|
||||
template <typename U>
|
||||
[[nodiscard]] auto as() noexcept
|
||||
[[nodiscard]]
|
||||
bool is() const noexcept
|
||||
{
|
||||
return node_ ? node_->template is<U>() : false;
|
||||
}
|
||||
|
||||
/// \brief Gets a pointer to the viewed node as a more specific node type.
|
||||
///
|
||||
/// \tparam U The node type or TOML value type to cast to.
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
|
||||
///
|
||||
/// \see toml::node::as()
|
||||
template <typename U>
|
||||
[[nodiscard]]
|
||||
auto as() noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return traits::template as<U>(haystack_, key_);
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Gets a pointer to the viewed node as a more specific node type (const overload).
|
||||
template <typename U>
|
||||
[[nodiscard]] const impl::node_of<U>* as() const noexcept
|
||||
[[nodiscard]]
|
||||
const impl::node_of<U>* as() const noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return traits::template as<U>(haystack_, key_);
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto as_string() noexcept { return as<string>(); }
|
||||
[[nodiscard]] auto as_integer() noexcept { return as<int64_t>(); }
|
||||
[[nodiscard]] auto as_floating_point() noexcept { return as<double>(); }
|
||||
[[nodiscard]] auto as_boolean() noexcept { return as<bool>(); }
|
||||
[[nodiscard]] auto as_date() noexcept { return as<date>(); }
|
||||
[[nodiscard]] auto as_time() noexcept { return as<time>(); }
|
||||
[[nodiscard]] auto as_date_time() noexcept { return as<date_time>(); }
|
||||
[[nodiscard]] auto as_array() noexcept { return as<array>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
|
||||
[[nodiscard]] auto as_table() noexcept { return as<table>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
|
||||
[[nodiscard]] auto as_array() noexcept { return as<array>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
|
||||
[[nodiscard]] auto as_string() noexcept { return as<string>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
|
||||
[[nodiscard]] auto as_integer() noexcept { return as<int64_t>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
|
||||
[[nodiscard]] auto as_floating_point() noexcept { return as<double>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
|
||||
[[nodiscard]] auto as_boolean() noexcept { return as<bool>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
|
||||
[[nodiscard]] auto as_date() noexcept { return as<date>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
|
||||
[[nodiscard]] auto as_time() noexcept { return as<time>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
|
||||
[[nodiscard]] auto as_date_time() noexcept { return as<date_time>(); }
|
||||
|
||||
[[nodiscard]] const table* as_table() const noexcept { return as<table>(); }
|
||||
[[nodiscard]] const array* as_array() const noexcept { return as<array>(); }
|
||||
[[nodiscard]] const value<string>* as_string() const noexcept { return as<string>(); }
|
||||
[[nodiscard]] const value<int64_t>* as_integer() const noexcept { return as<int64_t>(); }
|
||||
[[nodiscard]] const value<double>* as_floating_point() const noexcept { return as<double>(); }
|
||||
@@ -195,97 +177,174 @@ namespace toml
|
||||
[[nodiscard]] const value<date>* as_date() const noexcept { return as<date>(); }
|
||||
[[nodiscard]] const value<time>* as_time() const noexcept { return as<time>(); }
|
||||
[[nodiscard]] const value<date_time>* as_date_time() const noexcept { return as<date_time>(); }
|
||||
[[nodiscard]] const array* as_array() const noexcept { return as<array>(); }
|
||||
[[nodiscard]] const table* as_table() const noexcept { return as<table>(); }
|
||||
|
||||
private:
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static bool value_equality(const node_view& lhs, const U& rhs) noexcept
|
||||
template <typename N, typename FUNC>
|
||||
static decltype(auto) do_visit(N* node, FUNC&& visitor)
|
||||
TOML_MAY_THROW_UNLESS(noexcept(std::declval<N*>()->visit(std::declval<FUNC&&>())))
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && val->get() == rhs;
|
||||
using return_type = decltype(node->visit(std::forward<FUNC>(visitor)));
|
||||
if (node)
|
||||
return node->visit(std::forward<FUNC>(visitor));
|
||||
if constexpr (!std::is_void_v<return_type>)
|
||||
return return_type{};
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static bool container_equality(const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename U::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
const array* arr = lhs.as<array>();
|
||||
if (!arr || arr->size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = arr->get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || elem->get() != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
template <typename FUNC, typename N>
|
||||
static constexpr bool visit_is_nothrow =
|
||||
noexcept(do_visit(std::declval<N*>(), std::declval<FUNC&&>()));
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]] bool operator == (string_view rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int64_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int32_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int16_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int8_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint32_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint16_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint8_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (double rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (float rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (bool rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const date& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const time& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const date_time& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
/// \brief Invokes a visitor on the viewed node based on its concrete type.
|
||||
///
|
||||
/// \remarks Has no effect if the view does not reference a node.
|
||||
///
|
||||
/// \see node::visit()
|
||||
template <typename FUNC>
|
||||
decltype(auto) visit(FUNC&& visitor)
|
||||
TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, viewed_type>)
|
||||
{
|
||||
return do_visit(node_, std::forward<FUNC>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the viewed node based on its concrete type (const overload).
|
||||
///
|
||||
/// \remarks Has no effect if the view does not reference a node.
|
||||
///
|
||||
/// \see node::visit()
|
||||
template <typename FUNC>
|
||||
decltype(auto) visit(FUNC&& visitor) const
|
||||
TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, const viewed_type>)
|
||||
{
|
||||
return do_visit(node_, std::forward<FUNC>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Returns true if the viewed node is a table with the same contents as RHS.
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const table& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto tbl = lhs.as<table>();
|
||||
return tbl && *tbl == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, )
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as RHS.
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const array& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, )
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename U>
|
||||
[[nodiscard]] bool operator == (const std::initializer_list<U>& rhs) const noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
return container_equality(*this, rhs);
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto val = lhs.as<U>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const value<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view&,
|
||||
const U&,
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
)
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
|
||||
template <typename U>
|
||||
[[nodiscard]] bool operator == (const std::vector<U>& rhs) const noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::initializer_list<U>& rhs) noexcept
|
||||
{
|
||||
return container_equality(*this, rhs);
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS vector.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const U& lhs, const node_view& rhs) noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::vector<U>& rhs) noexcept
|
||||
{
|
||||
return rhs == lhs;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param key The key of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented a table and it contained a
|
||||
/// value at the given key, or an empty view.
|
||||
[[nodiscard]] node_view<viewed_type> operator[] (string_view key) noexcept
|
||||
{
|
||||
if (auto tbl = this->as_table())
|
||||
return { tbl->get(key) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
[[nodiscard]] node_view<impl::sub_view<node_view<T>, string_view>> operator[] (string_view key) noexcept
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param index The index of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented an array and it contained a
|
||||
/// value at the given index, or an empty view.
|
||||
[[nodiscard]] node_view<viewed_type> operator[] (size_t index) noexcept
|
||||
{
|
||||
return { *this, key };
|
||||
if (auto tbl = this->as_array())
|
||||
return { tbl->get(index) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
[[nodiscard]] node_view<impl::sub_view<node_view<T>, size_t>> operator[] (size_t index) noexcept
|
||||
/// \brief Returns a view of the selected subnode (const overload).
|
||||
[[nodiscard]] node_view<const viewed_type> operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { *this, index };
|
||||
if (auto tbl = this->as_table())
|
||||
return { tbl->get(key) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
/// \brief Returns a view of the selected subnode (const overload).
|
||||
[[nodiscard]] node_view<const viewed_type> operator[] (size_t index) const noexcept
|
||||
{
|
||||
if (auto tbl = this->as_array())
|
||||
return { tbl->get(index) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
|
||||
/// \brief Prints the viewed node out to a stream.
|
||||
template <typename CHAR>
|
||||
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view& nv) TOML_MAY_THROW
|
||||
{
|
||||
nv.visit([&](const auto& node) TOML_MAY_THROW
|
||||
{
|
||||
os << node;
|
||||
});
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
inline node_view<table> table::operator[] (string_view key) noexcept
|
||||
inline node_view<node> table::operator[] (string_view key) noexcept
|
||||
{
|
||||
return { this, key };
|
||||
return { this->get(key) };
|
||||
}
|
||||
|
||||
inline node_view<const table> table::operator[] (string_view key) const noexcept
|
||||
inline node_view<const node> table::operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { this, key };
|
||||
return { this->get(key) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,6 +597,7 @@ namespace toml::impl
|
||||
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
|
||||
@@ -612,6 +613,7 @@ namespace toml::impl
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
case U't': str += TOML_STRING_PREFIX('\t'); break;
|
||||
case U'"': str += TOML_STRING_PREFIX('"'); break;
|
||||
@@ -1925,7 +1927,8 @@ namespace toml::impl
|
||||
" offset; expected minute between 0 and 59 (inclusive), saw "sv, hour
|
||||
);
|
||||
|
||||
offset.emplace(time_offset{ static_cast<int16_t>((hour * 60 + minute) * sign) });
|
||||
offset.emplace();
|
||||
offset->minutes = static_cast<int16_t>((hour * 60 + minute) * sign);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1937,11 +1940,10 @@ namespace toml::impl
|
||||
);
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
return {
|
||||
date,
|
||||
time,
|
||||
offset
|
||||
};
|
||||
if (offset)
|
||||
return { date, time, *offset };
|
||||
else
|
||||
return { date, time };
|
||||
}
|
||||
|
||||
// TOML_DISABLE_SWITCH_WARNINGS
|
||||
|
||||
@@ -123,7 +123,6 @@ namespace toml
|
||||
{
|
||||
private:
|
||||
friend class impl::parser;
|
||||
friend class node_view<table>;
|
||||
|
||||
impl::string_map<std::unique_ptr<node>> values;
|
||||
bool inline_ = false;
|
||||
@@ -198,6 +197,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
table(const table&) = delete;
|
||||
table& operator= (const table&) = delete;
|
||||
|
||||
/// \brief Always returns `node_type::table` for table nodes.
|
||||
[[nodiscard]] node_type type() const noexcept override { return node_type::table; }
|
||||
/// \brief Always returns `true` for table nodes.
|
||||
@@ -256,17 +258,17 @@ namespace toml
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A node_view.
|
||||
/// \returns A view of the value at the given key if one existed, or an empty node view.
|
||||
///
|
||||
/// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
|
||||
/// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
|
||||
/// <strong>This is not an error.</strong>
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] inline node_view<table> operator[] (string_view key) noexcept;
|
||||
[[nodiscard]] inline node_view<node> operator[] (string_view key) noexcept;
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair (const overload).
|
||||
[[nodiscard]] inline node_view<const table> operator[] (string_view key) const noexcept;
|
||||
[[nodiscard]] inline node_view<const node> operator[] (string_view key) const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
[[nodiscard]] iterator begin() noexcept { return { values.begin() }; }
|
||||
@@ -302,7 +304,7 @@ namespace toml
|
||||
/// for (auto k : { "a", "d" })
|
||||
/// {
|
||||
/// auto result = tbl.insert(k, 42);
|
||||
/// std::cout << "inserted a value with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// std::cout << "inserted with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// }
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
@@ -310,8 +312,8 @@ namespace toml
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// inserted a value with key 'a': false
|
||||
/// inserted a value with key 'd': true
|
||||
/// inserted with key 'a': false
|
||||
/// inserted with key 'd': true
|
||||
/// { a = 1, b = 2, c = 3, d = 42 }
|
||||
/// \eout
|
||||
///
|
||||
@@ -365,7 +367,7 @@ namespace toml
|
||||
/// \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
|
||||
/// \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<
|
||||
@@ -449,7 +451,7 @@ namespace toml
|
||||
/// {
|
||||
/// // add a string using std::string's substring constructor
|
||||
/// auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5);
|
||||
/// std::cout << "emplaced a value with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// }
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
@@ -457,8 +459,8 @@ namespace toml
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// emplaced a value with key 'a': false
|
||||
/// emplaced a value with key 'd': true
|
||||
/// emplaced with key 'a': false
|
||||
/// emplaced with key 'd': true
|
||||
/// { a = 1, b = 2, c = 3, d = "drill" }
|
||||
/// \eout
|
||||
///
|
||||
|
||||
@@ -6,8 +6,6 @@ namespace toml
|
||||
{
|
||||
/// \brief A TOML value.
|
||||
///
|
||||
/// \extends ::toml::node
|
||||
///
|
||||
/// \tparam T The value's data type. Can be one of:
|
||||
/// - toml::string
|
||||
/// - int64_t
|
||||
@@ -69,6 +67,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
value(const value&) = delete;
|
||||
value& operator= (const value&) = delete;
|
||||
|
||||
/// \brief Returns the value's node type identifier.
|
||||
///
|
||||
/// \returns One of:
|
||||
@@ -195,12 +196,7 @@ namespace toml
|
||||
|
||||
/// \brief Value equality operator.
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ == rhs; }
|
||||
/// \brief Value equality operator.
|
||||
[[nodiscard]] friend bool operator == (value_arg_t lhs, const value& rhs) noexcept { return lhs == rhs.val_; }
|
||||
/// \brief Value inequality operator.
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ != rhs; }
|
||||
/// \brief Value inequality operator.
|
||||
[[nodiscard]] friend bool operator != (value_arg_t lhs, const value& rhs) noexcept { return lhs != rhs.val_; }
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg_t, )
|
||||
|
||||
/// \brief Value less-than operator.
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ < rhs; }
|
||||
@@ -244,10 +240,7 @@ namespace toml
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ != rhs.val_;
|
||||
else
|
||||
return true;
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#define TOML_LIB_MAJOR 0
|
||||
#define TOML_LIB_MINOR 1
|
||||
#define TOML_LIB_REVISION 0
|
||||
#define TOML_LIB_PATCH 0
|
||||
|
||||
#define TOML_LANG_MAJOR 0
|
||||
#define TOML_LANG_MINOR 5
|
||||
#define TOML_LANG_REVISION 0
|
||||
#define TOML_LANG_PATCH 0
|
||||
|
||||
@@ -13,7 +13,7 @@ project(
|
||||
compiler = meson.get_compiler('cpp')
|
||||
|
||||
if compiler.get_id() == 'gcc'
|
||||
add_project_arguments(['-fmax-errors=5', '-Wno-attributes'], language : 'cpp')
|
||||
add_project_arguments(['-fmax-errors=5', '-Wno-attributes', '-Wno-init-list-lifetime' ], language : 'cpp')
|
||||
endif
|
||||
|
||||
if compiler.get_id() == 'clang'
|
||||
|
||||
@@ -28,6 +28,7 @@ type_names = [
|
||||
'date',
|
||||
'time',
|
||||
'date_time',
|
||||
'time_offset',
|
||||
'string',
|
||||
'string_view',
|
||||
'string_char',
|
||||
@@ -844,11 +845,14 @@ def preprocess_xml(xml_dir):
|
||||
toml_value_text = read_all_text_from_file(toml_value_path)
|
||||
toml_value_search_string = '<compoundname>toml::value</compoundname>'
|
||||
toml_value_insert_pos = toml_value_text.find(toml_value_search_string)
|
||||
changed = False
|
||||
if (toml_value_insert_pos != -1):
|
||||
toml_value_insert_pos += len(toml_value_search_string)
|
||||
toml_value_text = toml_value_text[:toml_value_insert_pos] \
|
||||
+ '\n <basecompoundref refid="classtoml_1_1node" prot="public" virt="non-virtual">toml::node</basecompoundref>' \
|
||||
+ toml_value_text[toml_value_insert_pos:]
|
||||
changed = True
|
||||
if changed:
|
||||
with open(toml_value_path,'w', encoding='utf-8', newline='\n') as output_file:
|
||||
print(toml_value_text, file=output_file)
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ def main():
|
||||
match = re.search(r'^\s*#\s*define\s+TOML_LIB_MINOR\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
||||
if match is not None:
|
||||
library_version[1] = match.group(1)
|
||||
match = re.search(r'^\s*#\s*define\s+TOML_LIB_REVISION\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
||||
match = re.search(r'^\s*#\s*define\s+TOML_LIB_(?:REVISION|PATCH)\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
||||
if match is not None:
|
||||
library_version[2] = match.group(1)
|
||||
|
||||
|
||||
@@ -96,6 +96,23 @@ TEST_CASE("arrays - equality")
|
||||
{
|
||||
array arr1{ 1, 2, 3 };
|
||||
CHECK(arr1 == arr1);
|
||||
{
|
||||
auto ilist = { 1, 2, 3 };
|
||||
CHECK(arr1 == ilist);
|
||||
CHECK(ilist == arr1);
|
||||
|
||||
ilist = { 2, 3, 4 };
|
||||
CHECK(arr1 != ilist);
|
||||
CHECK(ilist != arr1);
|
||||
|
||||
auto ivec = std::vector{ 1, 2, 3 };
|
||||
CHECK(arr1 == ivec);
|
||||
CHECK(ivec == arr1);
|
||||
|
||||
ivec = std::vector{ 2, 3, 4 };
|
||||
CHECK(arr1 != ivec);
|
||||
CHECK(ivec != arr1);
|
||||
}
|
||||
|
||||
array arr2{ 1, 2, 3 };
|
||||
CHECK(arr1 == arr2);
|
||||
|
||||
@@ -18,13 +18,13 @@ lt2 = 00:32:00.999999
|
||||
)"sv),
|
||||
[](table&& tbl) noexcept
|
||||
{
|
||||
static constexpr auto odt1 = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset{} };
|
||||
static constexpr auto odt1 = date_time{ { 1979, 5, 27 }, { 7, 32 }, {} };
|
||||
CHECK(tbl[S("odt1")] == odt1);
|
||||
static constexpr auto odt2 = date_time{ { 1979, 5, 27 }, { 0, 32 }, time_offset::from_hh_mm(-7, 0) };
|
||||
static constexpr auto odt2 = date_time{ { 1979, 5, 27 }, { 0, 32 }, { -7, 0 } };
|
||||
CHECK(tbl[S("odt2")] == odt2);
|
||||
static constexpr auto odt3 = date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u }, time_offset::from_hh_mm(-7, 0) };
|
||||
static constexpr auto odt3 = date_time{ { 1979, 5, 27 }, { 0, 32, 0, 999999000u }, { -7, 0 } };
|
||||
CHECK(tbl[S("odt3")] == odt3);
|
||||
static constexpr auto odt4 = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset{} };
|
||||
static constexpr auto odt4 = date_time{ { 1979, 5, 27 }, { 7, 32 }, {} };
|
||||
CHECK(tbl[S("odt4")] == odt4);
|
||||
static constexpr auto ldt1 = date_time{ { 1979, 5, 27 }, { 7, 32 } };
|
||||
CHECK(tbl[S("ldt1")] == ldt1);
|
||||
@@ -49,12 +49,12 @@ lt2 = 00:32:00.999999
|
||||
parse_expected_value("1987-03-16 10:20:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, time_offset::from_hh_mm( -9, -30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, { -9, -30 } };
|
||||
parse_expected_value("1987-03-16T10:20:30-09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30-09:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, time_offset::from_hh_mm( 9, 30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, { 9, 30 } };
|
||||
parse_expected_value("1987-03-16T10:20:30+09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30+09:30"sv, val);
|
||||
}
|
||||
@@ -64,22 +64,22 @@ lt2 = 00:32:00.999999
|
||||
parse_expected_value("1987-03-16 10:20:30.04"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, time_offset::from_hh_mm( -9, -30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, { -9, -30 } };
|
||||
parse_expected_value("1987-03-16T10:20:30.04-09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30.04-09:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, time_offset::from_hh_mm( 9, 30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, { 9, 30 } };
|
||||
parse_expected_value("1987-03-16T10:20:30.04+09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30.04+09:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, time_offset{} };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30 }, {} };
|
||||
parse_expected_value("1987-03-16T10:20:30Z"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30Z"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, time_offset{} };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20, 30, 40000000 }, {} };
|
||||
parse_expected_value("1987-03-16T10:20:30.04Z"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20:30.04Z"sv, val);
|
||||
}
|
||||
@@ -94,17 +94,17 @@ lt2 = 00:32:00.999999
|
||||
parse_expected_value("1987-03-16 10:20"sv, val );
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, time_offset::from_hh_mm( -9, -30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, { -9, -30 } };
|
||||
parse_expected_value("1987-03-16T10:20-09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20-09:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, time_offset::from_hh_mm( 9, 30 ) };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, { 9, 30 } };
|
||||
parse_expected_value("1987-03-16T10:20+09:30"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20+09:30"sv, val);
|
||||
}
|
||||
{
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, time_offset{} };
|
||||
const auto val = date_time{ { 1987, 3, 16 }, { 10, 20 }, {} };
|
||||
parse_expected_value("1987-03-16T10:20Z"sv, val);
|
||||
parse_expected_value("1987-03-16 10:20Z"sv, val);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ hosts = [
|
||||
CHECK(tbl[S("owner")]);
|
||||
CHECK(tbl[S("owner")].as<table>());
|
||||
CHECK(tbl[S("owner")][S("name")] == S("Tom Preston-Werner"sv));
|
||||
const auto dob = date_time{ { 1979, 5, 27 }, { 7, 32 }, time_offset::from_hh_mm(-8, 0) };
|
||||
const auto dob = date_time{ { 1979, 5, 27 }, { 7, 32 }, { -8, 0 } };
|
||||
CHECK(tbl[S("owner")][S("dob")] == dob);
|
||||
|
||||
CHECK(tbl[S("database")].as<table>());
|
||||
|
||||
@@ -131,7 +131,7 @@ str = ''''That's still pointless', she said.'''
|
||||
S("\"\u03B1\u03B2\u03B3\""sv));
|
||||
|
||||
// toml/issues/622 - escaping alias for spaces
|
||||
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
|
||||
#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));
|
||||
|
||||
@@ -201,10 +201,28 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
|
||||
parsing_should_succeed(std::string_view{ value }, [&](table&& tbl) noexcept
|
||||
{
|
||||
CHECK(tbl.size() == 1);
|
||||
REQUIRE(tbl[S("val"sv)].as<impl::promoted<T>>());
|
||||
REQUIRE(tbl[S("val"sv)].get()->type() == impl::node_type_of<T>);
|
||||
CHECK(tbl[S("val"sv)].as<impl::promoted<T>>()->get() == expected);
|
||||
CHECK(tbl[S("val"sv)].get()->source().begin == begin);
|
||||
CHECK(tbl[S("val"sv)].get()->source().end == end);
|
||||
const auto nv = tbl[S("val"sv)];
|
||||
REQUIRE(nv);
|
||||
REQUIRE(nv.as<impl::promoted<T>>());
|
||||
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
|
||||
|
||||
//check the raw value
|
||||
CHECK(nv.as<impl::promoted<T>>()->get() == expected);
|
||||
|
||||
//check the value relops
|
||||
CHECK(*nv.as<impl::promoted<T>>() == expected);
|
||||
CHECK(expected == *nv.as<impl::promoted<T>>());
|
||||
CHECK(!(*nv.as<impl::promoted<T>>() != expected));
|
||||
CHECK(!(expected != *nv.as<impl::promoted<T>>()));
|
||||
|
||||
//check the node_view relops
|
||||
CHECK(nv == expected);
|
||||
CHECK(expected == nv);
|
||||
CHECK(!(nv != expected));
|
||||
CHECK(!(expected != nv));
|
||||
|
||||
//make sure source info is correct
|
||||
CHECK(nv.get()->source().begin == begin);
|
||||
CHECK(nv.get()->source().end == end);
|
||||
});
|
||||
}
|
||||
|
||||
490
toml.hpp
490
toml.hpp
@@ -154,6 +154,10 @@
|
||||
#define TOML_INTERFACE __declspec(novtable)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#ifndef __cpp_exceptions
|
||||
@@ -178,6 +182,10 @@
|
||||
#define TOML_USE_STREAMS_FOR_FLOATS 1
|
||||
#endif
|
||||
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOML_CPP_VERSION
|
||||
@@ -273,24 +281,35 @@
|
||||
#ifndef TOML_NODISCARD_CTOR
|
||||
#define TOML_NODISCARD_CTOR
|
||||
#endif
|
||||
#ifndef TOML_RELOPS_REORDERING
|
||||
#define TOML_RELOPS_REORDERING 0
|
||||
#endif
|
||||
#if TOML_RELOPS_REORDERING
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(...)
|
||||
#else
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator == (RHS rhs, LHS lhs) noexcept { return lhs == rhs; } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
|
||||
#endif
|
||||
|
||||
#define TOML_LIB_MAJOR 0
|
||||
#define TOML_LIB_MINOR 1
|
||||
#define TOML_LIB_REVISION 0
|
||||
#define TOML_LIB_PATCH 0
|
||||
|
||||
#define TOML_LANG_MAJOR 0
|
||||
#define TOML_LANG_MINOR 5
|
||||
#define TOML_LANG_REVISION 0
|
||||
#define TOML_LANG_PATCH 0
|
||||
|
||||
#define TOML_MAKE_VERSION(maj, min, rev) \
|
||||
((maj) * 1000 + (min) * 25 + (rev))
|
||||
|
||||
#if TOML_UNRELEASED_FEATURES
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION+1)
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
|
||||
#else
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION)
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
#endif
|
||||
|
||||
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
|
||||
@@ -375,6 +394,7 @@ namespace toml
|
||||
|
||||
enum class node_type : uint8_t
|
||||
{
|
||||
none,
|
||||
table,
|
||||
array,
|
||||
string,
|
||||
@@ -682,7 +702,7 @@ namespace toml::impl
|
||||
template <> struct node_type_of_<date_time> { static constexpr auto value = node_type::date_time; };
|
||||
|
||||
template <typename T>
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<T>::type>>::value;
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<remove_cvref_t<T>>::type>>::value;
|
||||
|
||||
inline constexpr toml::string_view low_character_escape_table[] =
|
||||
{
|
||||
@@ -722,6 +742,7 @@ namespace toml::impl
|
||||
|
||||
inline constexpr std::string_view node_type_friendly_names[] =
|
||||
{
|
||||
"none"sv,
|
||||
"table"sv,
|
||||
"array"sv,
|
||||
"string"sv,
|
||||
@@ -768,6 +789,8 @@ namespace toml
|
||||
template <typename T>
|
||||
inline constexpr bool is_floating_point = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<double>>;
|
||||
template <typename T>
|
||||
inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
|
||||
template <typename T>
|
||||
inline constexpr bool is_boolean = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<bool>>;
|
||||
template <typename T>
|
||||
inline constexpr bool is_date = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<date>>;
|
||||
@@ -867,11 +890,15 @@ namespace toml
|
||||
{
|
||||
int16_t minutes;
|
||||
|
||||
[[nodiscard]]
|
||||
static constexpr time_offset from_hh_mm(int8_t hours, int8_t minutes) noexcept
|
||||
{
|
||||
return time_offset{ static_cast<int16_t>(hours * 60 + minutes) };
|
||||
}
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset() noexcept
|
||||
: minutes{}
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset(int8_t hours, int8_t minutes) noexcept
|
||||
: minutes{ static_cast<int16_t>(hours * 60 + minutes) }
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
|
||||
@@ -900,6 +927,25 @@ namespace toml
|
||||
toml::time time;
|
||||
std::optional<toml::time_offset> time_offset;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time() noexcept
|
||||
: date{},
|
||||
time{}
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t) noexcept
|
||||
: date{ d },
|
||||
time{ t }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t, toml::time_offset offset) noexcept
|
||||
: date{ d },
|
||||
time{ t },
|
||||
time_offset{ offset }
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool is_local() const noexcept
|
||||
{
|
||||
@@ -1628,6 +1674,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
value(const value&) = delete;
|
||||
value& operator= (const value&) = delete;
|
||||
|
||||
[[nodiscard]] node_type type() const noexcept override { return impl::node_type_of<T>; }
|
||||
[[nodiscard]] bool is_table() const noexcept override { return false; }
|
||||
[[nodiscard]] bool is_array() const noexcept override { return false; }
|
||||
@@ -1704,9 +1753,7 @@ namespace toml
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ == rhs; }
|
||||
[[nodiscard]] friend bool operator == (value_arg_t lhs, const value& rhs) noexcept { return lhs == rhs.val_; }
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ != rhs; }
|
||||
[[nodiscard]] friend bool operator != (value_arg_t lhs, const value& rhs) noexcept { return lhs != rhs.val_; }
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg_t, )
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ < rhs; }
|
||||
[[nodiscard]] friend bool operator < (value_arg_t lhs, const value& rhs) noexcept { return lhs < rhs.val_; }
|
||||
[[nodiscard]] friend bool operator <= (const value& lhs, value_arg_t rhs) noexcept { return lhs.val_ <= rhs; }
|
||||
@@ -1728,10 +1775,7 @@ namespace toml
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ != rhs.val_;
|
||||
else
|
||||
return true;
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
@@ -1980,7 +2024,6 @@ namespace toml::impl
|
||||
namespace toml
|
||||
{
|
||||
[[nodiscard]] bool operator == (const table& lhs, const table& rhs) noexcept;
|
||||
[[nodiscard]] bool operator != (const table& lhs, const table& rhs) noexcept;
|
||||
|
||||
class array final
|
||||
: public node
|
||||
@@ -2042,6 +2085,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
array(const array&) = delete;
|
||||
array& operator= (const array&) = delete;
|
||||
|
||||
[[nodiscard]] node_type type() const noexcept override { return node_type::array; }
|
||||
[[nodiscard]] bool is_table() const noexcept override { return false; }
|
||||
[[nodiscard]] bool is_array() const noexcept override { return true; }
|
||||
@@ -2266,6 +2312,31 @@ namespace toml
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = lhs.get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || *elem != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t total_leaf_count() const noexcept
|
||||
{
|
||||
size_t leaves{};
|
||||
@@ -2295,6 +2366,19 @@ namespace toml
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::initializer_list<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>)
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::vector<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>)
|
||||
void flatten() TOML_MAY_THROW
|
||||
{
|
||||
if (values.empty())
|
||||
@@ -2468,7 +2552,6 @@ namespace toml
|
||||
{
|
||||
private:
|
||||
friend class impl::parser;
|
||||
friend class node_view<table>;
|
||||
|
||||
impl::string_map<std::unique_ptr<node>> values;
|
||||
bool inline_ = false;
|
||||
@@ -2509,6 +2592,9 @@ namespace toml
|
||||
return *this;
|
||||
}
|
||||
|
||||
table(const table&) = delete;
|
||||
table& operator= (const table&) = delete;
|
||||
|
||||
[[nodiscard]] node_type type() const noexcept override { return node_type::table; }
|
||||
[[nodiscard]] bool is_table() const noexcept override { return true; }
|
||||
[[nodiscard]] bool is_array() const noexcept override { return false; }
|
||||
@@ -2517,8 +2603,8 @@ namespace toml
|
||||
[[nodiscard]] const table* as_table() const noexcept override { return this; }
|
||||
[[nodiscard]] bool is_inline() const noexcept { return inline_; }
|
||||
void is_inline(bool val) noexcept { inline_ = val; }
|
||||
[[nodiscard]] inline node_view<table> operator[] (string_view key) noexcept;
|
||||
[[nodiscard]] inline node_view<const table> operator[] (string_view key) const noexcept;
|
||||
[[nodiscard]] inline node_view<node> operator[] (string_view key) noexcept;
|
||||
[[nodiscard]] inline node_view<const node> operator[] (string_view key) const noexcept;
|
||||
[[nodiscard]] iterator begin() noexcept { return { values.begin() }; }
|
||||
[[nodiscard]] const_iterator begin() const noexcept { return { values.begin() }; }
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept { return { values.cbegin() }; }
|
||||
@@ -2713,176 +2799,79 @@ namespace toml
|
||||
//------------------------------------------------------------------------------------------ ↓ toml_node_view.h ------
|
||||
#pragma region
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename T>
|
||||
struct node_view_traits;
|
||||
|
||||
template <>
|
||||
struct node_view_traits<const table>
|
||||
{
|
||||
using haystack_type = const table*;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static const node* get(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<U>(key);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct node_view_traits<table>
|
||||
{
|
||||
using haystack_type = table*;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static node* get(table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get(key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static node_of<T>* as(table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<T>(key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static const node_of<T>* as(const table* tbl, key_type key) noexcept
|
||||
{
|
||||
return tbl->get_as<T>(key);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename K>
|
||||
struct sub_view final { };
|
||||
|
||||
template <typename T>
|
||||
struct node_view_traits<sub_view<T, string_view>>
|
||||
{
|
||||
using haystack_type = T;
|
||||
using key_type = string_view;
|
||||
|
||||
[[nodiscard]] static auto get(haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->get(key) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->get(key) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static auto as(haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->template get_as<U>(key) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const haystack_type& view, string_view key) noexcept
|
||||
{
|
||||
auto parent = view.as_table();
|
||||
return parent ? parent->template get_as<U>(key) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct node_view_traits<sub_view<T, size_t>>
|
||||
{
|
||||
using haystack_type = T;
|
||||
using key_type = size_t;
|
||||
|
||||
[[nodiscard]] static auto get(haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->get(index) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const node* get(const haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->get(index) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static auto as(haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->template get_as<U>(index) : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static const node_of<U>* as(const haystack_type& view, size_t index) noexcept
|
||||
{
|
||||
auto parent = view.as_array();
|
||||
return parent ? parent->template get_as<U>(index) : nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename T>
|
||||
class node_view final
|
||||
{
|
||||
public:
|
||||
using traits = impl::node_view_traits<T>;
|
||||
using key_type = typename traits::key_type;
|
||||
using viewed_type = T;
|
||||
|
||||
private:
|
||||
using haystack_type = typename traits::haystack_type;
|
||||
haystack_type haystack_;
|
||||
key_type key_;
|
||||
friend class toml::table;
|
||||
|
||||
viewed_type* node_;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(viewed_type* node) noexcept
|
||||
: node_{ node }
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(haystack_type obj, key_type key) noexcept
|
||||
: haystack_{ obj },
|
||||
key_{ key }
|
||||
{}
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
|
||||
[[nodiscard]] viewed_type* get() noexcept { return node_; }
|
||||
[[nodiscard]] const viewed_type* get() const noexcept { return node_; }
|
||||
|
||||
[[nodiscard]] auto get() noexcept { return traits::get(haystack_, key_); }
|
||||
[[nodiscard]] const node* get() const noexcept { return traits::get(haystack_, key_); }
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return !!get(); }
|
||||
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
|
||||
[[nodiscard]] bool is_table() const noexcept { return type() == node_type::table; }
|
||||
[[nodiscard]] bool is_array() const noexcept { return type() == node_type::array; }
|
||||
[[nodiscard]] bool is_value() const noexcept { return type() > node_type::array; }
|
||||
[[nodiscard]] bool is_string() const noexcept { return type() == node_type::string; }
|
||||
[[nodiscard]] bool is_integer() const noexcept { return type() == node_type::integer; }
|
||||
[[nodiscard]] bool is_floating_point() const noexcept { return type() == node_type::floating_point; }
|
||||
[[nodiscard]] bool is_boolean() const noexcept { return type() == node_type::boolean; }
|
||||
[[nodiscard]] bool is_date() const noexcept { return type() == node_type::date; }
|
||||
[[nodiscard]] bool is_time() const noexcept { return type() == node_type::time; }
|
||||
[[nodiscard]] bool is_date_time() const noexcept { return type() == node_type::date_time; }
|
||||
[[nodiscard]] bool is_array_of_tables() const noexcept
|
||||
{
|
||||
return node_ ? node_->is_array_of_tables() : false;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] auto as() noexcept
|
||||
[[nodiscard]]
|
||||
bool is() const noexcept
|
||||
{
|
||||
return node_ ? node_->template is<U>() : false;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]]
|
||||
auto as() noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return traits::template as<U>(haystack_, key_);
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] const impl::node_of<U>* as() const noexcept
|
||||
[[nodiscard]]
|
||||
const impl::node_of<U>* as() const noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return traits::template as<U>(haystack_, key_);
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto as_table() noexcept { return as<table>(); }
|
||||
[[nodiscard]] auto as_array() noexcept { return as<array>(); }
|
||||
[[nodiscard]] auto as_string() noexcept { return as<string>(); }
|
||||
[[nodiscard]] auto as_integer() noexcept { return as<int64_t>(); }
|
||||
[[nodiscard]] auto as_floating_point() noexcept { return as<double>(); }
|
||||
@@ -2890,8 +2879,8 @@ namespace toml
|
||||
[[nodiscard]] auto as_date() noexcept { return as<date>(); }
|
||||
[[nodiscard]] auto as_time() noexcept { return as<time>(); }
|
||||
[[nodiscard]] auto as_date_time() noexcept { return as<date_time>(); }
|
||||
[[nodiscard]] auto as_array() noexcept { return as<array>(); }
|
||||
[[nodiscard]] auto as_table() noexcept { return as<table>(); }
|
||||
[[nodiscard]] const table* as_table() const noexcept { return as<table>(); }
|
||||
[[nodiscard]] const array* as_array() const noexcept { return as<array>(); }
|
||||
[[nodiscard]] const value<string>* as_string() const noexcept { return as<string>(); }
|
||||
[[nodiscard]] const value<int64_t>* as_integer() const noexcept { return as<int64_t>(); }
|
||||
[[nodiscard]] const value<double>* as_floating_point() const noexcept { return as<double>(); }
|
||||
@@ -2899,98 +2888,141 @@ namespace toml
|
||||
[[nodiscard]] const value<date>* as_date() const noexcept { return as<date>(); }
|
||||
[[nodiscard]] const value<time>* as_time() const noexcept { return as<time>(); }
|
||||
[[nodiscard]] const value<date_time>* as_date_time() const noexcept { return as<date_time>(); }
|
||||
[[nodiscard]] const array* as_array() const noexcept { return as<array>(); }
|
||||
[[nodiscard]] const table* as_table() const noexcept { return as<table>(); }
|
||||
|
||||
private:
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static bool value_equality(const node_view& lhs, const U& rhs) noexcept
|
||||
template <typename N, typename FUNC>
|
||||
static decltype(auto) do_visit(N* node, FUNC&& visitor)
|
||||
TOML_MAY_THROW_UNLESS(noexcept(std::declval<N*>()->visit(std::declval<FUNC&&>())))
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && val->get() == rhs;
|
||||
using return_type = decltype(node->visit(std::forward<FUNC>(visitor)));
|
||||
if (node)
|
||||
return node->visit(std::forward<FUNC>(visitor));
|
||||
if constexpr (!std::is_void_v<return_type>)
|
||||
return return_type{};
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] static bool container_equality(const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename U::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
const array* arr = lhs.as<array>();
|
||||
if (!arr || arr->size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = arr->get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || elem->get() != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
template <typename FUNC, typename N>
|
||||
static constexpr bool visit_is_nothrow =
|
||||
noexcept(do_visit(std::declval<N*>(), std::declval<FUNC&&>()));
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]] bool operator == (string_view rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int64_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int32_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int16_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (int8_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint32_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint16_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (uint8_t rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (double rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (float rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (bool rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const date& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const time& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
[[nodiscard]] bool operator == (const date_time& rhs) const noexcept { return value_equality(*this, rhs); }
|
||||
template <typename FUNC>
|
||||
decltype(auto) visit(FUNC&& visitor)
|
||||
TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, viewed_type>)
|
||||
{
|
||||
return do_visit(node_, std::forward<FUNC>(visitor));
|
||||
}
|
||||
|
||||
template <typename FUNC>
|
||||
decltype(auto) visit(FUNC&& visitor) const
|
||||
TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, const viewed_type>)
|
||||
{
|
||||
return do_visit(node_, std::forward<FUNC>(visitor));
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const table& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto tbl = lhs.as<table>();
|
||||
return tbl && *tbl == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, )
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const array& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, )
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] bool operator == (const std::initializer_list<U>& rhs) const noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
return container_equality(*this, rhs);
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto val = lhs.as<U>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const value<U>&, template <typename U>)
|
||||
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view&,
|
||||
const U&,
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
)
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] bool operator == (const std::vector<U>& rhs) const noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::initializer_list<U>& rhs) noexcept
|
||||
{
|
||||
return container_equality(*this, rhs);
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<U>&, template <typename U>)
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const U& lhs, const node_view& rhs) noexcept
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::vector<U>& rhs) noexcept
|
||||
{
|
||||
return rhs == lhs;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<U>&, template <typename U>)
|
||||
[[nodiscard]] node_view<viewed_type> operator[] (string_view key) noexcept
|
||||
{
|
||||
if (auto tbl = this->as_table())
|
||||
return { tbl->get(key) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
[[nodiscard]] node_view<impl::sub_view<node_view<T>, string_view>> operator[] (string_view key) noexcept
|
||||
[[nodiscard]] node_view<viewed_type> operator[] (size_t index) noexcept
|
||||
{
|
||||
return { *this, key };
|
||||
if (auto tbl = this->as_array())
|
||||
return { tbl->get(index) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
[[nodiscard]] node_view<impl::sub_view<node_view<T>, size_t>> operator[] (size_t index) noexcept
|
||||
[[nodiscard]] node_view<const viewed_type> operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { *this, index };
|
||||
if (auto tbl = this->as_table())
|
||||
return { tbl->get(key) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
[[nodiscard]] node_view<const viewed_type> operator[] (size_t index) const noexcept
|
||||
{
|
||||
if (auto tbl = this->as_array())
|
||||
return { tbl->get(index) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view& nv) TOML_MAY_THROW
|
||||
{
|
||||
nv.visit([&](const auto& node) TOML_MAY_THROW
|
||||
{
|
||||
os << node;
|
||||
});
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
inline node_view<table> table::operator[] (string_view key) noexcept
|
||||
inline node_view<node> table::operator[] (string_view key) noexcept
|
||||
{
|
||||
return { this, key };
|
||||
return { this->get(key) };
|
||||
}
|
||||
|
||||
inline node_view<const table> table::operator[] (string_view key) const noexcept
|
||||
inline node_view<const node> table::operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { this, key };
|
||||
return { this->get(key) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5124,6 +5156,7 @@ namespace toml::impl
|
||||
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
|
||||
@@ -5139,6 +5172,7 @@ namespace toml::impl
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
case U't': str += TOML_STRING_PREFIX('\t'); break;
|
||||
case U'"': str += TOML_STRING_PREFIX('"'); break;
|
||||
@@ -6451,7 +6485,8 @@ namespace toml::impl
|
||||
" offset; expected minute between 0 and 59 (inclusive), saw "sv, hour
|
||||
);
|
||||
|
||||
offset.emplace(time_offset{ static_cast<int16_t>((hour * 60 + minute) * sign) });
|
||||
offset.emplace();
|
||||
offset->minutes = static_cast<int16_t>((hour * 60 + minute) * sign);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6462,11 +6497,10 @@ namespace toml::impl
|
||||
);
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
return {
|
||||
date,
|
||||
time,
|
||||
offset
|
||||
};
|
||||
if (offset)
|
||||
return { date, time, *offset };
|
||||
else
|
||||
return { date, time };
|
||||
}
|
||||
|
||||
// TOML_DISABLE_SWITCH_WARNINGS
|
||||
@@ -8447,6 +8481,8 @@ namespace toml
|
||||
#undef TOML_STRING_PREFIX
|
||||
#undef TOML_UNDEF_MACROS
|
||||
#undef TOML_DOXYGEN
|
||||
#undef TOML_RELOPS_REORDERING
|
||||
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
Reference in New Issue
Block a user