added array::at() and table::at()

This commit is contained in:
Mark Gillard 2021-11-07 21:25:42 +02:00
parent 5e2ddc16c8
commit 76e681da4d
9 changed files with 531 additions and 404 deletions

View File

@ -17,53 +17,56 @@ template:
## Unreleased
This release will be a major version bump, so it's ABI breaks all around. Any API changes that might necessitate
code changes at callsites or in build systems are indicated with '️'.
code changes at callsites or in build systems are indicated with ⚠️.
#### Fixes:
- fixed `json_formatter` not formatting inf and nan incorrectly
- fixed `table` init-list constructor requiring double-brackets
- fixed `TOML_API` + extern templates causing linker errors in some circumstances
- fixed an illegal table redefinition edge case (#112) (@python36)
- fixed incorrect source position in redefinition error messages
- fixed documentation issues
- fixed some interfaces missing `TOML_API`
- fixed `toml::table` init-list constructor requiring double-brackets
- fixed incorrect `noexcept` specifications on many functions ⚠️
- fixed incorrect source position in redefinition error messages
- fixed missing `#include <initializer_list>`
- fixed missing `#include <utility>`
- fixed incorrect `noexcept` specifications on many functions ⚠&#xFE0F;
- fixed `TOML_API` + extern templates causing linker errors in some circumstances
- fixed inf and nan being formatted incorrectly by the `json_formatter`
- fixed missing `TOML_API` on interfaces
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
#### Additions:
- added support for Unicode 14.0
- added formatter indentation flags (#120) (@W4RH4WK)
- added value flags to array + table insert methods (#44) (@levicki)
- added magic `value_flags` constant `preserve_source_value_flags`
- added clang's enum annotation attributes to all enums
- added `formatter_flags::quote_infinities_and_nans`
- added `TOML_ENABLE_FORMATTERS` option
- added `default_init_flags` param to `array::resize()`
- added `toml::yaml_formatter`
- added `operator->` to `toml::value` for class types
- added `parse_benchmark` example
- added `array::at()` and `table::at()`
- added `array::replace()` (#109) (#LebJe)
- added `default_init_flags` param to `array::resize()`
- added `formatter_flags::quote_infinities_and_nans`
- added `operator->` to `value` for class types
- added `parse_benchmark` example
- added `TOML_ENABLE_FORMATTERS` option
- added `yaml_formatter`
- added clang's enum annotation attributes to all enums
- added formatter indentation flags (#120) (@W4RH4WK)
- added magic `value_flags` constant `preserve_source_value_flags`
- added support for Unicode 14.0
- added value flags to array + table insert methods (#44) (@levicki)
#### Changes:
- moved all implementation headers to `/impl`
- improved performance of parser's internal UTF-8 stream decoder
- made date/time constructors accept any integral types
- made all overloaded operators 'hidden friends' where possible
- renamed all implementation headers to `.h` and 'source' headers to `.inl`
- renamed `default_formatter` to `toml_formatter` (`default_formatter` is now an alias)
- `format_flags` is now backed by `uint64_t` (was previously `uint8_t`) ⚠&#xFE0F;
- `source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`) ⚠&#xFE0F;
- `value_flags` is now backed by `uint16_t` (was previously `uint8_t`) ⚠&#xFE0F;
- applied clang-format to all the things 🎉&#xFE0F;
- improved performance of parser's internal UTF-8 stream decoder
- made all overloaded operators 'hidden friends' where possible ⚠&#xFE0F;
- made date/time constructors accept any integral types
- moved all implementation headers to `/impl`
- renamed `default_formatter` to `toml_formatter` (`default_formatter` is now an alias)
- renamed all implementation headers to `.h` and 'source' headers to `.inl`
- updated conformance tests
#### Removals and Deprecations:
- removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_PARSER` to `0` will invoke an `#error`) ⚠&#xFE0F;
- renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated) ⚠&#xFE0F;
- renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated) ⚠&#xFE0F;
- renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated) ⚠&#xFE0F;
- removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_LARGE_FILES` to `0` will invoke an `#error`) ⚠&#xFE0F;
- removed unnecessary template machinery (esp. where ostreams were involved)
- removed unnecessary uses of `final`
- renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated) ⚠&#xFE0F;
- renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated) ⚠&#xFE0F;
- renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated) ⚠&#xFE0F;
#### Build system:
- disabled 'install' path when being used as a meson subproject (#114) (@Tachi107)

View File

@ -145,7 +145,7 @@ won't need to mess with these at all, but if you do, set them before including t
| `TOML_CONFIG_HEADER` | string literal | Includes the given header file before the rest of the library. | undefined |
| `TOML_ENABLE_FORMATTERS` | boolean | Enables the formatters. Set to `0` if you don't need them to improve compile times and binary size. | `1` |
| `TOML_ENABLE_PARSER` | boolean | Enables the parser. Set to `0` if you don't need it to improve compile times and binary size. | `1` |
| `TOML_ENABLE_UNRELEASED_FEATURES` | boolean | Enables support for [unreleased TOML language features. | `0` |
| `TOML_ENABLE_UNRELEASED_FEATURES` | boolean | Enables support for [unreleased TOML language features]. | `0` |
| `TOML_ENABLE_WINDOWS_COMPAT` | boolean | Enables support for transparent conversion between wide and narrow strings. | `1` on Windows |
| `TOML_EXCEPTIONS` | boolean | Sets whether the library uses exceptions. | per compiler settings |
| `TOML_HEADER_ONLY` | boolean | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library).| `1` |
@ -167,7 +167,7 @@ support for a number of unreleased features from the [TOML master] and some sane
The library advertises the most recent numbered language version it fully supports via the preprocessor
defines `TOML_LANG_MAJOR`, `TOML_LANG_MINOR` and `TOML_LANG_PATCH`.
### 🔸&#xFE0F; **Unreleased language features:**
### **Unreleased language features:**
- [#516]: Allow newlines and trailing commas in inline tables
- [#562]: Allow hex floating-point values
- [#644]: Support `+` in key names
@ -238,7 +238,7 @@ though you're welcome to reach out via other means. In order of likely response
[API documentation]: https://marzer.github.io/tomlplusplus/
[homepage]: https://marzer.github.io/tomlplusplus/
[unreleased TOML language features]: #-unreleased-language-features
[unreleased TOML language features]: #unreleased-language-features
[most recently-released version]: https://github.com/toml-lang/toml/releases
[numbered version]: https://github.com/toml-lang/toml/releases
[char8_t]: https://en.cppreference.com/w/cpp/keyword/char8_t

View File

@ -646,6 +646,28 @@ TOML_NAMESPACE_START
return *elems_[index];
}
#if TOML_COMPILER_EXCEPTIONS
/// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions enabled.
TOML_NODISCARD
node& at(size_t index)
{
return *elems_.at(index);
}
/// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions enabled.
TOML_NODISCARD
const node& at(size_t index) const
{
return *elems_.at(index);
}
#endif // TOML_COMPILER_EXCEPTIONS
/// \brief Returns a reference to the first element in the array.
TOML_NODISCARD
node& front() noexcept

View File

@ -25,7 +25,6 @@ TOML_NAMESPACE_START
/// std::cout << "The node 'description' was defined at "sv
/// << table.get("description")->source().begin()
/// << "\n";
///
/// \ecpp
///
/// \out
@ -33,8 +32,8 @@ TOML_NAMESPACE_START
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// various non-conventional whitespace and newline characters, but it doesn't give
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
@ -93,7 +92,6 @@ TOML_NAMESPACE_START
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source().begin()
/// << "\n";
///
/// \ecpp
///
/// \out
@ -121,7 +119,6 @@ TOML_NAMESPACE_START
/// std::cout << "end: "sv << server->source().end << "\n";
/// std::cout << "path: "sv << *server->source().path << "\n";
/// }
///
/// \ecpp
///
/// \out
@ -131,8 +128,8 @@ TOML_NAMESPACE_START
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// various non-conventional whitespace and newline characters, but it doesn't give
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
@ -159,7 +156,7 @@ TOML_NAMESPACE_START
///
/// \remarks This will return an empty optional if no path was provided to toml::parse().
TOML_NODISCARD
optional<std::wstring> wide_path() const noexcept
optional<std::wstring> wide_path() const
{
if (!path || path->empty())
return {};
@ -176,7 +173,6 @@ TOML_NAMESPACE_START
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source()
/// << "\n";
///
/// \ecpp
///
/// \out

View File

@ -235,47 +235,6 @@ TOML_NAMESPACE_START
TOML_API
table(const impl::table_init_pair*, const impl::table_init_pair*);
template <typename Map, typename Key>
TOML_NODISCARD
static auto do_get(Map& vals, const Key& key) noexcept(!impl::is_wide_string<Key>)
-> std::conditional_t<std::is_const_v<Map>, const node*, node*>
{
static_assert(!impl::is_wide_string<Key> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieval using wide-character keys is only supported on Windows with "
"TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (impl::is_wide_string<Key>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
return do_get(vals, impl::narrow(key));
#else
static_assert(impl::dependent_false<Key>, "Evaluated unreachable branch!");
#endif
}
else
{
if (auto it = vals.find(key); it != vals.end())
return { it->second.get() };
return {};
}
}
template <typename T, typename Map, typename Key>
TOML_NODISCARD
static auto do_get_as(Map& vals, const Key& key) noexcept
{
const auto node = do_get(vals, key);
return node ? node->template as<T>() : nullptr;
}
template <typename Map, typename Key>
TOML_NODISCARD
TOML_ALWAYS_INLINE
static bool do_contains(Map& vals, const Key& key) noexcept
{
return do_get(vals, key) != nullptr;
}
/// \endcond
public:
@ -608,7 +567,7 @@ TOML_NAMESPACE_START
///
/// \remarks Runtime-constructed tables (i.e. those not created during
/// parsing) are not inline by default.
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
bool is_inline() const noexcept
{
return inline_;
@ -660,85 +619,191 @@ TOML_NAMESPACE_START
/// @}
/// \name Node views
/// \name Value retrieval
/// @{
/// \brief Gets a node_view for the selected key-value pair.
/// \brief Gets the node at a specific key.
///
/// \param key The key used for the lookup.
/// \detail \cpp
/// auto tbl = toml::table{
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// };
/// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << "\n";
/// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << "\n";
/// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << "\n";
/// if (auto val = arr.get("a"))
/// std::cout << R"(node ["a"] was an )"sv << val->type() << "\n";
///
/// \returns A view of the value at the given key if one existed, or an empty node view.
/// \ecpp
///
/// \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>
/// \out
/// node ["a"] exists: true
/// node ["b"] exists: true
/// node ["c"] exists: false
/// node ["a"] was an integer
/// \eout
///
/// \see toml::node_view
TOML_NODISCARD
node_view<node> operator[](std::string_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key, or nullptr.
TOML_PURE_GETTER
TOML_API
node* get(std::string_view key) noexcept;
/// \brief Gets a node_view for the selected key-value pair (const overload).
/// \brief Gets the node at a specific key (const overload).
///
/// \param key The key used for the lookup.
/// \param key The node's key.
///
/// \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
TOML_NODISCARD
node_view<const node> operator[](std::string_view key) const noexcept
/// \returns A pointer to the node at the specified key, or nullptr.
TOML_PURE_INLINE_GETTER
const node* get(std::string_view key) const noexcept
{
return node_view<const node>{ this->get(key) };
return const_cast<table&>(*this).get(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets a node_view for the selected key-value pair.
/// \brief Gets the node at a specific key.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
/// \param key The node's key.
///
/// \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
/// \returns A pointer to the node at the specified key, or nullptr.
TOML_NODISCARD
node_view<node> operator[](std::wstring_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
TOML_API
node* get(std::wstring_view key);
/// \brief Gets a node_view for the selected key-value pair (const overload).
/// \brief Gets the node at a specific key (const overload).
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
/// \param key The node's key.
///
/// \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
/// \returns A pointer to the node at the specified key, or nullptr.
TOML_NODISCARD
node_view<const node> operator[](std::wstring_view key) const noexcept
const node* get(std::wstring_view key) const
{
return node_view<const node>{ this->get(key) };
return const_cast<table&>(*this).get(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \detail \cpp
/// auto tbl = toml::table{
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// };
/// if (auto val = arr.get_as<int64_t>("a"))
/// std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n";
///
/// \ecpp
///
/// \out
/// node ["a"] was an integer with value 42
/// \eout
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_PURE_GETTER
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
const auto n = this->get(key);
return n ? n->template as<ValueType>() : nullptr;
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_PURE_GETTER
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return const_cast<table&>(*this).template get_as<ValueType>(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::wstring_view key)
{
return get_as<ValueType>(impl::narrow(key));
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const
{
return const_cast<table&>(*this).template get_as<ValueType>(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#if TOML_COMPILER_EXCEPTIONS
/// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions enabled.
TOML_NODISCARD
TOML_API
node& at(std::string_view key);
/// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions enabled.
TOML_NODISCARD
const node& at(std::string_view key) const
{
return const_cast<table&>(*this).at(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions and #TOML_ENABLE_WINDOWS_COMPAT enabled.
TOML_NODISCARD
TOML_API
node& at(std::wstring_view key);
/// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
///
/// \availability This function is only available if you compile with exceptions and #TOML_ENABLE_WINDOWS_COMPAT enabled.
TOML_NODISCARD
const node& at(std::wstring_view key) const
{
return const_cast<table&>(*this).at(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#endif // TOML_COMPILER_EXCEPTIONS
/// @}
/// \name Table operations
@ -1284,7 +1349,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
bool contains(std::string_view key) const noexcept
{
return do_contains(map_, key);
return get(key) != nullptr;
}
#if TOML_ENABLE_WINDOWS_COMPAT
@ -1328,151 +1393,81 @@ TOML_NAMESPACE_START
/// @}
/// \name Value retrieval
/// \name Node views
/// @{
/// \brief Gets the node at a specific key.
/// \brief Gets a node_view for the selected key-value pair.
///
/// \detail \cpp
/// auto tbl = toml::table{
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// };
/// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << "\n";
/// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << "\n";
/// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << "\n";
/// if (auto val = arr.get("a"))
/// std::cout << R"(node ["a"] was an )"sv << val->type() << "\n";
/// \param key The key used for the lookup.
///
/// \ecpp
/// \returns A view of the value at the given key if one existed, or an empty node view.
///
/// \out
/// node ["a"] exists: true
/// node ["b"] exists: true
/// node ["c"] exists: false
/// node ["a"] was an integer
/// \eout
/// \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>
///
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key, or nullptr.
/// \see toml::node_view
TOML_NODISCARD
node* get(std::string_view key) noexcept
node_view<node> operator[](std::string_view key) noexcept
{
return do_get(map_, key);
return node_view<node>{ get(key) };
}
/// \brief Gets the node at a specific key (const overload).
/// \brief Gets a node_view for the selected key-value pair (const overload).
///
/// \param key The node's key.
/// \param key The key used for the lookup.
///
/// \returns A pointer to the node at the specified key, or nullptr.
/// \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
TOML_NODISCARD
const node* get(std::string_view key) const noexcept
node_view<const node> operator[](std::string_view key) const noexcept
{
return do_get(map_, key);
return node_view<const node>{ get(key) };
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets the node at a specific key.
/// \brief Gets a node_view for the selected key-value pair.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The node's key.
/// \param key The key used for the lookup.
///
/// \returns A pointer to the node at the specified key, or nullptr.
/// \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
TOML_NODISCARD
node* get(std::wstring_view key)
node_view<node> operator[](std::wstring_view key) noexcept
{
return get(impl::narrow(key));
return node_view<node>{ get(key) };
}
/// \brief Gets the node at a specific key (const overload).
/// \brief Gets a node_view for the selected key-value pair (const overload).
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The node's key.
/// \param key The key used for the lookup.
///
/// \returns A pointer to the node at the specified key, or nullptr.
/// \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
TOML_NODISCARD
const node* get(std::wstring_view key) const
node_view<const node> operator[](std::wstring_view key) const noexcept
{
return get(impl::narrow(key));
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \detail \cpp
/// auto tbl = toml::table{
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// };
/// if (auto val = arr.get_as<int64_t>("a"))
/// std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n";
///
/// \ecpp
///
/// \out
/// node ["a"] was an integer with value 42
/// \eout
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
return do_get_as<ValueType>(map_, key);
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return do_get_as<ValueType>(map_, key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::wstring_view key)
{
return get_as<ValueType>(impl::narrow(key));
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const
{
return get_as<ValueType>(impl::narrow(key));
return node_view<const node>{ get(key) };
}
#endif // TOML_ENABLE_WINDOWS_COMPAT

View File

@ -15,33 +15,6 @@
#include "node_view.h"
#include "header_start.h"
TOML_ANON_NAMESPACE_START
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool table_is_homogeneous(T & map, node_type ntype, U & first_nonmatch) noexcept
{
if (map.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
}
TOML_ANON_NAMESPACE_END;
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
@ -132,15 +105,79 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
{
return TOML_ANON_NAMESPACE::table_is_homogeneous(map_, ntype, first_nonmatch);
if (map_.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map_.cbegin()->second->type();
for (const auto& [k, v] : map_)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
{
return TOML_ANON_NAMESPACE::table_is_homogeneous(map_, ntype, first_nonmatch);
node* fnm = nullptr;
const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
first_nonmatch = fnm;
return result;
}
TOML_EXTERNAL_LINKAGE
node* table::get(std::string_view key) noexcept
{
if (auto it = map_.find(key); it != map_.end())
return it->second.get();
return nullptr;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node* table::get(std::wstring_view key)
{
return get(impl::narrow(key));
}
#endif
#if TOML_COMPILER_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
node& table::at(std::string_view key)
{
auto n = get(key);
if (!n)
{
auto err = "key '"s;
err.append(key);
err.append("' not found in table"sv);
throw std::out_of_range{ err };
}
return *n;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node& table::at(std::wstring_view key)
{
return at(impl::narrow(key));
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#endif // TOML_COMPILER_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
bool table::equal(const table& lhs, const table& rhs) noexcept
{

View File

@ -178,9 +178,28 @@ TEST_CASE("arrays - construction")
CHECK(arr.cbegin() != arr.cend());
REQUIRE(arr.get_as<int64_t>(0u));
CHECK(*arr.get_as<int64_t>(0u) == 42);
CHECK(arr.get(0u) == &arr[0u]);
CHECK(arr.is_homogeneous());
CHECK(arr.is_homogeneous<int64_t>());
CHECK(!arr.is_homogeneous<double>());
#if TOML_COMPILER_EXCEPTIONS
CHECK(arr.get(0u) == &arr.at(0u));
#endif
const array& carr = arr;
CHECK(carr.size() == 1u);
CHECK(!carr.empty());
CHECK(carr.begin() != carr.end());
CHECK(carr.cbegin() != carr.cend());
REQUIRE(carr.get_as<int64_t>(0u));
CHECK(*carr.get_as<int64_t>(0u) == 42);
CHECK(carr.get(0u) == &carr[0u]);
CHECK(carr.is_homogeneous());
CHECK(carr.is_homogeneous<int64_t>());
CHECK(!carr.is_homogeneous<double>());
#if TOML_COMPILER_EXCEPTIONS
CHECK(carr.get(0u) == &carr.at(0u));
#endif
}
{
@ -189,14 +208,20 @@ TEST_CASE("arrays - construction")
CHECK(!arr.empty());
REQUIRE(arr.get_as<int64_t>(0u));
CHECK(*arr.get_as<int64_t>(0u) == 42);
CHECK(arr.get(0u) == &arr[0u]);
REQUIRE(arr.get_as<std::string>(1u));
CHECK(*arr.get_as<std::string>(1u) == "test"sv);
CHECK(arr.get(1u) == &arr[1u]);
REQUIRE(arr.get_as<double>(2u));
CHECK(*arr.get_as<double>(2u) == 10.0);
REQUIRE(arr.get_as<array>(3u));
REQUIRE(arr.get_as<int64_t>(4u));
CHECK(*arr.get_as<int64_t>(4u) == 3);
CHECK(!arr.is_homogeneous());
#if TOML_COMPILER_EXCEPTIONS
CHECK(arr.get(0u) == &arr.at(0u));
CHECK(arr.get(1u) == &arr.at(1u));
#endif
}
#if TOML_ENABLE_WINDOWS_COMPAT

View File

@ -19,7 +19,21 @@ TEST_CASE("tables - moving")
CHECK(tbl["test"].as<table>()->size() == 1u);
CHECK(tbl["test"].as<table>()->source().begin == source_position{ 1, 8 });
CHECK(tbl["test"].as<table>()->source().end == source_position{ 1, 24 });
CHECK(tbl["test"]["val1"] == "foo");
CHECK(tbl["test"].node() == tbl.get("test"sv));
#if TOML_COMPILER_EXCEPTIONS
CHECK(tbl["test"].node() == &tbl.at("test"sv));
#endif
// sanity-check initial state of a freshly-parsed table (const)
const table& ctbl = tbl;
REQUIRE(ctbl["test"].as<table>());
CHECK(ctbl["test"].as<table>()->size() == 1u);
CHECK(ctbl["test"].as<table>()->source().begin == source_position{ 1, 8 });
CHECK(ctbl["test"].as<table>()->source().end == source_position{ 1, 24 });
CHECK(ctbl["test"].node() == ctbl.get("test"sv));
#if TOML_COMPILER_EXCEPTIONS
CHECK(ctbl["test"].node() == &ctbl.at("test"sv));
#endif
// sanity check the virtual type checks
CHECK(tbl.type() == node_type::table);
@ -48,7 +62,6 @@ TEST_CASE("tables - moving")
CHECK(!tbl.as_date_time());
// sanity check the virtual type casts (const)
const auto& ctbl = std::as_const(tbl);
CHECK(ctbl.as_table() == &ctbl);
CHECK(!ctbl.as_array());
CHECK(!ctbl.as_string());

290
toml.hpp
View File

@ -2066,7 +2066,7 @@ TOML_NAMESPACE_START
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_NODISCARD
optional<std::wstring> wide_path() const noexcept
optional<std::wstring> wide_path() const
{
if (!path || path->empty())
return {};
@ -5190,6 +5190,22 @@ TOML_NAMESPACE_START
return *elems_[index];
}
#if TOML_COMPILER_EXCEPTIONS
TOML_NODISCARD
node& at(size_t index)
{
return *elems_.at(index);
}
TOML_NODISCARD
const node& at(size_t index) const
{
return *elems_.at(index);
}
#endif // TOML_COMPILER_EXCEPTIONS
TOML_NODISCARD
node& front() noexcept
{
@ -5800,47 +5816,6 @@ TOML_NAMESPACE_START
TOML_API
table(const impl::table_init_pair*, const impl::table_init_pair*);
template <typename Map, typename Key>
TOML_NODISCARD
static auto do_get(Map& vals, const Key& key) noexcept(!impl::is_wide_string<Key>)
-> std::conditional_t<std::is_const_v<Map>, const node*, node*>
{
static_assert(!impl::is_wide_string<Key> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieval using wide-character keys is only supported on Windows with "
"TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (impl::is_wide_string<Key>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
return do_get(vals, impl::narrow(key));
#else
static_assert(impl::dependent_false<Key>, "Evaluated unreachable branch!");
#endif
}
else
{
if (auto it = vals.find(key); it != vals.end())
return { it->second.get() };
return {};
}
}
template <typename T, typename Map, typename Key>
TOML_NODISCARD
static auto do_get_as(Map& vals, const Key& key) noexcept
{
const auto node = do_get(vals, key);
return node ? node->template as<T>() : nullptr;
}
template <typename Map, typename Key>
TOML_NODISCARD
TOML_ALWAYS_INLINE
static bool do_contains(Map& vals, const Key& key) noexcept
{
return do_get(vals, key) != nullptr;
}
public:
using iterator = table_iterator;
@ -6097,7 +6072,7 @@ TOML_NAMESPACE_START
return nullptr;
}
TOML_NODISCARD
TOML_PURE_INLINE_GETTER
bool is_inline() const noexcept
{
return inline_;
@ -6108,34 +6083,90 @@ TOML_NAMESPACE_START
inline_ = val;
}
TOML_NODISCARD
node_view<node> operator[](std::string_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
TOML_PURE_GETTER
TOML_API
node* get(std::string_view key) noexcept;
TOML_NODISCARD
node_view<const node> operator[](std::string_view key) const noexcept
TOML_PURE_INLINE_GETTER
const node* get(std::string_view key) const noexcept
{
return node_view<const node>{ this->get(key) };
return const_cast<table&>(*this).get(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_NODISCARD
node_view<node> operator[](std::wstring_view key) noexcept
{
return node_view<node>{ this->get(key) };
}
TOML_API
node* get(std::wstring_view key);
TOML_NODISCARD
node_view<const node> operator[](std::wstring_view key) const noexcept
const node* get(std::wstring_view key) const
{
return node_view<const node>{ this->get(key) };
return const_cast<table&>(*this).get(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
template <typename ValueType>
TOML_PURE_GETTER
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
const auto n = this->get(key);
return n ? n->template as<ValueType>() : nullptr;
}
template <typename ValueType>
TOML_PURE_GETTER
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return const_cast<table&>(*this).template get_as<ValueType>(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::wstring_view key)
{
return get_as<ValueType>(impl::narrow(key));
}
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const
{
return const_cast<table&>(*this).template get_as<ValueType>(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#if TOML_COMPILER_EXCEPTIONS
TOML_NODISCARD
TOML_API
node& at(std::string_view key);
TOML_NODISCARD
const node& at(std::string_view key) const
{
return const_cast<table&>(*this).at(key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_NODISCARD
TOML_API
node& at(std::wstring_view key);
TOML_NODISCARD
const node& at(std::wstring_view key) const
{
return const_cast<table&>(*this).at(key);
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#endif // TOML_COMPILER_EXCEPTIONS
TOML_NODISCARD
iterator begin() noexcept
{
@ -6369,7 +6400,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
bool contains(std::string_view key) const noexcept
{
return do_contains(map_, key);
return get(key) != nullptr;
}
#if TOML_ENABLE_WINDOWS_COMPAT
@ -6395,61 +6426,29 @@ TOML_NAMESPACE_START
#endif // TOML_ENABLE_WINDOWS_COMPAT
TOML_NODISCARD
node* get(std::string_view key) noexcept
node_view<node> operator[](std::string_view key) noexcept
{
return do_get(map_, key);
return node_view<node>{ get(key) };
}
TOML_NODISCARD
const node* get(std::string_view key) const noexcept
node_view<const node> operator[](std::string_view key) const noexcept
{
return do_get(map_, key);
return node_view<const node>{ get(key) };
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_NODISCARD
node* get(std::wstring_view key)
node_view<node> operator[](std::wstring_view key) noexcept
{
return get(impl::narrow(key));
return node_view<node>{ get(key) };
}
TOML_NODISCARD
const node* get(std::wstring_view key) const
node_view<const node> operator[](std::wstring_view key) const noexcept
{
return get(impl::narrow(key));
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
return do_get_as<ValueType>(map_, key);
}
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return do_get_as<ValueType>(map_, key);
}
#if TOML_ENABLE_WINDOWS_COMPAT
template <typename ValueType>
TOML_NODISCARD
impl::wrap_node<ValueType>* get_as(std::wstring_view key)
{
return get_as<ValueType>(impl::narrow(key));
}
template <typename ValueType>
TOML_NODISCARD
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const
{
return get_as<ValueType>(impl::narrow(key));
return node_view<const node>{ get(key) };
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
@ -9459,33 +9458,6 @@ TOML_PUSH_WARNINGS;
#undef max
#endif
TOML_ANON_NAMESPACE_START
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool table_is_homogeneous(T & map, node_type ntype, U & first_nonmatch) noexcept
{
if (map.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
}
TOML_ANON_NAMESPACE_END;
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
@ -9576,15 +9548,79 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
{
return TOML_ANON_NAMESPACE::table_is_homogeneous(map_, ntype, first_nonmatch);
if (map_.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map_.cbegin()->second->type();
for (const auto& [k, v] : map_)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
{
return TOML_ANON_NAMESPACE::table_is_homogeneous(map_, ntype, first_nonmatch);
node* fnm = nullptr;
const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
first_nonmatch = fnm;
return result;
}
TOML_EXTERNAL_LINKAGE
node* table::get(std::string_view key) noexcept
{
if (auto it = map_.find(key); it != map_.end())
return it->second.get();
return nullptr;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node* table::get(std::wstring_view key)
{
return get(impl::narrow(key));
}
#endif
#if TOML_COMPILER_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
node& table::at(std::string_view key)
{
auto n = get(key);
if (!n)
{
auto err = "key '"s;
err.append(key);
err.append("' not found in table"sv);
throw std::out_of_range{ err };
}
return *n;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node& table::at(std::wstring_view key)
{
return at(impl::narrow(key));
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
#endif // TOML_COMPILER_EXCEPTIONS
TOML_EXTERNAL_LINKAGE
bool table::equal(const table& lhs, const table& rhs) noexcept
{