mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Prioritize the mapper if it does accept container and tuple like elements
This commit is contained in:
parent
20f586376f
commit
5dfe388f7f
@ -697,14 +697,22 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
||||
/// We use the proxy function invoke_mapper here,
|
||||
/// because some compilers (MSVC) tend to instantiate the invocation
|
||||
/// before matching the tag, which leads to build failures.
|
||||
template <typename T>
|
||||
auto match(container_category_tag<false, false>, T&& element) -> decltype(
|
||||
std::declval<mapping_helper>().invoke_mapper(std::forward<T>(element)));
|
||||
template <bool IsContainer, bool IsTupleLike, typename T>
|
||||
auto map(container_category_tag<IsContainer, IsTupleLike>, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().invoke_mapper(
|
||||
std::forward<T>(element)));
|
||||
|
||||
/// SFINAE helper for forwarding the input to the deep remap methods in order
|
||||
/// to prioritize the mapper before deep container remaps.
|
||||
template <typename Category, typename T>
|
||||
auto map(Category category, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().deep_map(
|
||||
category, std::forward<T>(element)));
|
||||
|
||||
/// SFINAE helper for elements satisfying the container
|
||||
/// requirements, which are not tuple like.
|
||||
template <typename T>
|
||||
auto match(container_category_tag<true, false>, T&& container)
|
||||
auto deep_map(container_category_tag<true, false>, T&& container)
|
||||
-> decltype(container_remapping::remap(Strategy{},
|
||||
std::forward<T>(container),
|
||||
std::declval<traversor>()));
|
||||
@ -712,42 +720,38 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
||||
/// SFINAE helper for elements which are tuple like and
|
||||
/// that also may satisfy the container requirements
|
||||
template <bool IsContainer, typename T>
|
||||
auto match(container_category_tag<IsContainer, true>, T&& tuple_like)
|
||||
auto deep_map(container_category_tag<IsContainer, true>, T&& tuple_like)
|
||||
-> decltype(tuple_like_remapping::remap(Strategy{},
|
||||
std::forward<T>(tuple_like),
|
||||
std::declval<traversor>()));
|
||||
|
||||
/// This method implements the functionality for routing
|
||||
/// elements through, that aren't accepted by the mapper.
|
||||
/// Since the real matcher methods below are failing through SFINAE,
|
||||
/// the compiler will try to specialize this function last,
|
||||
/// since it's the least concrete one.
|
||||
/// This works recursively, so we only call the mapper
|
||||
/// with the minimal needed set of accepted arguments.
|
||||
template <typename MatcherTag, typename T>
|
||||
auto try_match(MatcherTag, T&& element) -> decltype(
|
||||
std::declval<mapping_helper>().may_void(std::forward<T>(element))) {
|
||||
return this->may_void(std::forward<T>(element));
|
||||
}
|
||||
|
||||
/// Match plain elements not satisfying the tuple like or
|
||||
/// container requirements.
|
||||
/// Prioritize the mapper over container remapping.
|
||||
///
|
||||
/// We use the proxy function invoke_mapper here,
|
||||
/// because some compilers (MSVC) tend to instantiate the invocation
|
||||
/// before matching the tag, which leads to build failures.
|
||||
template <typename T>
|
||||
auto try_match(container_category_tag<false, false>, T&& element) -> decltype(
|
||||
std::declval<mapping_helper>().invoke_mapper(std::forward<T>(element))) {
|
||||
template <bool IsContainer, bool IsTupleLike, typename T>
|
||||
auto try_map(container_category_tag<IsContainer, IsTupleLike>, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().invoke_mapper(
|
||||
std::forward<T>(element))) {
|
||||
// T could be any non container or non tuple like type here,
|
||||
// take int or hpx::future<int> as an example.
|
||||
return invoke_mapper(std::forward<T>(element));
|
||||
}
|
||||
|
||||
/// Forward the input to the deep remap methods in order
|
||||
/// to prioritize the mapper before deep container remaps.
|
||||
template <typename Category, typename T>
|
||||
auto try_map(Category category, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().try_deep_map(
|
||||
category, std::forward<T>(element))) {
|
||||
return try_deep_map(category, std::forward<T>(element));
|
||||
}
|
||||
|
||||
/// Match elements satisfying the container requirements,
|
||||
/// which are not tuple like.
|
||||
template <typename T>
|
||||
auto try_match(container_category_tag<true, false>, T&& container)
|
||||
auto try_deep_map(container_category_tag<true, false>, T&& container)
|
||||
-> decltype(container_remapping::remap(Strategy{},
|
||||
std::forward<T>(container),
|
||||
std::declval<try_traversor>())) {
|
||||
@ -759,7 +763,7 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
||||
/// satisfy the container requirements
|
||||
/// -> We match tuple like types over container like ones
|
||||
template <bool IsContainer, typename T>
|
||||
auto try_match(container_category_tag<IsContainer, true>, T&& tuple_like)
|
||||
auto try_deep_map(container_category_tag<IsContainer, true>, T&& tuple_like)
|
||||
-> decltype(tuple_like_remapping::remap(Strategy{},
|
||||
std::forward<T>(tuple_like),
|
||||
std::declval<try_traversor>())) {
|
||||
@ -767,27 +771,40 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
||||
try_traversor{this});
|
||||
}
|
||||
|
||||
/// This method implements the functionality for routing
|
||||
/// elements through, that aren't accepted by the mapper.
|
||||
/// Since the real matcher methods below are failing through SFINAE,
|
||||
/// the compiler will try to specialize this function last,
|
||||
/// since it's the least concrete one.
|
||||
/// This works recursively, so we only call the mapper
|
||||
/// with the minimal needed set of accepted arguments.
|
||||
template <typename MatcherTag, typename T>
|
||||
auto try_deep_map(MatcherTag, T&& element) -> decltype(
|
||||
std::declval<mapping_helper>().may_void(std::forward<T>(element))) {
|
||||
return this->may_void(std::forward<T>(element));
|
||||
}
|
||||
|
||||
/// Traverses a single element.
|
||||
///
|
||||
/// SFINAE helper: Doesn't allow routing through elements,
|
||||
/// that aren't accepted by the mapper
|
||||
template <typename T>
|
||||
auto traverse(Strategy, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().match(
|
||||
-> decltype(std::declval<mapping_helper>().map(
|
||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
||||
std::declval<T>()));
|
||||
|
||||
/// \copybrief traverse
|
||||
template <typename T>
|
||||
auto try_traverse(Strategy, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().try_match(
|
||||
-> decltype(std::declval<mapping_helper>().try_map(
|
||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
||||
std::declval<T>())) {
|
||||
// We use tag dispatching here, to categorize the type T whether
|
||||
// it satisfies the container or tuple like requirements.
|
||||
// Then we can choose the underlying implementation accordingly.
|
||||
return try_match(container_category_of_t<typename std::decay<T>::type>{},
|
||||
std::forward<T>(element));
|
||||
return try_map(container_category_of_t<typename std::decay<T>::type>{},
|
||||
std::forward<T>(element));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -44,7 +44,9 @@ using cti::spread_this;
|
||||
using cti::traverse_pack;
|
||||
|
||||
struct all_map_float {
|
||||
template <typename T>
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_integral<std::decay_t<T>>::value>* = nullptr>
|
||||
float operator()(T el) const {
|
||||
return float(el + 1.f);
|
||||
}
|
||||
@ -59,8 +61,7 @@ struct my_mapper {
|
||||
};
|
||||
|
||||
struct all_map {
|
||||
template <typename T>
|
||||
int operator()(T) const {
|
||||
int operator()(int) const {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
@ -677,8 +678,7 @@ TEST(traverse_strategic_tuple_like_traverse, remap_references) {
|
||||
|
||||
/// A mapper which duplicates the given element
|
||||
struct duplicate_mapper {
|
||||
template <typename T>
|
||||
auto operator()(T arg) -> decltype(spread_this(arg, arg)) {
|
||||
auto operator()(int arg) -> decltype(spread_this(arg, arg)) {
|
||||
return spread_this(arg, arg);
|
||||
}
|
||||
};
|
||||
@ -755,3 +755,16 @@ TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_array) {
|
||||
using Result = decltype(map_pack(zero_mapper{}, std::array<int, 2>{{1, 2}}));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
TEST(traversal_prio, prioritize_mapping) {
|
||||
std::vector<int> vec{0, 1, 2};
|
||||
int res = map_pack(
|
||||
[](std::vector<int>& vec) {
|
||||
// ...
|
||||
EXPECT_EQ(vec.size(), 3U);
|
||||
return 4;
|
||||
},
|
||||
vec);
|
||||
|
||||
EXPECT_EQ(res, 4);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user