Skip to content

Commit

Permalink
Merge pull request #280 from ken-matsui/find_or_default
Browse files Browse the repository at this point in the history
Implement find_or_default
  • Loading branch information
ToruNiina authored Jan 18, 2025
2 parents 499be3c + 4ceba3a commit 9251741
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/content.en/docs/features/value.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,17 @@ This is useful when you want to provide a fallback value instead of handling exc
const auto a = toml::find_or(input, "a", 42);
```

## Using `toml::find_or_default` to Search and Use the Default Value on Failure

`toml::find_or_default` works similarly to `toml::find_or<T>` but returns the default constructor result if the search or conversion fails.

This is useful when you want to use the default value instead of handling exceptions, especially when the default construction is costly, as this delays it until the actual failure happens.

```cpp
const auto a = toml::find_or(input, "a", expensive()); // ctor is called before the function call
const auto a = toml::find_or_default<expensive>(input, "a"); // ctor will be called only on failure
```

## `toml::find<std::optional<T>>`

If `std::optional` is available, you can specify `std::optional` as a template argument of `toml::find`.
Expand Down
11 changes: 11 additions & 0 deletions docs/content.ja/docs/features/value.md
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,17 @@ const auto a = toml::find_or(input, "a", 42);

型変換の失敗だけでなく、キーが見つからなかった場合もデフォルト値を返します。

## `toml::find_or_default`を使って失敗時の値を指定する

`toml::find_or_default` は、 `toml::find_or` と同様に、失敗時にデフォルトコンストラクタの結果を返します。デフォルトコンストラクタは失敗時のみに呼ばれるため、特にそれが高価な時に有効です。

```cpp
const auto a = toml::find_or(input, "a", expensive()); // 関数呼出前にコンストラクタ呼出
const auto a = toml::find_or_default<expensive>(input, "a"); // 失敗時にのみコンストラクタ呼出
```

型変換の失敗だけでなく、キーが見つからなかった場合もデフォルトコンストラクタの結果を返します。

## `toml::find<std::optional<T>>`

C++17以降の場合、`std::optional``toml::find`に指定することができます。
Expand Down
31 changes: 31 additions & 0 deletions include/toml11/find.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,5 +544,36 @@ T find_or(const basic_value<TC>& v, const K1& k1, const K2& k2, const K3& k3, co
}
}

// ===========================================================================
// find_or_default<T>(value, key)

template<typename T, typename TC, typename K>
cxx::enable_if_t<std::is_default_constructible<T>::value, T>
find_or_default(const basic_value<TC>& v, K&& k) noexcept(std::is_nothrow_default_constructible<T>::value)
{
try
{
return ::toml::get<T>(v.at(detail::key_cast<TC>(std::forward<K>(k))));
}
catch(...)
{
return T();
}
}

template<typename T, typename TC, typename K1, typename ... Ks>
cxx::enable_if_t<std::is_default_constructible<T>::value, T>
find_or_default(const basic_value<TC>& v, K1&& k1, Ks&& ... keys) noexcept(std::is_nothrow_default_constructible<T>::value)
{
try
{
return find_or_default<T>(v.at(std::forward<K1>(k1)), std::forward<Ks>(keys)...);
}
catch(...)
{
return T();
}
}

} // toml
#endif // TOML11_FIND_HPP
83 changes: 83 additions & 0 deletions tests/test_find_or.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,3 +673,86 @@ TEST_CASE("testing find_or(val, keys..., opt)")
CHECK_EQ(v2, 3.14);
}
}

TEST_CASE("testing find_or_default(val, keys...)")
{
// explicitly specify type, doing type conversion
{
const toml::value v(
toml::table{ {"foo",
toml::table{ {"bar",
toml::table{ {"baz",
42
} }
} }
} }
);
auto v1 = toml::find_or_default<int>(v, "foo", "bar", "baz");
auto v2 = toml::find_or_default<int>(v, "foo", "bar", "qux");

CHECK_EQ(v1, 42);
CHECK_EQ(v2, 0);
}
{
toml::value v(
toml::table{ {"A",
toml::table{ {"B",
toml::table{ {"C",
toml::table{ {"D",
toml::table{ {"E",
toml::table{ {"F",
42
} }
} }
} }
} }
} }
} }
);
auto v1 = toml::find_or_default<int>(v, "A", "B", "C", "D", "E", "F");
auto v2 = toml::find_or_default<int>(v, "A", "B", "C", "D", "E", "G");

CHECK_EQ(v1, 42);
CHECK_EQ(v2, 0);
}

// the value exists, but type is different from the expected.
{
const toml::value v(
toml::table{ {"foo",
toml::table{ {"bar",
toml::table{ {"baz",
42
} }
} }
} }
);
auto v1 = toml::find_or_default<std::string>(v, "foo", "bar", "baz");
auto v2 = toml::find_or_default<double >(v, "foo", "bar", "baz");

CHECK_EQ(v1, "");
CHECK_EQ(v2, 0.);
}
{
const toml::value v(
toml::table{ {"A",
toml::table{ {"B",
toml::table{ {"C",
toml::table{ {"D",
toml::table{ {"E",
toml::table{ {"F",
42
} }
} }
} }
} }
} }
} }
);
auto v1 = toml::find_or_default<std::string>(v, "A", "B", "C", "D", "E", "F");
auto v2 = toml::find_or_default<double >(v, "A", "B", "C", "D", "E", "F");

CHECK_EQ(v1, "");
CHECK_EQ(v2, 0.);
}
}

0 comments on commit 9251741

Please sign in to comment.