mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
9 Commits
v3.6.0
...
find-fuzzy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bf4ac0965 | ||
|
|
d53026837a | ||
|
|
6d31cccc5b | ||
|
|
99e46813f4 | ||
|
|
c0df39ca49 | ||
|
|
3e6747cfeb | ||
|
|
4cebd660fd | ||
|
|
43907de365 | ||
|
|
9b43171b65 |
121
README.md
121
README.md
@@ -270,6 +270,46 @@ const auto color = toml::find<std::string>(data, "fruit", "physical", "color");
|
|||||||
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
|
const auto shape = toml::find<std::string>(data, "fruit", "physical", "shape");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Dotted keys
|
||||||
|
|
||||||
|
TOML v0.5.0 has a new feature named "dotted keys".
|
||||||
|
You can chain keys to represent the structure of the data.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
physical.color = "orange"
|
||||||
|
physical.shape = "round"
|
||||||
|
```
|
||||||
|
|
||||||
|
This is equivalent to the following.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[physical]
|
||||||
|
color = "orange"
|
||||||
|
shape = "round"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can get both of the above tables with the same c++ code.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const auto physical = toml::find(data, "physical");
|
||||||
|
const auto color = toml::find<std::string>(physical, "color");
|
||||||
|
```
|
||||||
|
|
||||||
|
The following code does not work for the above toml file.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// XXX this does not work!
|
||||||
|
const auto color = toml::find<std::string>(data, "physical.color");
|
||||||
|
```
|
||||||
|
|
||||||
|
The above code works with the following toml file.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
"physical.color" = "orange"
|
||||||
|
# equivalent to {"physical.color": "orange"},
|
||||||
|
# NOT {"physical": {"color": "orange"}}.
|
||||||
|
```
|
||||||
|
|
||||||
### In case of error
|
### In case of error
|
||||||
|
|
||||||
If the value does not exist, `toml::find` throws an error with the location of
|
If the value does not exist, `toml::find` throws an error with the location of
|
||||||
@@ -310,46 +350,77 @@ shared by `toml::value`s and remains on the heap memory. It is recommended to
|
|||||||
destruct all the `toml::value` classes after configuring your application
|
destruct all the `toml::value` classes after configuring your application
|
||||||
if you have a large TOML file compared to the memory resource.
|
if you have a large TOML file compared to the memory resource.
|
||||||
|
|
||||||
### Dotted keys
|
### Fuzzy Search
|
||||||
|
|
||||||
TOML v0.5.0 has a new feature named "dotted keys".
|
To find a value, you can use `find_fuzzy` instead of `find`.
|
||||||
You can chain keys to represent the structure of the data.
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
physical.color = "orange"
|
[foobar]
|
||||||
physical.shape = "round"
|
# typo!
|
||||||
|
anseer = 42
|
||||||
```
|
```
|
||||||
|
|
||||||
This is equivalent to the following.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[physical]
|
|
||||||
color = "orange"
|
|
||||||
shape = "round"
|
|
||||||
```
|
|
||||||
|
|
||||||
You can get both of the above tables with the same c++ code.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const auto physical = toml::find(data, "physical");
|
const auto data = toml::parse("sample.toml");
|
||||||
const auto color = toml::find<std::string>(physical, "color");
|
const auto foobar = toml::find(data, "foobar");
|
||||||
|
const auto answer = toml::find_fuzzy<int>(data, "answer"); // it finds "anseer".
|
||||||
```
|
```
|
||||||
|
|
||||||
The following code does not work for the above toml file.
|
When the specified key is not found, `toml::find_fuzzy` calculates
|
||||||
|
[levenstein distance](https://en.wikipedia.org/wiki/Levenshtein_distance)
|
||||||
|
between the specified key and other keys.
|
||||||
|
If it finds a key that is 1 away from the specified key by the Levenstein
|
||||||
|
distance, it returns the corresponding value.
|
||||||
|
|
||||||
|
To allow a more distant string, you can explicitly pass `toml::levenstein_matcher`
|
||||||
|
to `find_fuzzy`.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// XXX this does not work!
|
toml::levenstein_matcher lev(2); // allow distance <= 2
|
||||||
const auto color = toml::find<std::string>(data, "physical.color");
|
const auto answer = toml::find_fuzzy<int>(data, "answer", lev);
|
||||||
```
|
```
|
||||||
|
|
||||||
The above code works with the following toml file.
|
You can also use your own distance metric. Implement your `fuzzy_matcher` that
|
||||||
|
has `operator()` that takes two strings and returns true if two strings resemble
|
||||||
|
each other.
|
||||||
|
|
||||||
```toml
|
```cpp
|
||||||
"physical.color" = "orange"
|
struct fuzzy_matcher
|
||||||
# equivalent to {"physical.color": "orange"},
|
{
|
||||||
# NOT {"physical": {"color": "orange"}}.
|
bool operator()(const std::string& lhs, const std::string& rhs) const
|
||||||
|
{
|
||||||
|
// return true if lhs matches with rhs.
|
||||||
|
}
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If there are multiple keys that meets the condition, it throws `runtime_error`.
|
||||||
|
|
||||||
|
However, in many cases, rather than just allowing typographical errors,
|
||||||
|
you will want to suggest it and encouledge users to correct it.
|
||||||
|
|
||||||
|
If you pass a `fuzzy_matcher` to `toml::find`, a suggestion will be displayed
|
||||||
|
in the error message.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
toml::levenstein_matcher lev(1); // finds keys within distance <= 1
|
||||||
|
const auto answer = toml::find<int>(data, "answer", lev); // it throws!
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
terminate called after throwing an instance of 'std::out_of_range'
|
||||||
|
what(): [error] key "answer" not found.
|
||||||
|
--> hoge.toml
|
||||||
|
1 | [foobar]
|
||||||
|
| ~~~~~~~~ in this table
|
||||||
|
...
|
||||||
|
2 | anseer = 42
|
||||||
|
| ~~ did you mean this here?
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Currently, `find_fuzzy` and `find(value, key, matcher)` take only one key.
|
||||||
|
The codes like `find_fuzzy(value, key1, key2, key3)` do not work.
|
||||||
|
|
||||||
## Casting a toml value
|
## Casting a toml value
|
||||||
|
|
||||||
### `toml::get`
|
### `toml::get`
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ set(TEST_NAMES
|
|||||||
test_get_or
|
test_get_or
|
||||||
test_find
|
test_find
|
||||||
test_find_or
|
test_find_or
|
||||||
|
test_find_fuzzy
|
||||||
test_expect
|
test_expect
|
||||||
test_parse_file
|
test_parse_file
|
||||||
test_serialize_file
|
test_serialize_file
|
||||||
|
|||||||
350
tests/test_find_fuzzy.cpp
Normal file
350
tests/test_find_fuzzy.cpp
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
#define BOOST_TEST_MODULE "test_find_fuzzy"
|
||||||
|
|
||||||
|
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#else
|
||||||
|
#define BOOST_TEST_NO_LIB
|
||||||
|
#include <boost/test/included/unit_test.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <toml.hpp>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_levenstein_distance)
|
||||||
|
{
|
||||||
|
const toml::levenstein_matcher lev(1);
|
||||||
|
|
||||||
|
// distance == 0
|
||||||
|
{
|
||||||
|
const std::string s1("foobar");
|
||||||
|
const std::string s2 = s1;
|
||||||
|
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string s1("foobar");
|
||||||
|
const std::string s2("foobaz");
|
||||||
|
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string s1("foobar"); // insertion (+x)
|
||||||
|
const std::string s2("fooxbar");
|
||||||
|
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string s1("foobar");
|
||||||
|
const std::string s2("fooar"); // insertion(+b)
|
||||||
|
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// distance > 1
|
||||||
|
{
|
||||||
|
const std::string s1("foobar");
|
||||||
|
const std::string s2("fooquux");
|
||||||
|
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string s1("foobar");
|
||||||
|
const std::string s2("fooqu");
|
||||||
|
|
||||||
|
BOOST_TEST(s1 != s2);
|
||||||
|
BOOST_TEST(lev.distance(s1, s2) == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_fuzzy)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", "value"} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy(v, "key") == toml::value("value"));
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(v, "kiwi"), std::out_of_range);
|
||||||
|
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value&, decltype(toml::find_fuzzy(v, "key"))>::value, "");
|
||||||
|
|
||||||
|
toml::find_fuzzy(v, "key") = "foobar";
|
||||||
|
BOOST_TEST(toml::find(v, "keu") == toml::value("foobar"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
{"keu", "value"} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy(v, "key") == toml::value("value"));
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(v, "kiwi"), std::out_of_range);
|
||||||
|
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value const&, decltype(toml::find_fuzzy(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", "value"} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy(std::move(v), "key") == toml::value("value"));
|
||||||
|
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value&&, decltype(toml::find_fuzzy(std::move(v), "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", "value"} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(std::move(v), "kiwi"), std::out_of_range);
|
||||||
|
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value&&, decltype(toml::find_fuzzy(std::move(v), "key"))>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// find with conversion
|
||||||
|
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", 42} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy<int>(v, "key") == 42);
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "kiwi"), std::out_of_range);
|
||||||
|
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find_fuzzy<int>(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
{"keu", 42} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy<int>(v, "key") == 42);
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "kiwi"), std::out_of_range);
|
||||||
|
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find_fuzzy<int>(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", 42} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TEST(toml::find_fuzzy<int>(std::move(v), "key") == 42);
|
||||||
|
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find_fuzzy<int>(std::move(v), "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", 42} // typo! key -> keu
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(std::move(v), "kiwi"), std::out_of_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_fuzzy_throw)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", "value"}, // typo! key -> keu
|
||||||
|
{"ky", "value"} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(v, "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
{"keu", "value"}, // typo! key -> keu
|
||||||
|
{"ky", "value"} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(v, "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", "value"}, // typo! key -> keu
|
||||||
|
{"ky", "value"} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy(std::move(v), "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", 42}, // typo! key -> keu
|
||||||
|
{"ky", 42} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v{
|
||||||
|
{"keu", 42}, // typo! key -> keu
|
||||||
|
{"ky", 42} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(v, "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v{
|
||||||
|
{"keu", 42}, // typo! key -> keu
|
||||||
|
{"ky", 42} // typo! key -> ky
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find_fuzzy<int>(std::move(v), "key"), std::out_of_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_throw_typo_aware_exception)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
const toml::levenstein_matcher lev(1);
|
||||||
|
{
|
||||||
|
toml::value v = u8R"(
|
||||||
|
keu = "value"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find(v, "key", lev), std::out_of_range);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find(v, "key", lev);
|
||||||
|
(void)ret; // suppress unused variable
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value&, decltype(toml::find(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v = u8R"(
|
||||||
|
keu = "value"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find(v, "key", lev), std::out_of_range);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find(v, "key", lev);
|
||||||
|
(void)ret;
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value const&, decltype(toml::find(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v = u8R"(
|
||||||
|
keu = "value"
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
bool thrown = false; // since it moves, we need to check both once
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find(std::move(v), "key", lev);
|
||||||
|
(void)ret;
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
thrown = true;
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
BOOST_TEST(thrown);
|
||||||
|
static_assert(std::is_same<
|
||||||
|
toml::value&, decltype(toml::find(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_find_throw_conversion_typo_aware_exception)
|
||||||
|
{
|
||||||
|
using namespace toml::literals::toml_literals;
|
||||||
|
const toml::levenstein_matcher lev(1);
|
||||||
|
{
|
||||||
|
toml::value v = u8R"(
|
||||||
|
keu = 42
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find<int>(v, "key", lev), std::out_of_range);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find<int>(v, "key", lev);
|
||||||
|
(void)ret; // suppress unused variable
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find<int>(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const toml::value v = u8R"(
|
||||||
|
keu = 42
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(toml::find<int>(v, "key", lev), std::out_of_range);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find<int>(v, "key", lev);
|
||||||
|
(void)ret;
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find<int>(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
toml::value v = u8R"(
|
||||||
|
keu = 42
|
||||||
|
)"_toml;
|
||||||
|
|
||||||
|
bool thrown = false; // since it moves, we need to check both once
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& ret = toml::find<int>(std::move(v), "key", lev);
|
||||||
|
(void)ret;
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
// exception.what() should include the typo-ed key name
|
||||||
|
const std::string what(oor.what());
|
||||||
|
BOOST_TEST(what.find("keu") != std::string::npos);
|
||||||
|
thrown = true;
|
||||||
|
|
||||||
|
// std::cout << what << std::endl;
|
||||||
|
}
|
||||||
|
BOOST_TEST(thrown);
|
||||||
|
static_assert(std::is_same<int,
|
||||||
|
decltype(toml::find<int>(v, "key"))>::value, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
1
toml.hpp
1
toml.hpp
@@ -37,5 +37,6 @@
|
|||||||
#include "toml/literal.hpp"
|
#include "toml/literal.hpp"
|
||||||
#include "toml/serializer.hpp"
|
#include "toml/serializer.hpp"
|
||||||
#include "toml/get.hpp"
|
#include "toml/get.hpp"
|
||||||
|
#include "toml/find.hpp"
|
||||||
|
|
||||||
#endif// TOML_FOR_MODERN_CPP
|
#endif// TOML_FOR_MODERN_CPP
|
||||||
|
|||||||
786
toml/find.hpp
Normal file
786
toml/find.hpp
Normal file
@@ -0,0 +1,786 @@
|
|||||||
|
// Copyright Toru Niina 2019.
|
||||||
|
// Distributed under the MIT License.
|
||||||
|
#ifndef TOML11_FIND_HPP
|
||||||
|
#define TOML11_FIND_HPP
|
||||||
|
#include "get.hpp"
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
namespace toml
|
||||||
|
{
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// these overloads do not require to set T. and returns value itself.
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
||||||
|
{
|
||||||
|
const auto& tab = v.template cast<value_t::table>();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return tab.at(ky);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
||||||
|
{
|
||||||
|
auto& tab = v.template cast<value_t::table>();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return tab.at(ky);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V>&& find(basic_value<C, M, V>&& v, const key& ky)
|
||||||
|
{
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return std::move(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// find<T>(value, key);
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
|
||||||
|
find(const basic_value<C, M, V>& v, const key& ky)
|
||||||
|
{
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 key& ky)
|
||||||
|
{
|
||||||
|
auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 key& ky)
|
||||||
|
{
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, 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,
|
||||||
|
typename ... Ts>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, 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,
|
||||||
|
typename ... Ts>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, 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>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, decltype(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,
|
||||||
|
typename ... Ts>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, decltype(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,
|
||||||
|
typename ... Ts>
|
||||||
|
detail::enable_if_t<detail::conjunction<std::is_convertible<Ts, std::string>...
|
||||||
|
>::value, decltype(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)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// find_or(value, key, fallback)
|
||||||
|
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V> const&
|
||||||
|
find_or(const basic_value<C, M, V>& v, const key& ky,
|
||||||
|
const basic_value<C, M, V>& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return tab.at(ky);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V>&
|
||||||
|
find_or(basic_value<C, M, V>& v, const toml::key& ky, basic_value<C, M, V>& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return tab[ky];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
basic_value<C, M, V>
|
||||||
|
find_or(basic_value<C, M, V>&& v, const toml::key& ky, basic_value<C, M, V>&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return std::move(opt);}
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0) {return std::move(opt);}
|
||||||
|
return std::move(tab[ky]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// exact types (return type can be a reference)
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
|
||||||
|
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
|
||||||
|
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab[ky], opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&&
|
||||||
|
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return std::forward<T>(opt);}
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
||||||
|
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// std::string (return type can be a reference)
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
|
||||||
|
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
|
||||||
|
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return opt;}
|
||||||
|
auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return opt;}
|
||||||
|
return get_or(tab.at(ky), opt);
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
|
||||||
|
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return std::forward<T>(opt);}
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
||||||
|
return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// string literal (deduced as std::string)
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
||||||
|
std::string>
|
||||||
|
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return std::string(opt);}
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return std::string(opt);}
|
||||||
|
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// others (require type conversion and return type cannot be lvalue reference)
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
// T is not an exact toml type
|
||||||
|
detail::negation<detail::is_exact_toml_type<
|
||||||
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type,
|
||||||
|
basic_value<C, M, V>>>,
|
||||||
|
// T is not std::string
|
||||||
|
detail::negation<std::is_same<std::string,
|
||||||
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
||||||
|
// T is not a string literal
|
||||||
|
detail::negation<detail::is_string_literal<
|
||||||
|
typename std::remove_reference<T>::type>>
|
||||||
|
>::value, typename std::remove_cv<typename std::remove_reference<T>::type>::type>
|
||||||
|
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
||||||
|
{
|
||||||
|
if(!v.is_table()) {return std::forward<T>(opt);}
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
||||||
|
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// expect
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
result<T, std::string> expect(const basic_value<C, M, V>& v) noexcept
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ok(get<T>(v));
|
||||||
|
}
|
||||||
|
catch(const std::exception& e)
|
||||||
|
{
|
||||||
|
return err(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V>
|
||||||
|
result<T, std::string>
|
||||||
|
expect(const basic_value<C, M, V>& v, const toml::key& k) noexcept
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ok(find<T>(v, k));
|
||||||
|
}
|
||||||
|
catch(const std::exception& e)
|
||||||
|
{
|
||||||
|
return err(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename Table>
|
||||||
|
detail::enable_if_t<detail::conjunction<
|
||||||
|
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>
|
||||||
|
>::value, result<T, std::string>>
|
||||||
|
expect(const Table& t, const toml::key& k,
|
||||||
|
std::string tablename = "unknown table") noexcept
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ok(find<T>(t, k, std::move(tablename)));
|
||||||
|
}
|
||||||
|
catch(const std::exception& e)
|
||||||
|
{
|
||||||
|
return err(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// find_fuzzy
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// default fuzzy matcher; levenstein distance (all cost is 1)
|
||||||
|
|
||||||
|
struct levenstein_matcher
|
||||||
|
{
|
||||||
|
levenstein_matcher(): tolerance(1) {}
|
||||||
|
levenstein_matcher(const std::uint32_t tol): tolerance(tol) {}
|
||||||
|
~levenstein_matcher() = default;
|
||||||
|
levenstein_matcher(levenstein_matcher const&) = default;
|
||||||
|
levenstein_matcher(levenstein_matcher &&) = default;
|
||||||
|
levenstein_matcher& operator=(levenstein_matcher const&) = default;
|
||||||
|
levenstein_matcher& operator=(levenstein_matcher &&) = default;
|
||||||
|
|
||||||
|
template<typename charT, typename traitsT, typename Alloc1, typename Alloc2>
|
||||||
|
bool operator()(const std::basic_string<charT, traitsT, Alloc1>& lhs,
|
||||||
|
const std::basic_string<charT, traitsT, Alloc2>& rhs) const
|
||||||
|
{
|
||||||
|
return this->distance(lhs, rhs) <= this->tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename charT, typename traitsT, typename Alloc1, typename Alloc2>
|
||||||
|
std::uint32_t distance(
|
||||||
|
const std::basic_string<charT, traitsT, Alloc1>& lhs,
|
||||||
|
const std::basic_string<charT, traitsT, Alloc2>& rhs) const
|
||||||
|
{
|
||||||
|
// force `lhs.size() <= rhs.size()`
|
||||||
|
if(lhs.size() > rhs.size()) {return this->distance(rhs, lhs);}
|
||||||
|
|
||||||
|
std::vector<std::uint32_t> matrix(lhs.size() + 1u);
|
||||||
|
std::iota(matrix.begin(), matrix.end(), 0);
|
||||||
|
|
||||||
|
for(const charT r : rhs)
|
||||||
|
{
|
||||||
|
std::uint32_t prev_diag = matrix.front();
|
||||||
|
matrix.front() += 1;
|
||||||
|
|
||||||
|
for(std::size_t i=0; i<lhs.size(); ++i)
|
||||||
|
{
|
||||||
|
const charT l = lhs[i];
|
||||||
|
if(traitsT::eq(l, r))
|
||||||
|
{
|
||||||
|
std::swap(matrix[i+1], prev_diag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto tmp = matrix[i+1];
|
||||||
|
matrix[i+1] = std::min(prev_diag, std::min(matrix[i], matrix[i+1])) + 1;
|
||||||
|
prev_diag = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matrix.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::uint32_t tolerance;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// toml::find_fuzzy<T>(v, "tablename", FuzzyMatcher);
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename Iterator, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
Iterator find_unique(
|
||||||
|
Iterator iter, const Iterator end, const basic_value<C, M, V>& v,
|
||||||
|
const toml::key& k, const FuzzyMatcher& match)
|
||||||
|
{
|
||||||
|
Iterator found = end;
|
||||||
|
for(; iter != end; ++iter)
|
||||||
|
{
|
||||||
|
if(match(iter->first, k))
|
||||||
|
{
|
||||||
|
if(found != end)
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(
|
||||||
|
concat_to_string("[error] key \"", k, "\" not found."),
|
||||||
|
{
|
||||||
|
{std::addressof(detail::get_region(v)),"in this table"},
|
||||||
|
{std::addressof(detail::get_region(found->second)),
|
||||||
|
"did you mean this here?"},
|
||||||
|
{std::addressof(detail::get_region(iter->second)),
|
||||||
|
"or this?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
found = iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
auto find_fuzzy(const basic_value<C, M, V>& v, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
-> decltype(find<T>(std::declval<const basic_value<C, M, V>&>(), ky))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return find<T>(v, ky);
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
const auto& t = v.as_table();
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return get<T>(found->second);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
auto find_fuzzy(basic_value<C, M, V>& v, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
-> decltype(find<T>(std::declval<basic_value<C, M, V>&>(), ky))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return find<T>(v, ky);
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
auto& t = v.as_table();
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return get<T>(found->second);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
auto find_fuzzy(basic_value<C, M, V>&& v_, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
-> decltype(find<T>(std::declval<basic_value<C, M, V>&&>(), ky))
|
||||||
|
{
|
||||||
|
basic_value<C, M, V> v = v_; // to re-use later, store it once
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return std::move(find<T>(v, ky)); // pass lref, move later
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
auto& t = v.as_table(); // because v is used here
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return get<T>(std::move(found->second));
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// no-template-argument case (by default, return toml::value).
|
||||||
|
// toml::find_fuzzy(v, "tablename", FuzzyMatcher);
|
||||||
|
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
basic_value<C, M, V> const&
|
||||||
|
find_fuzzy(const basic_value<C, M, V>& v, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return find(v, ky);
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
const auto& t = v.as_table();
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return found->second;
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
basic_value<C, M, V>&
|
||||||
|
find_fuzzy(basic_value<C, M, V>& v, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return find(v, ky);
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
auto& t = v.as_table();
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return found->second;
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher = levenstein_matcher>
|
||||||
|
basic_value<C, M, V>&&
|
||||||
|
find_fuzzy(basic_value<C, M, V>&& v_, const key& ky,
|
||||||
|
const FuzzyMatcher match = levenstein_matcher(1))
|
||||||
|
{
|
||||||
|
basic_value<C, M, V> v = v_; // to re-use later, store it once
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return std::move(find(v, ky));
|
||||||
|
}
|
||||||
|
catch(const std::out_of_range& oor)
|
||||||
|
{
|
||||||
|
auto& t = v.as_table();
|
||||||
|
const auto found = detail::find_unique(t.begin(), t.end(), v, ky, match);
|
||||||
|
if(found != t.end())
|
||||||
|
{
|
||||||
|
return std::move(found->second);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// find(v, k, matcher)
|
||||||
|
//
|
||||||
|
// when matcher is passed, check a key that matches exists or not. if it exists,
|
||||||
|
// suggest that in the error message
|
||||||
|
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
basic_value<C, M, V> const&
|
||||||
|
find(const basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
const auto& tab = v.template cast<value_t::table>();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return tab.at(ky);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
basic_value<C, M, V>&
|
||||||
|
find(basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
auto& tab = v.template cast<value_t::table>();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return tab.at(ky);
|
||||||
|
}
|
||||||
|
template<typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
basic_value<C, M, V>&&
|
||||||
|
find(basic_value<C, M, V>&& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
auto tab = std::move(v).as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return std::move(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// find<T>(value, key, fuzzy_matcher);
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))>
|
||||||
|
find(const basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
const auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this here?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))>
|
||||||
|
find(basic_value<C, M, V>& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
auto& tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this here?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(tab.at(ky));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename C,
|
||||||
|
template<typename ...> class M, template<typename ...> class V,
|
||||||
|
typename FuzzyMatcher>
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::negation<std::is_convertible<FuzzyMatcher, std::string>>::value,
|
||||||
|
decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))>
|
||||||
|
find(basic_value<C, M, V>&& v, const key& ky, FuzzyMatcher match)
|
||||||
|
{
|
||||||
|
auto tab = v.as_table();
|
||||||
|
if(tab.count(ky) == 0)
|
||||||
|
{
|
||||||
|
for(const auto& kv : tab)
|
||||||
|
{
|
||||||
|
if(match(kv.first, ky))
|
||||||
|
{
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found."), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"},
|
||||||
|
{std::addressof(detail::get_region(kv.second)),
|
||||||
|
"did you mean this here?"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||||
|
"[error] key \"", ky, "\" not found"), {
|
||||||
|
{std::addressof(detail::get_region(v)), "in this table"}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return ::toml::get<T>(std::move(tab.at(ky)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // toml
|
||||||
|
#endif// TOML11_FIND_HPP
|
||||||
346
toml/get.hpp
346
toml/get.hpp
@@ -420,158 +420,6 @@ T get(const basic_value<C, M, V>& v)
|
|||||||
return ::toml::from<T>::from_toml(v);
|
return ::toml::from<T>::from_toml(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// find and get
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// these overloads do not require to set T. and returns value itself.
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
|
||||||
{
|
|
||||||
const auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return tab.at(ky);
|
|
||||||
}
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
|
||||||
{
|
|
||||||
auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return tab.at(ky);
|
|
||||||
}
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V>&& find(basic_value<C, M, V>&& v, const key& ky)
|
|
||||||
{
|
|
||||||
auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return std::move(tab.at(ky));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// find<T>(value, key);
|
|
||||||
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
|
|
||||||
find(const basic_value<C, M, V>& v, const key& ky)
|
|
||||||
{
|
|
||||||
const auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return ::toml::get<T>(tab.at(ky));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 key& ky)
|
|
||||||
{
|
|
||||||
auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return ::toml::get<T>(tab.at(ky));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 key& ky)
|
|
||||||
{
|
|
||||||
auto& tab = v.template cast<value_t::table>();
|
|
||||||
if(tab.count(ky) == 0)
|
|
||||||
{
|
|
||||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
|
||||||
"[error] key \"", ky, "\" not found"), {
|
|
||||||
{std::addressof(detail::get_region(v)), "in this table"}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
typename ... Ts>
|
|
||||||
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,
|
|
||||||
typename ... Ts>
|
|
||||||
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,
|
|
||||||
typename ... Ts>
|
|
||||||
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,
|
|
||||||
typename ... Ts>
|
|
||||||
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)
|
// get_or(value, fallback)
|
||||||
|
|
||||||
@@ -745,199 +593,5 @@ get_or(const basic_value<C, M, V>& v, T&& opt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
// find_or(value, key, fallback)
|
|
||||||
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V> const&
|
|
||||||
find_or(const basic_value<C, M, V>& v, const key& ky,
|
|
||||||
const basic_value<C, M, V>& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
const auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return tab.at(ky);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V>&
|
|
||||||
find_or(basic_value<C, M, V>& v, const toml::key& ky, basic_value<C, M, V>& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return tab[ky];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
basic_value<C, M, V>
|
|
||||||
find_or(basic_value<C, M, V>&& v, const toml::key& ky, basic_value<C, M, V>&& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
auto tab = std::move(v).as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return std::move(tab[ky]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// exact types (return type can be a reference)
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<
|
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
|
|
||||||
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
const auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return get_or(tab.at(ky), opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<
|
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
|
|
||||||
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return get_or(tab[ky], opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<
|
|
||||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&&
|
|
||||||
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
auto tab = std::move(v).as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return get_or(std::move(tab[ky]), std::forward<T>(opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// std::string (return type can be a reference)
|
|
||||||
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
|
|
||||||
find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
const auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return get_or(tab.at(ky), opt);
|
|
||||||
}
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
|
|
||||||
find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return opt;}
|
|
||||||
auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return opt;}
|
|
||||||
return get_or(tab.at(ky), opt);
|
|
||||||
}
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
|
|
||||||
find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return std::forward<T>(opt);}
|
|
||||||
auto tab = std::move(v).as_table();
|
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
|
||||||
return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// string literal (deduced as std::string)
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<
|
|
||||||
detail::is_string_literal<typename std::remove_reference<T>::type>::value,
|
|
||||||
std::string>
|
|
||||||
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return std::string(opt);}
|
|
||||||
const auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return std::string(opt);}
|
|
||||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// others (require type conversion and return type cannot be lvalue reference)
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
detail::enable_if_t<detail::conjunction<
|
|
||||||
// T is not an exact toml type
|
|
||||||
detail::negation<detail::is_exact_toml_type<
|
|
||||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type,
|
|
||||||
basic_value<C, M, V>>>,
|
|
||||||
// T is not std::string
|
|
||||||
detail::negation<std::is_same<std::string,
|
|
||||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type>>,
|
|
||||||
// T is not a string literal
|
|
||||||
detail::negation<detail::is_string_literal<
|
|
||||||
typename std::remove_reference<T>::type>>
|
|
||||||
>::value, typename std::remove_cv<typename std::remove_reference<T>::type>::type>
|
|
||||||
find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
|
||||||
{
|
|
||||||
if(!v.is_table()) {return std::forward<T>(opt);}
|
|
||||||
const auto& tab = v.as_table();
|
|
||||||
if(tab.count(ky) == 0) {return std::forward<T>(opt);}
|
|
||||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// expect
|
|
||||||
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
result<T, std::string> expect(const basic_value<C, M, V>& v) noexcept
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ok(get<T>(v));
|
|
||||||
}
|
|
||||||
catch(const std::exception& e)
|
|
||||||
{
|
|
||||||
return err(e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<typename T, typename C,
|
|
||||||
template<typename ...> class M, template<typename ...> class V>
|
|
||||||
result<T, std::string>
|
|
||||||
expect(const basic_value<C, M, V>& v, const toml::key& k) noexcept
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ok(find<T>(v, k));
|
|
||||||
}
|
|
||||||
catch(const std::exception& e)
|
|
||||||
{
|
|
||||||
return err(e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<typename T, typename Table>
|
|
||||||
detail::enable_if_t<detail::conjunction<
|
|
||||||
detail::is_map<Table>, detail::is_basic_value<typename Table::mapped_type>
|
|
||||||
>::value, result<T, std::string>>
|
|
||||||
expect(const Table& t, const toml::key& k,
|
|
||||||
std::string tablename = "unknown table") noexcept
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ok(find<T>(t, k, std::move(tablename)));
|
|
||||||
}
|
|
||||||
catch(const std::exception& e)
|
|
||||||
{
|
|
||||||
return err(e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_GET
|
#endif// TOML11_GET
|
||||||
|
|||||||
Reference in New Issue
Block a user