Skip to content

Commit 0544692

Browse files
authored
Merge pull request #304 from elbeno/reverse-lookup
✨ Add reverse lookup to compile-time type maps
2 parents eb52714 + 119e469 commit 0544692

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

docs/utility.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,27 @@ type arguments which are defaults returned when lookup fails. In the case of
242242
mapping to values, the `*_lookup_v` aliases have optional third NTTP arguments
243243
in the same role.
244244

245+
Any of these type maps can also use reverse lookup, if values are unique:
246+
247+
[source,cpp]
248+
----
249+
// a type-type map that uses reverse_type_lookup_t
250+
using M1 = stdx::type_map<stdx::tt_pair<A, X>, stdx::tt_pair<B, Y>>;
251+
using T1 = stdx::reverse_type_lookup_t<M1, X>; // A
252+
253+
// a type-value map that uses reverse_value_lookup_t
254+
using M2 = stdx::type_map<stdx::tv_pair<A, 0>, stdx::tv_pair<B, 1>>;
255+
using T2 = stdx::reverse_value_lookup_t<M2, 0>; // A
256+
257+
// a value-type map that uses reverse_type_lookup_v
258+
using M3 = stdx::type_map<stdx::vt_pair<0, X>, stdx::vt_pair<1, Y>>;
259+
constexpr auto v3 = stdx::reverse_type_lookup_v<M3, X>; // 0
260+
261+
// a value-value map that uses reverse_value_lookup_v
262+
using M4 = stdx::type_map<stdx::vv_pair<0, 42>, stdx::vv_pair<1, 17>>;
263+
constexpr auto v4 = stdx::reverse_value_lookup_v<M4, 42>; // 0
264+
----
265+
245266
=== `unreachable`
246267

247268
`unreachable` is an implementation of

include/stdx/utility.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,29 @@ template <typename K, typename Default>
5050
constexpr static auto lookup(...) -> Default;
5151
template <typename K, typename Default, typename V>
5252
constexpr static auto lookup(type_pair<K, V>) -> V;
53+
54+
template <typename V, typename Default>
55+
constexpr static auto reverse_lookup(...) -> Default;
56+
template <typename V, typename Default, typename K>
57+
constexpr static auto reverse_lookup(type_pair<K, V>) -> K;
5358
} // namespace detail
5459

5560
template <typename M, typename K, typename Default = void>
5661
using type_lookup_t = decltype(detail::lookup<K, Default>(std::declval<M>()));
5762

63+
template <typename M, typename V, typename Default = void>
64+
using reverse_type_lookup_t =
65+
decltype(detail::reverse_lookup<V, Default>(std::declval<M>()));
66+
5867
template <typename M, auto K, typename Default = void>
5968
using value_lookup_t =
6069
decltype(detail::lookup<detail::value_t<K>, Default>(std::declval<M>()));
6170

71+
template <typename M, auto V, typename Default = void>
72+
using reverse_value_lookup_t =
73+
decltype(detail::reverse_lookup<detail::value_t<V>, Default>(
74+
std::declval<M>()));
75+
6276
namespace detail {
6377
template <typename T>
6478
using is_not_void = std::bool_constant<not std::is_void_v<T>>;
@@ -70,13 +84,26 @@ constexpr static auto type_lookup_v =
7084
decltype(detail::lookup<K, void>(std::declval<M>())),
7185
detail::value_t<Default>>::value;
7286

87+
template <typename M, typename V, auto Default = 0>
88+
constexpr static auto reverse_type_lookup_v =
89+
type_or_t<detail::is_not_void,
90+
decltype(detail::reverse_lookup<V, void>(std::declval<M>())),
91+
detail::value_t<Default>>::value;
92+
7393
template <typename M, auto K, auto Default = 0>
7494
constexpr static auto value_lookup_v =
7595
type_or_t<detail::is_not_void,
7696
decltype(detail::lookup<detail::value_t<K>, void>(
7797
std::declval<M>())),
7898
detail::value_t<Default>>::value;
7999

100+
template <typename M, auto V, auto Default = 0>
101+
constexpr static auto reverse_value_lookup_v =
102+
type_or_t<detail::is_not_void,
103+
decltype(detail::reverse_lookup<detail::value_t<V>, void>(
104+
std::declval<M>())),
105+
detail::value_t<Default>>::value;
106+
80107
#if __cpp_lib_forward_like < 202207L
81108
template <typename T, typename U>
82109
[[nodiscard]] constexpr auto forward_like(U &&u) noexcept -> decltype(auto) {

test/type_map.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,52 @@ TEST_CASE("look up value not in map (by value)", "[type map]") {
5757
STATIC_REQUIRE(stdx::value_lookup_v<M, 2> == 0);
5858
STATIC_REQUIRE(stdx::value_lookup_v<M, 2, 3> == 3);
5959
}
60+
61+
TEST_CASE("reverse look up type in map", "[type map]") {
62+
using M = stdx::type_map<stdx::type_pair<A, X>, stdx::type_pair<B, Y>>;
63+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_type_lookup_t<M, X>, A>);
64+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_type_lookup_t<M, Y>, B>);
65+
}
66+
67+
TEST_CASE("reverse look up type not in map", "[type map]") {
68+
using M = stdx::type_map<stdx::type_pair<A, X>, stdx::type_pair<B, Y>>;
69+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_type_lookup_t<M, Z>, void>);
70+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_type_lookup_t<M, Z, int>, int>);
71+
}
72+
73+
TEST_CASE("reverse look up type in map (by value)", "[type map]") {
74+
using M = stdx::type_map<stdx::tv_pair<X, 0>, stdx::tv_pair<Y, 1>>;
75+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_value_lookup_t<M, 0>, X>);
76+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_value_lookup_t<M, 1>, Y>);
77+
}
78+
79+
TEST_CASE("reverse look up type not in map (by value)", "[type map]") {
80+
using M = stdx::type_map<stdx::tv_pair<X, 0>, stdx::tv_pair<Y, 1>>;
81+
STATIC_REQUIRE(std::is_same_v<stdx::reverse_value_lookup_t<M, 2>, void>);
82+
STATIC_REQUIRE(
83+
std::is_same_v<stdx::reverse_value_lookup_t<M, 2, int>, int>);
84+
}
85+
86+
TEST_CASE("reverse look up value in map (by type)", "[type map]") {
87+
using M = stdx::type_map<stdx::vt_pair<0, A>, stdx::vt_pair<1, B>>;
88+
STATIC_REQUIRE(stdx::reverse_type_lookup_v<M, A> == 0);
89+
STATIC_REQUIRE(stdx::reverse_type_lookup_v<M, B> == 1);
90+
}
91+
92+
TEST_CASE("reverse look up value not in map (by type)", "[type map]") {
93+
using M = stdx::type_map<stdx::vt_pair<0, A>, stdx::vt_pair<1, B>>;
94+
STATIC_REQUIRE(stdx::reverse_type_lookup_v<M, Z> == 0);
95+
STATIC_REQUIRE(stdx::reverse_type_lookup_v<M, Z, 2> == 2);
96+
}
97+
98+
TEST_CASE("reverse look up value in map (by value)", "[type map]") {
99+
using M = stdx::type_map<stdx::vv_pair<0, 10>, stdx::vv_pair<1, 11>>;
100+
STATIC_REQUIRE(stdx::reverse_value_lookup_v<M, 10> == 0);
101+
STATIC_REQUIRE(stdx::reverse_value_lookup_v<M, 11> == 1);
102+
}
103+
104+
TEST_CASE("reverse look up value not in map (by value)", "[type map]") {
105+
using M = stdx::type_map<stdx::vv_pair<0, 10>, stdx::vv_pair<1, 11>>;
106+
STATIC_REQUIRE(stdx::reverse_value_lookup_v<M, 2> == 0);
107+
STATIC_REQUIRE(stdx::reverse_value_lookup_v<M, 2, 3> == 3);
108+
}

0 commit comments

Comments
 (0)