From 014d882f8fae659fc41511eb66699279d67bc55c Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 7 Jun 2019 00:06:14 +0900 Subject: [PATCH] feat: enable to find value by recursive search --- tests/test_get_related_func.cpp | 80 ++++++++++++++++++++++++++++++--- toml/get.hpp | 26 +++++++++++ 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/tests/test_get_related_func.cpp b/tests/test_get_related_func.cpp index 30eb362..e6e448c 100644 --- a/tests/test_get_related_func.cpp +++ b/tests/test_get_related_func.cpp @@ -12,8 +12,9 @@ #include #include -BOOST_AUTO_TEST_CASE(test_find) +BOOST_AUTO_TEST_CASE(test_find_for_value) { + // value itself is not a table { toml::value v(true); bool thrown = false; @@ -27,22 +28,87 @@ BOOST_AUTO_TEST_CASE(test_find) } BOOST_CHECK(thrown); } - + // the value corresponding to the key is not the expected type { - toml::table v{{"num", 42}}; - BOOST_CHECK_EQUAL(42, toml::find(v, "num")); - toml::find(v, "num") = 54; - BOOST_CHECK_EQUAL(54, toml::find(v, "num")); + toml::value v{{"key", 42}}; + bool thrown = false; + try + { + toml::find(v, "key"); + } + catch(toml::type_error const& te) + { + thrown = true; + } + BOOST_CHECK(thrown); } { toml::value v = toml::table{{"num", 42}}; BOOST_CHECK_EQUAL(42, toml::find(v, "num")); - toml::find(v, "num") = 54; + + // reference that can be used to modify the content + auto& num = toml::find(v, "num"); + num = 54; BOOST_CHECK_EQUAL(54, toml::find(v, "num")); } + + // recursively search tables + { + toml::value v = toml::table{ + {"a", toml::table{ + {"b", toml::table{ + {"c", toml::table{ + {"d", 42} + }} + }} + }} + }; + BOOST_CHECK_EQUAL(42, toml::find(v, "a", "b", "c", "d")); + + // reference that can be used to modify the content + auto& num = toml::find(v, "a", "b", "c", "d"); + num = 54; + BOOST_CHECK_EQUAL(54, toml::find(v, "a", "b", "c", "d")); + + const std::string a("a"), b("b"), c("c"), d("d"); + auto& num2 = toml::find(v, a, b, c, d); + num2 = 42; + BOOST_CHECK_EQUAL(42, toml::find(v, a, b, c, d)); + } } +BOOST_AUTO_TEST_CASE(test_find_for_table) +{ + // the value corresponding to the key is not the expected type + { + toml::table v{{"key", 42}}; + bool thrown = false; + try + { + toml::find(v, "key"); + } + catch(toml::type_error const& te) + { + thrown = true; + } + BOOST_CHECK(thrown); + } + + { + toml::table v{{"num", 42}}; + BOOST_CHECK_EQUAL(42, toml::find(v, "num")); + + // reference that can be used to modify the content + auto& num = toml::find(v, "num"); + num = 54; + BOOST_CHECK_EQUAL(54, toml::find(v, "num")); + } + + // recursive search is not provided for tables. +} + + BOOST_AUTO_TEST_CASE(test_get_or) { // requires conversion int -> uint diff --git a/toml/get.hpp b/toml/get.hpp index cf2cec4..326f2a9 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -430,6 +430,32 @@ find(toml::value&& v, const toml::key& ky) return ::toml::get(std::move(tab[ky])); } +// -------------------------------------------------------------------------- +// toml::find(toml::value, toml::key, Ts&& ... keys) +// +// Note: C++ draft N3337 (14.1.11) says that... +// > If a template-parameter of a class template or alias template has a default +// > template-argument, each subsequent template-parameter shall either have a +// > default template-argument supplied or be a template parameter pack. +// So the template parameter pack can appear after a default template argument. +template +decltype(::toml::get(std::declval())) +find(const ::toml::value& v, const ::toml::key& ky, Ts&& ... keys) +{ + return ::toml::find(::toml::find(v, ky), std::forward(keys)...); +} +template +decltype(::toml::get(std::declval<::toml::value&>())) +find(::toml::value& v, const ::toml::key& ky, Ts&& ... keys) +{ + return ::toml::find(::toml::find(v, ky), std::forward(keys)...); +} +template +decltype(::toml::get(std::declval<::toml::value&&>())) +find(::toml::value&& v, const ::toml::key& ky, Ts&& ... keys) +{ + return ::toml::find(::toml::find(std::move(v), ky), std::forward(keys)...); +} // ============================================================================ // get_or(value, fallback)