Commit a5683e13 authored by Michael Park's avatar Michael Park Committed by Facebook GitHub Bot

Add `std::variant` support for `folly::variant_match`.

Summary: This patch adds support for `std::variant` to `folly::variant_match` but without including `<variant>`.

Reviewed By: yfeldblum

Differential Revision: D23196572

fbshipit-source-id: 9d5b519958b04c13cc024d393247c73cec00ac67
parent e72f5c7b
......@@ -19,6 +19,9 @@
#include <type_traits>
#include <utility>
#include <folly/Traits.h>
#include <folly/functional/Invoke.h>
/**
* folly implementation of `std::overload` like functionality
*
......@@ -64,15 +67,33 @@ decltype(auto) overload(Cases&&... cases) {
std::forward<Cases>(cases)...};
}
namespace overload_detail {
FOLLY_CREATE_MEMBER_INVOKER(valueless_by_exception, valueless_by_exception);
FOLLY_CREATE_FREE_INVOKER(visit, visit);
FOLLY_CREATE_FREE_INVOKER(apply_visitor, apply_visitor);
} // namespace overload_detail
/*
* Match `Variant` with one of the `Cases`
*
* Note: you can also use `[] (const auto&) {...}` as default case
*
* Selects `visit` if `v.valueless_by_exception()` available and the call to
* `visit` is valid (e.g. `std::variant`). Otherwise, selects `apply_visitor`
* (e.g. `boost::variant`, `folly::DiscriminatedPtr`).
*/
template <typename Variant, typename... Cases>
decltype(auto) variant_match(Variant&& variant, Cases&&... cases) {
return apply_visitor(
using invoker = std::conditional_t<
folly::Conjunction<
is_invocable<overload_detail::valueless_by_exception, Variant>,
is_invocable<
overload_detail::visit,
decltype(overload(std::forward<Cases>(cases)...)),
Variant>>::value,
overload_detail::visit,
overload_detail::apply_visitor>;
return invoker{}(
overload(std::forward<Cases>(cases)...), std::forward<Variant>(variant));
}
......
......@@ -15,6 +15,9 @@
*/
#include <folly/Overload.h>
#include <variant>
#include <boost/variant.hpp>
#include <folly/DiscriminatedPtr.h>
#include <folly/portability/GTest.h>
......@@ -32,11 +35,29 @@ struct Two {
return "Two";
}
};
using OneOrTwo = boost::variant<One, Two>;
TEST(Overload, StdVariant) {
using V = std::variant<One, Two>;
V one(One{});
V two(Two{});
EXPECT_TRUE(variant_match(
one, [](const One&) { return true; }, [](const Two&) { return false; }));
EXPECT_TRUE(variant_match(
two, [](const One&) { return false; }, [](const Two&) { return true; }));
auto toString = [](const auto& variant) {
return variant_match(
variant, [](const auto& value) { return value.toString(); });
};
EXPECT_EQ(toString(one), "One");
EXPECT_EQ(toString(two), "Two");
}
TEST(Overload, BoostVariant) {
OneOrTwo one(One{});
OneOrTwo two(Two{});
using V = boost::variant<One, Two>;
V one(One{});
V two(Two{});
EXPECT_TRUE(variant_match(
one, [](const One&) { return true; }, [](const Two&) { return false; }));
......@@ -75,9 +96,36 @@ TEST(Overload, DiscriminatedPtr) {
EXPECT_EQ(toString(two_ptr), "Two");
}
TEST(Overload, Pattern) {
OneOrTwo one(One{});
OneOrTwo two(Two{});
TEST(Overload, StdPattern) {
using V = std::variant<One, Two>;
V one(One{});
V two(Two{});
auto is_one_overload = overload(
[](const One&) { return true; }, [](const Two&) { return false; });
EXPECT_TRUE(std::visit(is_one_overload, one));
EXPECT_TRUE(variant_match(one, is_one_overload));
EXPECT_FALSE(variant_match(two, is_one_overload));
auto is_two_overload = overload(
[](const One&) { return false; }, [](const Two&) { return true; });
EXPECT_TRUE(std::visit(is_two_overload, two));
EXPECT_FALSE(variant_match(one, is_two_overload));
EXPECT_TRUE(variant_match(two, is_two_overload));
auto is_one_copy = overload(is_one_overload);
auto is_one_const_copy =
overload(static_cast<const decltype(is_one_overload)&>(is_one_overload));
EXPECT_TRUE(variant_match(one, is_one_copy));
EXPECT_TRUE(variant_match(one, is_one_const_copy));
EXPECT_FALSE(variant_match(two, is_one_copy));
EXPECT_FALSE(variant_match(two, is_one_const_copy));
}
TEST(Overload, BoostPattern) {
using V = boost::variant<One, Two>;
V one(One{});
V two(Two{});
auto is_one_overload = overload(
[](const One&) { return true; }, [](const Two&) { return false; });
......@@ -99,5 +147,6 @@ TEST(Overload, Pattern) {
EXPECT_FALSE(variant_match(two, is_one_copy));
EXPECT_FALSE(variant_match(two, is_one_const_copy));
}
} // namespace test
} // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment