diff --git a/docs/utility.adoc b/docs/utility.adoc index f1170a2..a83d8ad 100644 --- a/docs/utility.adoc +++ b/docs/utility.adoc @@ -242,6 +242,27 @@ type arguments which are defaults returned when lookup fails. In the case of mapping to values, the `*_lookup_v` aliases have optional third NTTP arguments in the same role. +Any of these type maps can also use reverse lookup, if values are unique: + +[source,cpp] +---- +// a type-type map that uses reverse_type_lookup_t +using M1 = stdx::type_map, stdx::tt_pair>; +using T1 = stdx::reverse_type_lookup_t; // A + +// a type-value map that uses reverse_value_lookup_t +using M2 = stdx::type_map, stdx::tv_pair>; +using T2 = stdx::reverse_value_lookup_t; // A + +// a value-type map that uses reverse_type_lookup_v +using M3 = stdx::type_map, stdx::vt_pair<1, Y>>; +constexpr auto v3 = stdx::reverse_type_lookup_v; // 0 + +// a value-value map that uses reverse_value_lookup_v +using M4 = stdx::type_map, stdx::vv_pair<1, 17>>; +constexpr auto v4 = stdx::reverse_value_lookup_v; // 0 +---- + === `unreachable` `unreachable` is an implementation of diff --git a/include/stdx/utility.hpp b/include/stdx/utility.hpp index e406a6b..0f6ff37 100644 --- a/include/stdx/utility.hpp +++ b/include/stdx/utility.hpp @@ -50,15 +50,29 @@ template constexpr static auto lookup(...) -> Default; template constexpr static auto lookup(type_pair) -> V; + +template +constexpr static auto reverse_lookup(...) -> Default; +template +constexpr static auto reverse_lookup(type_pair) -> K; } // namespace detail template using type_lookup_t = decltype(detail::lookup(std::declval())); +template +using reverse_type_lookup_t = + decltype(detail::reverse_lookup(std::declval())); + template using value_lookup_t = decltype(detail::lookup, Default>(std::declval())); +template +using reverse_value_lookup_t = + decltype(detail::reverse_lookup, Default>( + std::declval())); + namespace detail { template using is_not_void = std::bool_constant>; @@ -70,6 +84,12 @@ constexpr static auto type_lookup_v = decltype(detail::lookup(std::declval())), detail::value_t>::value; +template +constexpr static auto reverse_type_lookup_v = + type_or_t(std::declval())), + detail::value_t>::value; + template constexpr static auto value_lookup_v = type_or_t())), detail::value_t>::value; +template +constexpr static auto reverse_value_lookup_v = + type_or_t, void>( + std::declval())), + detail::value_t>::value; + #if __cpp_lib_forward_like < 202207L template [[nodiscard]] constexpr auto forward_like(U &&u) noexcept -> decltype(auto) { diff --git a/test/type_map.cpp b/test/type_map.cpp index 57693c1..abe36f1 100644 --- a/test/type_map.cpp +++ b/test/type_map.cpp @@ -57,3 +57,52 @@ TEST_CASE("look up value not in map (by value)", "[type map]") { STATIC_REQUIRE(stdx::value_lookup_v == 0); STATIC_REQUIRE(stdx::value_lookup_v == 3); } + +TEST_CASE("reverse look up type in map", "[type map]") { + using M = stdx::type_map, stdx::type_pair>; + STATIC_REQUIRE(std::is_same_v, A>); + STATIC_REQUIRE(std::is_same_v, B>); +} + +TEST_CASE("reverse look up type not in map", "[type map]") { + using M = stdx::type_map, stdx::type_pair>; + STATIC_REQUIRE(std::is_same_v, void>); + STATIC_REQUIRE(std::is_same_v, int>); +} + +TEST_CASE("reverse look up type in map (by value)", "[type map]") { + using M = stdx::type_map, stdx::tv_pair>; + STATIC_REQUIRE(std::is_same_v, X>); + STATIC_REQUIRE(std::is_same_v, Y>); +} + +TEST_CASE("reverse look up type not in map (by value)", "[type map]") { + using M = stdx::type_map, stdx::tv_pair>; + STATIC_REQUIRE(std::is_same_v, void>); + STATIC_REQUIRE( + std::is_same_v, int>); +} + +TEST_CASE("reverse look up value in map (by type)", "[type map]") { + using M = stdx::type_map, stdx::vt_pair<1, B>>; + STATIC_REQUIRE(stdx::reverse_type_lookup_v == 0); + STATIC_REQUIRE(stdx::reverse_type_lookup_v == 1); +} + +TEST_CASE("reverse look up value not in map (by type)", "[type map]") { + using M = stdx::type_map, stdx::vt_pair<1, B>>; + STATIC_REQUIRE(stdx::reverse_type_lookup_v == 0); + STATIC_REQUIRE(stdx::reverse_type_lookup_v == 2); +} + +TEST_CASE("reverse look up value in map (by value)", "[type map]") { + using M = stdx::type_map, stdx::vv_pair<1, 11>>; + STATIC_REQUIRE(stdx::reverse_value_lookup_v == 0); + STATIC_REQUIRE(stdx::reverse_value_lookup_v == 1); +} + +TEST_CASE("reverse look up value not in map (by value)", "[type map]") { + using M = stdx::type_map, stdx::vv_pair<1, 11>>; + STATIC_REQUIRE(stdx::reverse_value_lookup_v == 0); + STATIC_REQUIRE(stdx::reverse_value_lookup_v == 3); +}