mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-18 02:08:09 +08:00
🔀 Merge branch 'master' into v3
This commit is contained in:
158
README.md
158
README.md
@@ -451,36 +451,58 @@ const auto value = toml::expect<int>(data.at("number"))
|
||||
|
||||
## Finding a value from a table
|
||||
|
||||
toml11 provides utility function to find a value from `toml::table`.
|
||||
Of course, you can do this in your own way with `toml::get` because
|
||||
it just searches an `unordered_map` and returns a value if it exists.
|
||||
toml11 provides utility function to find a value from `toml::value` and `toml::table`.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find<int>(data, "num", /*for err msg*/"example.toml");
|
||||
// find a value named "num" from `data`.
|
||||
const auto num = toml::find<int>(data, "num");
|
||||
```
|
||||
|
||||
If the value does not exist, it throws `std::out_of_range` with an error message.
|
||||
But, since `toml::table` is just an alias of `std::unordered_map<toml::key, toml::value>`,
|
||||
you need to pass a name to the function to show the name in the exception.
|
||||
|
||||
```cpp
|
||||
const auto num = toml::find<int>(data, "num", "example.toml");
|
||||
```
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
what(): [error] key "num" not found in example.toml
|
||||
# ^^^^^^^^^^^^ this part
|
||||
```
|
||||
|
||||
You can use this with a `toml::value` that is expected to be a `toml::table`.
|
||||
It automatically casts the value to table.
|
||||
Of course, you can do this in your own way with `toml::get` because
|
||||
it just searches an `unordered_map` and returns a value if it exists.
|
||||
|
||||
```cpp
|
||||
const auto data = toml::parse("example.toml");
|
||||
const auto num = toml::find<int>(data.at("table"), "num");
|
||||
// expecting the following example.toml
|
||||
// [table]
|
||||
// num = 42
|
||||
const toml::table data = toml::parse("example.toml");
|
||||
if(data.count("num") == 1)
|
||||
{
|
||||
const auto num = toml::get<int>(data.at("num"));
|
||||
// more stuff ...
|
||||
}
|
||||
```
|
||||
|
||||
In this case, because the value `data.at("table")` knows the locatoin of itself,
|
||||
you don't need to pass where you find the value.
|
||||
`toml::find` will show you an error message including table location.
|
||||
----
|
||||
|
||||
You can also use this with a `toml::value` that is expected to contain a `toml::table`.
|
||||
It automatically casts the `toml::value` to a `toml::table`. If it failed to cast,
|
||||
it would throw a `toml::type_error`.
|
||||
|
||||
```cpp
|
||||
// # expecting the following example.toml
|
||||
// [table]
|
||||
// num = 42
|
||||
const toml::table data = toml::parse("example.toml");
|
||||
const toml::value table = data.at("table");
|
||||
const auto num = toml::find<int>(table, "num");
|
||||
```
|
||||
|
||||
In this case, because the `toml::value table` knows the locatoin of itself,
|
||||
you don't need to pass the name to show it in an error message.
|
||||
`toml::find` will automatically format an error message with the location of the table.
|
||||
|
||||
```console
|
||||
terminate called after throwing an instance of 'std::out_of_range'
|
||||
@@ -490,7 +512,45 @@ terminate called after throwing an instance of 'std::out_of_range'
|
||||
| ~~~~~~~ in this table
|
||||
```
|
||||
|
||||
If it's not a `toml::table`, the same error as "invalid type" would be thrown.
|
||||
The default return value of the `toml::find` is a `toml::value`.
|
||||
|
||||
```cpp
|
||||
const toml::value& subtable = toml::find(table, "subtable");
|
||||
```
|
||||
|
||||
There are several ways to find a value buried in a deep recursion of tables.
|
||||
|
||||
First, you can call `toml::find` as many as you need.
|
||||
|
||||
```cpp
|
||||
// # expecting the following example.toml
|
||||
// answer.to.the.ultimate.question = 42
|
||||
// # is equivalent to {"answer": {"to":{"the":{"ultimate:{"question":42}}}}}
|
||||
|
||||
const toml::table data = toml::parse("example.toml");
|
||||
const int a = toml::find<int>(toml::find(toml::find(toml::find(toml::find(
|
||||
data, "answer"), "to"), "the"), "ultimate"), "question");
|
||||
```
|
||||
|
||||
But it is a bother.
|
||||
|
||||
After toml11 v2.4.0, you can pass a `toml::value` and as many number of keys as you want.
|
||||
|
||||
```cpp
|
||||
const toml::table data = toml::parse("example.toml");
|
||||
const int a = toml::find<int>(data.at("answer"), "to", "the", "ultimate", "question");
|
||||
```
|
||||
|
||||
__NOTE__:
|
||||
Currently, this function does not support `toml::table` because of some
|
||||
technical reason. Please make sure that the type of the first argument is
|
||||
`toml::value`. The main reason is that the `toml::table` may take an additional string
|
||||
as the third argumnet to show its location in an error message. And the
|
||||
most confusing part is that `toml::parse` returns `toml::table`, not a
|
||||
`toml::value`. This confusing API will hopefully be resolved in the next
|
||||
major update, v3 (it will contain some unavoidable breaking changes).
|
||||
|
||||
----
|
||||
|
||||
There is another utility function, `toml::find_or`.
|
||||
It is almost same as `toml::find`, but returns a default value if the value is
|
||||
@@ -516,20 +576,27 @@ if(v.is_integer())
|
||||
The complete list of the functions is below.
|
||||
|
||||
```cpp
|
||||
const toml::value v(/*...*/);
|
||||
v.is_boolean();
|
||||
v.is_integer();
|
||||
v.is_float();
|
||||
v.is_string();
|
||||
v.is_offset_datetime();
|
||||
v.is_local_datetime();
|
||||
v.is_local_date();
|
||||
v.is_local_time();
|
||||
v.is_array();
|
||||
v.is_table();
|
||||
v.is_uninitialized();
|
||||
namespace toml {
|
||||
class value {
|
||||
// ...
|
||||
bool is_boolean() const noexcept;
|
||||
bool is_integer() const noexcept;
|
||||
bool is_floating() const noexcept;
|
||||
bool is_string() const noexcept;
|
||||
bool is_offset_datetime() const noexcept;
|
||||
bool is_local_datetime() const noexcept;
|
||||
bool is_local_date() const noexcept;
|
||||
bool is_local_time() const noexcept;
|
||||
bool is_array() const noexcept;
|
||||
bool is_table() const noexcept;
|
||||
bool is_uninitialized() const noexcept;
|
||||
// ...
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
__NOTE__: `is_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `is_floating` instead.
|
||||
|
||||
Also, you can get `enum class` value from `toml::value`.
|
||||
|
||||
```cpp
|
||||
@@ -569,20 +636,33 @@ if(v.is_integer() && v.as_integer() == 42)
|
||||
The complete list of the functions is below.
|
||||
|
||||
```cpp
|
||||
const toml::value v(/*...*/);
|
||||
v.as_boolean();
|
||||
v.as_integer();
|
||||
v.as_float();
|
||||
v.as_string();
|
||||
v.as_offset_datetime();
|
||||
v.as_local_datetime();
|
||||
v.as_local_date();
|
||||
v.as_local_time();
|
||||
v.as_array();
|
||||
v.as_table();
|
||||
v.as_uninitialized();
|
||||
namespace toml {
|
||||
class value {
|
||||
// ...
|
||||
const boolean& as_boolean() const& noexcept;
|
||||
const integer& as_integer() const& noexcept;
|
||||
const floating& as_floating() const& noexcept;
|
||||
const string& as_string() const& noexcept;
|
||||
const offset_datetime& as_offset_datetime() const& noexcept;
|
||||
const local_datetime& as_local_datetime() const& noexcept;
|
||||
const local_date& as_local_date() const& noexcept;
|
||||
const local_time& as_local_time() const& noexcept;
|
||||
const array& as_array() const& noexcept;
|
||||
const table& as_table() const& noexcept;
|
||||
// --------------------------------------------------------
|
||||
// non-const version
|
||||
boolean& as_boolean() & noexcept;
|
||||
// ditto...
|
||||
// --------------------------------------------------------
|
||||
// rvalue version
|
||||
boolean&& as_boolean() && noexcept;
|
||||
// ditto...
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
__NOTE__: `as_float` is marked as deprecated since v2.4.0 to make the function names consistent with snake case typenames. Please use `as_floating` instead.
|
||||
|
||||
## Visiting a toml::value
|
||||
|
||||
toml11 provides `toml::visit` to apply a function to `toml::value` in the
|
||||
|
@@ -12,8 +12,9 @@
|
||||
#include <deque>
|
||||
#include <array>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_find)
|
||||
BOOST_AUTO_TEST_CASE(test_find_for_value)
|
||||
{
|
||||
// value itself is not a table
|
||||
{
|
||||
toml::value v(true);
|
||||
bool thrown = false;
|
||||
@@ -27,22 +28,87 @@ BOOST_AUTO_TEST_CASE(test_find)
|
||||
}
|
||||
BOOST_CHECK(thrown);
|
||||
}
|
||||
// the value corresponding to the key is not the expected type
|
||||
{
|
||||
toml::value v{{"key", 42}};
|
||||
bool thrown = false;
|
||||
try
|
||||
{
|
||||
toml::find<toml::boolean>(v, "key");
|
||||
}
|
||||
catch(toml::type_error const& te)
|
||||
{
|
||||
thrown = true;
|
||||
}
|
||||
BOOST_CHECK(thrown);
|
||||
}
|
||||
|
||||
{
|
||||
toml::value v = toml::table{{"num", 42}};
|
||||
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "num"));
|
||||
|
||||
// reference that can be used to modify the content
|
||||
auto& num = toml::find<toml::integer>(v, "num");
|
||||
num = 54;
|
||||
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "num"));
|
||||
}
|
||||
|
||||
// recursively search tables
|
||||
{
|
||||
toml::value v = toml::table{
|
||||
{"a", toml::table{
|
||||
{"b", toml::table{
|
||||
{"c", toml::table{
|
||||
{"d", 42}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
};
|
||||
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "a", "b", "c", "d"));
|
||||
|
||||
// reference that can be used to modify the content
|
||||
auto& num = toml::find<toml::integer>(v, "a", "b", "c", "d");
|
||||
num = 54;
|
||||
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "a", "b", "c", "d"));
|
||||
|
||||
const std::string a("a"), b("b"), c("c"), d("d");
|
||||
auto& num2 = toml::find<toml::integer>(v, a, b, c, d);
|
||||
num2 = 42;
|
||||
BOOST_CHECK_EQUAL(42, toml::find<int>(v, a, b, c, d));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_find_for_table)
|
||||
{
|
||||
// the value corresponding to the key is not the expected type
|
||||
{
|
||||
toml::table v{{"key", 42}};
|
||||
bool thrown = false;
|
||||
try
|
||||
{
|
||||
toml::find<toml::boolean>(v, "key");
|
||||
}
|
||||
catch(toml::type_error const& te)
|
||||
{
|
||||
thrown = true;
|
||||
}
|
||||
BOOST_CHECK(thrown);
|
||||
}
|
||||
|
||||
{
|
||||
toml::table v{{"num", 42}};
|
||||
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "num"));
|
||||
toml::find<toml::integer>(v, "num") = 54;
|
||||
|
||||
// reference that can be used to modify the content
|
||||
auto& num = toml::find<toml::integer>(v, "num");
|
||||
num = 54;
|
||||
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "num"));
|
||||
}
|
||||
|
||||
{
|
||||
toml::value v = toml::table{{"num", 42}};
|
||||
BOOST_CHECK_EQUAL(42, toml::find<int>(v, "num"));
|
||||
toml::find<toml::integer>(v, "num") = 54;
|
||||
BOOST_CHECK_EQUAL(54, toml::find<int>(v, "num"));
|
||||
}
|
||||
// recursive search is not provided for tables.
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_get_or)
|
||||
{
|
||||
// requires conversion int -> uint
|
||||
|
@@ -810,7 +810,6 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_integer(), 54);
|
||||
BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "quux");
|
||||
|
||||
|
||||
toml::value v3(v1);
|
||||
BOOST_CHECK(v3 == v1);
|
||||
|
||||
|
49
toml/get.hpp
49
toml/get.hpp
@@ -559,6 +559,55 @@ find(basic_value<C, M, V>&& v, const key& ky)
|
||||
return ::toml::get<T>(std::move(tab.at(ky)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// toml::find(toml::value, toml::key, Ts&& ... keys)
|
||||
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
const basic_value<C, M, V>&
|
||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
basic_value<C, M, V>&
|
||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
template<typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
basic_value<C, M, V>&&
|
||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
typename ... Ts>
|
||||
decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
|
||||
find(const basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
|
||||
find(basic_value<C, M, V>& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(v, ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
|
||||
find(basic_value<C, M, V>&& v, const ::toml::key& ky, Ts&& ... keys)
|
||||
{
|
||||
return ::toml::find<T>(::toml::find(std::move(v), ky), std::forward<Ts>(keys)...);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// get_or(value, fallback)
|
||||
|
||||
|
@@ -11,7 +11,7 @@ inline namespace literals
|
||||
inline namespace toml_literals
|
||||
{
|
||||
|
||||
inline ::toml::value operator""_toml(const char* str, std::size_t len)
|
||||
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
{
|
||||
::toml::detail::location<std::vector<char>>
|
||||
loc(/* filename = */ std::string("TOML literal encoded in a C++ code"),
|
||||
|
Reference in New Issue
Block a user