#ifndef TOML11_FIND_HPP #define TOML11_FIND_HPP #include #include "get.hpp" #include "value.hpp" #if defined(TOML11_HAS_STRING_VIEW) #include #endif namespace toml { // ---------------------------------------------------------------------------- // find(value, key); template decltype(::toml::get(std::declval const&>())) find(const basic_value& v, const typename basic_value::key_type& ky) { return ::toml::get(v.at(ky)); } template decltype(::toml::get(std::declval&>())) find(basic_value& v, const typename basic_value::key_type& ky) { return ::toml::get(v.at(ky)); } template decltype(::toml::get(std::declval&&>())) find(basic_value&& v, const typename basic_value::key_type& ky) { return ::toml::get(std::move(v.at(ky))); } // ---------------------------------------------------------------------------- // find(value, idx) template decltype(::toml::get(std::declval const&>())) find(const basic_value& v, const std::size_t idx) { return ::toml::get(v.at(idx)); } template decltype(::toml::get(std::declval&>())) find(basic_value& v, const std::size_t idx) { return ::toml::get(v.at(idx)); } template decltype(::toml::get(std::declval&&>())) find(basic_value&& v, const std::size_t idx) { return ::toml::get(std::move(v.at(idx))); } // ---------------------------------------------------------------------------- // find(value, key/idx), w/o conversion template cxx::enable_if_t::value, basic_value>& find(basic_value& v, const typename basic_value::key_type& ky) { return v.at(ky); } template cxx::enable_if_t::value, basic_value> const& find(basic_value const& v, const typename basic_value::key_type& ky) { return v.at(ky); } template cxx::enable_if_t::value, basic_value> find(basic_value&& v, const typename basic_value::key_type& ky) { return basic_value(std::move(v.at(ky))); } template cxx::enable_if_t::value, basic_value>& find(basic_value& v, const std::size_t idx) { return v.at(idx); } template cxx::enable_if_t::value, basic_value> const& find(basic_value const& v, const std::size_t idx) { return v.at(idx); } template cxx::enable_if_t::value, basic_value> find(basic_value&& v, const std::size_t idx) { return basic_value(std::move(v.at(idx))); } // -------------------------------------------------------------------------- // toml::find(toml::value, toml::key, Ts&& ... keys) namespace detail { // It suppresses warnings by -Wsign-conversion when we pass integer literal // to toml::find. integer literal `0` is deduced as an int, and will be // converted to std::size_t. This causes sign-conversion. template std::size_t key_cast(const std::size_t& v) noexcept { return v; } template cxx::enable_if_t>::value, std::size_t> key_cast(const T& v) noexcept { return static_cast(v); } // for string-like (string, string literal, string_view) template typename basic_value::key_type const& key_cast(const typename basic_value::key_type& v) noexcept { return v; } template typename basic_value::key_type key_cast(const typename basic_value::key_type::value_type* v) { return typename basic_value::key_type(v); } #if defined(TOML11_HAS_STRING_VIEW) template typename basic_value::key_type key_cast(const std::string_view v) { return typename basic_value::key_type(v); } #endif // string_view } // detail // ---------------------------------------------------------------------------- // find(v, keys...) template cxx::enable_if_t::value, basic_value> const& find(const basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); } template cxx::enable_if_t::value, basic_value>& find(basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); } template cxx::enable_if_t::value, basic_value> find(basic_value&& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(std::move(v.at(detail::key_cast(k1))), detail::key_cast(k2), ks...); } // ---------------------------------------------------------------------------- // find(v, keys...) template decltype(::toml::get(std::declval&>())) find(const basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); } template decltype(::toml::get(std::declval&>())) find(basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); } template decltype(::toml::get(std::declval&&>())) find(basic_value&& v, const K1& k1, const K2& k2, const Ks& ... ks) { return find(std::move(v.at(detail::key_cast(k1))), detail::key_cast(k2), ks...); } // =========================================================================== // find_or(value, key, fallback) // --------------------------------------------------------------------------- // find_or(v, key, other_v) template cxx::enable_if_t::value, basic_value>& find_or(basic_value& v, const K& k, basic_value& opt) noexcept { try { return ::toml::find(v, detail::key_cast(k)); } catch(...) { return opt; } } template cxx::enable_if_t::value, basic_value> const& find_or(const basic_value& v, const K& k, const basic_value& opt) noexcept { try { return ::toml::find(v, detail::key_cast(k)); } catch(...) { return opt; } } template cxx::enable_if_t::value, basic_value> find_or(basic_value&& v, const K& k, basic_value&& opt) noexcept { try { return ::toml::find(v, detail::key_cast(k)); } catch(...) { return opt; } } // --------------------------------------------------------------------------- // toml types (return type can be a reference) template cxx::enable_if_t>::value, cxx::remove_cvref_t const&> find_or(const basic_value& v, const K& k, const T& opt) { try { return ::toml::get(v.at(detail::key_cast(k))); } catch(...) { return opt; } } template cxx::enable_if_t>, detail::is_exact_toml_type> >::value, cxx::remove_cvref_t&> find_or(basic_value& v, const K& k, T& opt) { try { return ::toml::get(v.at(detail::key_cast(k))); } catch(...) { return opt; } } template cxx::enable_if_t>::value, cxx::remove_cvref_t> find_or(basic_value&& v, const K& k, T opt) { try { return ::toml::get(std::move(v.at(detail::key_cast(k)))); } catch(...) { return T(std::move(opt)); } } // --------------------------------------------------------------------------- // string literal (deduced as std::string) // XXX to avoid confusion when T is explicitly specified in find_or(), // we restrict the string type as std::string. template cxx::enable_if_t::value, std::string> find_or(const basic_value& v, const K& k, const char* opt) { try { return ::toml::get(v.at(detail::key_cast(k))); } catch(...) { return std::string(opt); } } // --------------------------------------------------------------------------- // other types (requires type conversion and return type cannot be a reference) template cxx::enable_if_t>>, detail::is_not_toml_type, basic_value>, cxx::negation, const typename basic_value::string_type::value_type*>> >::value, cxx::remove_cvref_t> find_or(const basic_value& v, const K& ky, T opt) { try { return ::toml::get>(v.at(detail::key_cast(ky))); } catch(...) { return cxx::remove_cvref_t(std::move(opt)); } } // ---------------------------------------------------------------------------- // recursive namespace detail { template auto last_one(Ts&&... args) -> decltype(std::get(std::forward_as_tuple(std::forward(args)...))) { return std::get(std::forward_as_tuple(std::forward(args)...)); } } // detail template auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&& ... keys) noexcept -> cxx::enable_if_t< detail::is_basic_value>::value, decltype(find_or(v, k2, std::forward(k3), std::forward(keys)...)) > { try { return find_or(v.at(k1), k2, std::forward(k3), std::forward(keys)...); } catch(...) { return detail::last_one(k3, keys...); } } template T find_or(const basic_value& v, const K1& k1, const K2& k2, const K3& k3, const Ks& ... keys) noexcept { try { return find_or(v.at(k1), k2, k3, keys...); } catch(...) { return static_cast(detail::last_one(k3, keys...)); } } } // toml #endif // TOML11_FIND_HPP