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
{