1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <type_traits> 20 #include <utility> 21 22 #include <folly/Portability.h> 23 #include <folly/Traits.h> 24 #include <folly/functional/Invoke.h> 25 26 /** 27 * folly implementation of `std::overload` like functionality 28 * 29 * Example: 30 * struct One {}; 31 * struct Two {}; 32 * boost::variant<One, Two> value; 33 * 34 * variant_match(value, 35 * [] (const One& one) { ... }, 36 * [] (const Two& two) { ... }); 37 */ 38 39 namespace folly { 40 41 namespace detail { 42 template <typename...> 43 struct Overload; 44 45 template <typename Case, typename... Cases> 46 struct Overload<Case, Cases...> : Overload<Cases...>, Case { 47 Overload(Case c, Cases... cs) 48 : Overload<Cases...>(std::move(cs)...), Case(std::move(c)) {} 49 50 using Case::operator(); 51 using Overload<Cases...>::operator(); 52 }; 53 54 template <typename Case> 55 struct Overload<Case> : Case { 56 explicit Overload(Case c) : Case(std::move(c)) {} 57 58 using Case::operator(); 59 }; 60 } // namespace detail 61 62 /* 63 * Combine multiple `Cases` in one function object 64 */ 65 template <typename... Cases> 66 decltype(auto) overload(Cases&&... cases) { 67 return detail::Overload<typename std::decay<Cases>::type...>{ 68 std::forward<Cases>(cases)...}; 69 } 70 71 namespace overload_detail { 72 FOLLY_CREATE_MEMBER_INVOKER(valueless_by_exception, valueless_by_exception); 73 FOLLY_PUSH_WARNING 74 FOLLY_MSVC_DISABLE_WARNING(4003) /* not enough arguments to macro */ 75 FOLLY_CREATE_FREE_INVOKER(visit, visit); 76 FOLLY_CREATE_FREE_INVOKER(apply_visitor, apply_visitor); 77 FOLLY_POP_WARNING 78 } // namespace overload_detail 79 80 /* 81 * Match `Variant` with one of the `Cases` 82 * 83 * Note: you can also use `[] (const auto&) {...}` as default case 84 * 85 * Selects `visit` if `v.valueless_by_exception()` available and the call to 86 * `visit` is valid (e.g. `std::variant`). Otherwise, selects `apply_visitor` 87 * (e.g. `boost::variant`, `folly::DiscriminatedPtr`). 88 */ 89 template <typename Variant, typename... Cases> 90 decltype(auto) variant_match(Variant&& variant, Cases&&... cases) { 91 using invoker = std::conditional_t< 92 folly::Conjunction< 93 is_invocable<overload_detail::valueless_by_exception, Variant>, 94 is_invocable< 95 overload_detail::visit, 96 decltype(overload(std::forward<Cases>(cases)...)), 97 Variant>>::value, 98 overload_detail::visit, 99 overload_detail::apply_visitor>; 100 return invoker{}( 101 overload(std::forward<Cases>(cases)...), std::forward<Variant>(variant)); 102 } 103 104 } // namespace folly 105