diff --git a/tests/test_get_related_func.cpp b/tests/test_get_related_func.cpp index c47d8b6..30eb362 100644 --- a/tests/test_get_related_func.cpp +++ b/tests/test_get_related_func.cpp @@ -45,21 +45,194 @@ BOOST_AUTO_TEST_CASE(test_find) BOOST_AUTO_TEST_CASE(test_get_or) { - { - toml::table v{{"num", 42}}; - BOOST_CHECK_EQUAL(42, toml::get_or(v, "num", 0)); - BOOST_CHECK_EQUAL(0, toml::get_or(v, "foo", 0)); - } - { - toml::value v = toml::table{{"num", 42}}; - BOOST_CHECK_EQUAL(42, toml::get_or(v, "num", 0)); - BOOST_CHECK_EQUAL(0, toml::get_or(v, "foo", 0)); - } + // requires conversion int -> uint { toml::value v1(42); toml::value v2(3.14); - BOOST_CHECK_EQUAL(42, toml::get_or(v1, 0)); - BOOST_CHECK_EQUAL(0, toml::get_or(v2, 0)); + BOOST_CHECK_EQUAL(42u, toml::get_or(v1, 0u)); + BOOST_CHECK_EQUAL(0u, toml::get_or(v2, 0u)); + } + + // exact toml type + { + toml::value v1(42); + toml::value v2(3.14); + + toml::integer opt(0); + BOOST_CHECK_EQUAL(42, toml::get_or(v1, opt)); + BOOST_CHECK_EQUAL(0, toml::get_or(v2, opt)); + + toml::value v3("foobar"); + toml::string s("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::get_or(v3, s)); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v1, s)); + + } + + // std::string + { + toml::value v1("foobar"); + toml::value v2(42); + + std::string s1("bazqux"); + const std::string s2("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s1)); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s1)); + + std::string& v1r = toml::get_or(v1, s1); + std::string& s1r = toml::get_or(v2, s1); + + BOOST_CHECK_EQUAL("foobar", v1r); + BOOST_CHECK_EQUAL("bazqux", s1r); + + BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, s2)); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, s2)); + + BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, std::move(s1))); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, std::move(s1))); + } + + // string literal + { + toml::value v1("foobar"); + toml::value v2(42); + + BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, "bazqux")); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, "bazqux")); + + const char* lit = "bazqux"; + BOOST_CHECK_EQUAL("foobar", toml::get_or(v1, lit)); + BOOST_CHECK_EQUAL("bazqux", toml::get_or(v2, lit)); + } +} + +BOOST_AUTO_TEST_CASE(test_find_or) +{ + // ======================================================================== + // pass toml::value + // + // requires conversion int -> uint + { + toml::table v{{"num", 42}}; + BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u)); + BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u)); + } + // exact toml type + { + toml::table v1{{"key", 42 }}; + toml::table v2{{"key", 3.14}}; + toml::table v3{{"not", "key"}}; + + toml::integer opt(0); + BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", opt)); + BOOST_CHECK_EQUAL(0, toml::find_or(v2, "key", opt)); + BOOST_CHECK_EQUAL(0, toml::find_or(v3, "key", opt)); + + toml::table v4{{"str", "foobar"}}; + toml::string s("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s)); + } + // std::string + { + toml::table v1{{"key", "foobar"}}; + toml::table v2{{"key", 42}}; + + std::string s1("bazqux"); + const std::string s2("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1)); + + std::string& v1r = toml::find_or(v1, "key", s1); + std::string& s1r = toml::find_or(v2, "key", s1); + + BOOST_CHECK_EQUAL("foobar", v1r); + BOOST_CHECK_EQUAL("bazqux", s1r); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2)); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1))); + s1 = "bazqux"; // restoring moved value + BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1))); + } + // string literal + { + toml::table v1{{"key", "foobar"}}; + toml::table v2{{"key",42}}; + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux")); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux")); + + const char* lit = "bazqux"; + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit)); + } + + // ======================================================================== + // pass toml::value + // + // requires conversion int -> uint + { + toml::table v = toml::table{{"num", 42}}; + BOOST_CHECK_EQUAL(42u, toml::find_or(v, "num", 0u)); + BOOST_CHECK_EQUAL(0u, toml::find_or(v, "foo", 0u)); + } + // exact toml type + { + toml::value v1 = toml::table{{"key", 42 }}; + toml::value v2 = toml::table{{"key", 3.14}}; + toml::value v3 = toml::table{{"not", "key"}}; + + BOOST_CHECK_EQUAL(42, toml::find_or(v1, "key", toml::integer(0))); + BOOST_CHECK_EQUAL( 0, toml::find_or(v2, "key", toml::integer(0))); + BOOST_CHECK_EQUAL( 0, toml::find_or(v3, "key", toml::integer(0))); + + toml::value v4 = toml::table{{"str", "foobar"}}; + toml::string s("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v4, "str", s)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v1, "str", s)); + } + // std::string + { + toml::value v1 = toml::table{{"key", "foobar"}}; + toml::value v2 = toml::table{{"key", 42}}; + + std::string s1("bazqux"); + const std::string s2("bazqux"); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s1)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s1)); + + std::string& v1r = toml::find_or(v1, "key", s1); + std::string& s1r = toml::find_or(v2, "key", s1); + + BOOST_CHECK_EQUAL("foobar", v1r); + BOOST_CHECK_EQUAL("bazqux", s1r); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", s2)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", s2)); + + BOOST_CHECK_EQUAL("foobar", toml::find_or(std::move(v1), "key", std::move(s1))); + s1 = "bazqux"; // restoring moved value + BOOST_CHECK_EQUAL("bazqux", toml::find_or(std::move(v2), "key", std::move(s1))); + } + // string literal + { + toml::value v1 = toml::table{{"key", "foobar"}}; + toml::value v2 = toml::table{{"key",42}}; + + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", "bazqux")); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", "bazqux")); + + const char* lit = "bazqux"; + BOOST_CHECK_EQUAL("foobar", toml::find_or(v1, "key", lit)); + BOOST_CHECK_EQUAL("bazqux", toml::find_or(v2, "key", lit)); } } diff --git a/toml/get.hpp b/toml/get.hpp index 6aad019..ed211b0 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -420,13 +420,14 @@ find(toml::value&& v, const toml::key& ky) // ============================================================================ -// get_or +// get_or(value, fallback) -template -decltype(::toml::get::type>::type>( - std::declval())) -get_or(const toml::value& v, T&& opt) +// ---------------------------------------------------------------------------- +// specialization for the exact toml types (return type becomes lvalue ref) + +template::value, std::nullptr_t>::type = nullptr> +T const& get_or(const toml::value& v, const T& opt) { try { @@ -435,14 +436,12 @@ get_or(const toml::value& v, T&& opt) } catch(...) { - return std::forward(opt); + return opt; } } -template -decltype(::toml::get::type>::type>( - std::declval())) -get_or(toml::value& v, T&& opt) +template::value, std::nullptr_t>::type = nullptr> +T& get_or(toml::value& v, T& opt) { try { @@ -451,77 +450,333 @@ get_or(toml::value& v, T&& opt) } catch(...) { - return std::forward(opt); + return opt; } } -template -decltype(::toml::get::type>::type>( - std::declval())) -get_or(toml::value&& v, T&& opt) +template::value, std::nullptr_t>::type = nullptr> +T&& get_or(toml::value&& v, T&& opt) { try { return get::type>::type>(std::move(v)); + typename std::remove_reference::type>::type>(v); } catch(...) { - return std::forward(opt); + return opt; } } +// ---------------------------------------------------------------------------- +// specialization for std::string (return type becomes lvalue ref) + +template::value, std::nullptr_t>::type = nullptr> +std::string const& get_or(const toml::value& v, const T& opt) +{ + try + { + return get(v); + } + catch(...) + { + return opt; + } +} +template::value, std::nullptr_t>::type = nullptr> +std::string& get_or(toml::value& v, T& opt) +{ + try + { + return get(v); + } + catch(...) + { + return opt; + } +} +template::value, std::nullptr_t>::type = nullptr> +std::string get_or(toml::value&& v, T&& opt) +{ + try + { + return get(v); + } + catch(...) + { + return opt; + } +} +template::type>::value, + std::nullptr_t>::type = nullptr> +std::string get_or(const toml::value& v, T&& opt) +{ + try + { + return get(v); + } + catch(...) + { + return std::string(opt); + } +} + +// ---------------------------------------------------------------------------- +// others (require type conversion and return type cannot be lvalue reference) + +template>, + detail::negation>, + detail::negation::type>> + >::value, std::nullptr_t>::type = nullptr> +T get_or(const toml::value& v, T&& opt) +{ + try + { + return get::type>::type>(v); + } + catch(...) + { + return opt; + } +} + +// =========================================================================== +// get_or(table, key, fallback) +// +// DEPRECATED: use find_or instead. template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.") auto get_or(const toml::table& tab, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(tab.at(ky), std::forward(opt)); } template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.") auto get_or(toml::table& tab, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(tab[ky], std::forward(opt)); } template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(table, key, opt) instead.") auto get_or(toml::table&& tab, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(std::move(tab[ky]), std::forward(opt)); } template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.") auto get_or(const toml::value& v, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(v.type() != toml::value_t::Table){return std::forward(opt);} + if(!v.is_table()) {return opt;} const auto& tab = toml::get(v); - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(tab.at(ky), std::forward(opt)); } template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.") auto get_or(toml::value& v, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(v.type() != toml::value_t::Table){return std::forward(opt);} + if(!v.is_table()) {return opt;} auto& tab = toml::get(v); - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(tab[ky], std::forward(opt)); } template +TOML11_MARK_AS_DEPRECATED("use toml::find_or(value, key, opt) instead.") auto get_or(toml::value&& v, const toml::key& ky, T&& opt) -> decltype(get_or(std::declval(), std::forward(opt))) { - if(v.type() != toml::value_t::Table){return std::forward(opt);} + if(!v.is_table()) {return opt;} auto tab = toml::get(std::move(v)); - if(tab.count(ky) == 0) {return std::forward(opt);} + if(tab.count(ky) == 0) {return opt;} return ::toml::get_or(std::move(tab[ky]), std::forward(opt)); } +// =========================================================================== +// find_or(value, key, fallback) + +// --------------------------------------------------------------------------- +// exact types (return type can be a reference) +template::value, std::nullptr_t>::type = nullptr> +T const& find_or(const toml::value& v, const toml::key& ky, const T& opt) +{ + if(!v.is_table()) {return opt;} + const auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), opt); +} + +template::value, std::nullptr_t>::type = nullptr> +T& find_or(toml::value& v, const toml::key& ky, T& opt) +{ + if(!v.is_table()) {return opt;} + auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return opt;} + return get_or(tab[ky], opt); +} + +template::value, std::nullptr_t>::type = nullptr> +T&& find_or(toml::value&& v, const toml::key& ky, T&& opt) +{ + if(!v.is_table()) {return opt;} + auto tab = toml::get(std::move(v)); + if(tab.count(ky) == 0) {return opt;} + return get_or(std::move(tab[ky]), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// std::string (return type can be a reference) +template::value, std::nullptr_t>::type = nullptr> +std::string const& find_or(const toml::value& v, const toml::key& ky, const T& opt) +{ + if(!v.is_table()) {return opt;} + const auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), opt); +} +template::value, std::nullptr_t>::type = nullptr> +std::string& find_or(toml::value& v, const toml::key& ky, T& opt) +{ + if(!v.is_table()) {return opt;} + auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return opt;} + return get_or(tab[ky], opt); +} +template::value, std::nullptr_t>::type = nullptr> +std::string find_or(toml::value&& v, const toml::key& ky, T&& opt) +{ + if(!v.is_table()) {return opt;} + auto tab = toml::get(std::move(v)); + if(tab.count(ky) == 0) {return opt;} + return get_or(std::move(tab[ky]), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// string literal (deduced as std::string) +template::type>::value, + std::nullptr_t>::type = nullptr> +std::string find_or(const toml::value& v, const toml::key& ky, T&& opt) +{ + if(!v.is_table()) {return opt;} + const auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return std::string(opt);} + return get_or(tab.at(ky), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// others (require type conversion and return type cannot be lvalue reference) +template>, + detail::negation>, + detail::negation::type>> + >::value, std::nullptr_t>::type = nullptr> +T find_or(const toml::value& v, const toml::key& ky, T&& opt) +{ + if(!v.is_table()) {return opt;} + const auto& tab = toml::get(v); + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), std::forward(opt)); +} + +// =========================================================================== +// find_or(table, key, opt) + +// --------------------------------------------------------------------------- +// exact types (return type can be a reference) +template::value, std::nullptr_t>::type = nullptr> +T const& find_or(const toml::table& tab, const toml::key& ky, const T& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), opt); +} + +template::value, std::nullptr_t>::type = nullptr> +T& find_or(toml::table& tab, const toml::key& ky, T& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(tab[ky], opt); +} + +template::value, std::nullptr_t>::type = nullptr> +T&& find_or(toml::table&& tab, const toml::key& ky, T&& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(std::move(tab[ky]), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// std::string (return type can be a reference) +template::value, std::nullptr_t>::type = nullptr> +std::string const& find_or(const toml::table& tab, const toml::key& ky, const T& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), opt); +} +template::value, std::nullptr_t>::type = nullptr> +std::string& find_or(toml::table& tab, const toml::key& ky, T& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(tab[ky], opt); +} +template::value, std::nullptr_t>::type = nullptr> +std::string find_or(toml::table&& tab, const toml::key& ky, T&& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(std::move(tab[ky]), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// string literal (deduced as std::string) +template::type>::value, + std::nullptr_t>::type = nullptr> +std::string find_or(const toml::table& tab, const toml::key& ky, T&& opt) +{ + if(tab.count(ky) == 0) {return std::string(opt);} + return get_or(tab.at(ky), std::forward(opt)); +} + +// --------------------------------------------------------------------------- +// others (require type conversion and return type cannot be lvalue reference) +template>, + detail::negation>, + detail::negation::type>> + >::value, std::nullptr_t>::type = nullptr> +T find_or(const toml::table& tab, const toml::key& ky, T&& opt) +{ + if(tab.count(ky) == 0) {return opt;} + return get_or(tab.at(ky), std::forward(opt)); +} + // ============================================================================ // expect diff --git a/toml/traits.hpp b/toml/traits.hpp index 7f8f413..7f5654b 100644 --- a/toml/traits.hpp +++ b/toml/traits.hpp @@ -169,6 +169,21 @@ using return_type_of_t = typename std::result_of::type; #endif +// --------------------------------------------------------------------------- +// is_string_literal +// +// to use this, pass `typename remove_reference::type` to T. + +template +struct is_string_literal: +disjunction< + std::is_same, + conjunction< + std::is_array, + std::is_same::type> + > + >{}; + }// detail }//toml #endif // TOML_TRAITS diff --git a/toml/utility.hpp b/toml/utility.hpp index 01fe6d7..238a87d 100644 --- a/toml/utility.hpp +++ b/toml/utility.hpp @@ -8,11 +8,11 @@ #include #if __cplusplus >= 201402L -# define TOML11_MARK_AS_DEPRECATED [[deprecated]] +# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]] #elif defined(__GNUC__) -# define TOML11_MARK_AS_DEPRECATED __attribute__((deprecated)) +# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg))) #elif defined(_MSC_VER) -# define TOML11_MARK_AS_DEPRECATED __declspec(deprecated) +# define TOML11_MARK_AS_DEPRECATED(msg) __declspec(deprecated(msg)) #else # define TOML11_MARK_AS_DEPRECATED #endif