feat(#156): add find_or(value, keys..., opt)

This commit is contained in:
ToruNiina 2021-04-14 11:21:48 +09:00
parent 8bc09d552a
commit ba3d41d913
2 changed files with 77 additions and 0 deletions

View File

@ -1033,6 +1033,24 @@ find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
return get_or(tab.at(ky), std::forward<T>(opt));
}
template<typename T, typename C,
template<typename ...> class M, template<typename ...> class V,
typename ... Ks>
auto find_or(const basic_value<C, M, V>& v, const toml::key& ky, Ks&& ... keys)
-> decltype(find_or<T>(v, ky, detail::last_one(std::forward<Ks>(keys)...)))
{
if(!v.is_table())
{
return detail::last_one(std::forward<Ks>(keys)...);
}
const auto& tab = v.as_table();
if(tab.count(ky) == 0)
{
return detail::last_one(std::forward<Ks>(keys)...);
}
return find_or(tab.at(ky), std::forward<Ks>(keys)...);
}
// ============================================================================
// expect

View File

@ -89,5 +89,64 @@ T from_string(const std::string& str, T opt)
return v;
}
namespace detail
{
#if __cplusplus >= 201402L
template<typename T>
decltype(auto) last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
{
return last_one(std::forward<Ts>(tail)...);
}
#else // C++11
// The following code
// ```cpp
// 1 | template<typename T, typename ... Ts>
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
// 4 | {
// 5 | return last_one(std::forward<Ts>(tail)...);
// 6 | }
// ```
// does not work because the function `last_one(...)` is not yet defined at
// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
// So we need to determine return type in a different way, like a meta func.
template<typename ... Ts>
struct last_one_in_pack;
template<typename T, typename ... Ts>
struct last_one_in_pack<T, Ts...>
{
using type = typename last_one_in_pack<Ts...>::type;
};
template<typename T>
struct last_one_in_pack<T>
{
using type = T;
};
template<typename ... Ts>
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
template<typename T>
T&& last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
last_one_in_pack_t<Ts&& ...>
last_one(T&& /*head*/, Ts&& ... tail)
{
return last_one(std::forward<Ts>(tail)...);
}
#endif
} // detail
}// toml
#endif // TOML11_UTILITY