diff --git a/README.md b/README.md
index 9ae0c49b..710f35fc 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css
index 535053e5..f356340c 100644
--- a/docs/tomlplusplus.css
+++ b/docs/tomlplusplus.css
@@ -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;
}
diff --git a/include/toml++/toml.h b/include/toml++/toml.h
index cf112c7f..ea435f7d 100644
--- a/include/toml++/toml.h
+++ b/include/toml++/toml.h
@@ -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
///
-/// 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)!
+///////////////////////////////////////////////////////////////////////
///
+/// \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.
+///
+/// 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)!
+///
+///////////////////////////////////////////////////////////////////////
+///
+/// \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
+/// #include //required for parse_file()
/// #include
+/// 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
+/// #include //required for parse_file()
+/// #include
+/// 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
+/// #include
+/// 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 "]
+///
+/// [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 "]
+/// name = "toml++"
+/// version = "0.1.0"
+/// \eout
+/// \see toml::parse()
+///
+///////////////////////////////////
+///
+/// \subsection mainpage-example-manipulations Traversing and manipulating data
+///
+/// \cpp
+/// #include
+/// #include
+/// 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)
+/// (*n)++;
+/// else if constexpr (toml::is_string)
+/// n = "five"sv;
+/// });
+/// }
+/// numbers.as_array()->push_back(7);
+/// numbers.as_array()->emplace_back(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
+/// #include
+///
+/// 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"
+///
+/// ###### 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).
+///
///
diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h
index e597ff16..963a3141 100644
--- a/include/toml++/toml_array.h
+++ b/include/toml++/toml_array.h
@@ -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("arr");
@@ -196,9 +193,9 @@ namespace toml
/// {
/// arr[i].visit([=](auto&& el) noexcept
/// {
- /// if constexpr (toml::is_integer)
+ /// if constexpr (toml::is_number)
/// (*el)++;
- /// else
+ /// else if constexpr (toml::is_string)
/// 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
+ [[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept
+ {
+ using elem_t = std::remove_const_t;
+ static_assert(
+ impl::is_value_or_promotable,
+ "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>(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
+ [[nodiscard]] friend bool operator == (const array& lhs, const std::initializer_list& rhs) noexcept
+ {
+ return container_equality(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list&, template )
+
+ /// \brief Vector equality operator.
+ template
+ [[nodiscard]] friend bool operator == (const array& lhs, const std::vector& rhs) noexcept
+ {
+ return container_equality(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector&, template )
+
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
///
/// \detail \cpp
diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h
index d9b5d07f..c81acbd7 100644
--- a/include/toml++/toml_common.h
+++ b/include/toml++/toml_common.h
@@ -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.
@@ -745,7 +766,7 @@ namespace toml::impl
template <> struct node_type_of_ { static constexpr auto value = node_type::date_time; };
template
- inline constexpr auto node_type_of = node_type_of_::type>>::value;
+ inline constexpr auto node_type_of = node_type_of_>::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.
template
inline constexpr bool is_floating_point = std::is_same_v>, value>;
+ /// \brief Metafunction for determining if a type satisfies `toml::is_integer || toml::is_floating_point`.
+ template
+ inline constexpr bool is_number = is_integer || is_floating_point;
/// \brief Metafunction for determining if a type is a bool toml::value.
template
inline constexpr bool is_boolean = std::is_same_v>, value>;
diff --git a/include/toml++/toml_date_time.h b/include/toml++/toml_date_time.h
index 878fe977..6bf6bd5c 100644
--- a/include/toml++/toml_date_time.h
+++ b/include/toml++/toml_date_time.h
@@ -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
friend inline std::basic_ostream& operator << (std::basic_ostream& 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
friend inline std::basic_ostream& operator << (std::basic_ostream& 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(hours * 60 + minutes) };
- }
+ TOML_NODISCARD_CTOR
+ constexpr time_offset(int8_t hours, int8_t minutes) noexcept
+ : minutes{ static_cast(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
friend inline std::basic_ostream& operator << (std::basic_ostream& 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 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
friend inline std::basic_ostream& operator << (std::basic_ostream& lhs, const date_time& rhs)
TOML_MAY_THROW
diff --git a/include/toml++/toml_node.h b/include/toml++/toml_node.h
index 5e84b982..57224bb0 100644
--- a/include/toml++/toml_node.h
+++ b/include/toml++/toml_node.h
@@ -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
[[nodiscard]] TOML_ALWAYS_INLINE
bool is() const noexcept
diff --git a/include/toml++/toml_node_view.h b/include/toml++/toml_node_view.h
index 2d14aa79..d17d615c 100644
--- a/include/toml++/toml_node_view.h
+++ b/include/toml++/toml_node_view.h
@@ -3,191 +3,173 @@
#include "toml_array.h"
#include "toml_value.h"
-namespace toml::impl
-{
- template
- struct node_view_traits;
-
- template <>
- struct node_view_traits
- {
- 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
- [[nodiscard]] static const node_of* as(const table* tbl, key_type key) noexcept
- {
- return tbl->get_as(key);
- }
- };
-
- template <>
- struct node_view_traits
- {
- 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
- [[nodiscard]] static node_of* as(table* tbl, key_type key) noexcept
- {
- return tbl->get_as(key);
- }
-
- template
- [[nodiscard]] static const node_of* as(const table* tbl, key_type key) noexcept
- {
- return tbl->get_as(key);
- }
- };
-
- template
- struct sub_view final { };
-
- template
- struct node_view_traits>
- {
- 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
- [[nodiscard]] static auto as(haystack_type& view, string_view key) noexcept
- {
- auto parent = view.as_table();
- return parent ? parent->template get_as(key) : nullptr;
- }
-
- template
- [[nodiscard]] static const node_of* as(const haystack_type& view, string_view key) noexcept
- {
- auto parent = view.as_table();
- return parent ? parent->template get_as(key) : nullptr;
- }
- };
-
- template
- struct node_view_traits>
- {
- 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
- [[nodiscard]] static auto as(haystack_type& view, size_t index) noexcept
- {
- auto parent = view.as_array();
- return parent ? parent->template get_as(index) : nullptr;
- }
-
- template
- [[nodiscard]] static const node_of* as(const haystack_type& view, size_t index) noexcept
- {
- auto parent = view.as_array();
- return parent ? parent->template get_as(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 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
class node_view final
{
public:
- using traits = impl::node_view_traits;
- 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;
- public:
+ viewed_type* node_;
TOML_NODISCARD_CTOR
- node_view(haystack_type obj, key_type key) noexcept
- : haystack_{ obj },
- key_{ key }
+ node_view(viewed_type* node) noexcept
+ : node_{ node }
{}
- [[nodiscard]] auto get() noexcept { return traits::get(haystack_, key_); }
- [[nodiscard]] const node* get() const noexcept { return traits::get(haystack_, key_); }
+ public:
- [[nodiscard]] explicit operator bool() const noexcept { return !!get(); }
+ /// \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_; }
+
+
+ /// \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.
+ [[nodiscard]] bool is_string() const noexcept { return type() == node_type::string; }
+ /// \brief Returns true if the viewed node is a toml::value.
+ [[nodiscard]] bool is_integer() const noexcept { return type() == node_type::integer; }
+ /// \brief Returns true if the viewed node is a toml::value.
+ [[nodiscard]] bool is_floating_point() const noexcept { return type() == node_type::floating_point; }
+ /// \brief Returns true if the viewed node is a toml::value.
+ [[nodiscard]] bool is_boolean() const noexcept { return type() == node_type::boolean; }
+ /// \brief Returns true if the viewed node is a toml::value.
+ [[nodiscard]] bool is_date() const noexcept { return type() == node_type::date; }
+ /// \brief Returns true if the viewed node is a toml::value