xref: /aosp_15_r20/frameworks/native/include/ftl/match.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <utility>
20*38e8c45fSAndroid Build Coastguard Worker #include <variant>
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <ftl/details/match.h>
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl {
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker // Concise alternative to std::visit that compiles to branches rather than a dispatch table. For
27*38e8c45fSAndroid Build Coastguard Worker // std::variant<T0, ..., TN> where N is small, this is slightly faster since the branches can be
28*38e8c45fSAndroid Build Coastguard Worker // inlined unlike the function pointers.
29*38e8c45fSAndroid Build Coastguard Worker //
30*38e8c45fSAndroid Build Coastguard Worker //   using namespace std::chrono;
31*38e8c45fSAndroid Build Coastguard Worker //   std::variant<seconds, minutes, hours> duration = 119min;
32*38e8c45fSAndroid Build Coastguard Worker //
33*38e8c45fSAndroid Build Coastguard Worker //   // Mutable match.
34*38e8c45fSAndroid Build Coastguard Worker //   ftl::match(duration, [](auto& d) { ++d; });
35*38e8c45fSAndroid Build Coastguard Worker //
36*38e8c45fSAndroid Build Coastguard Worker //   // Immutable match. Exhaustive due to minutes being convertible to seconds.
37*38e8c45fSAndroid Build Coastguard Worker //   assert("2 hours"s ==
38*38e8c45fSAndroid Build Coastguard Worker //          ftl::match(duration,
39*38e8c45fSAndroid Build Coastguard Worker //                     [](const seconds& s) {
40*38e8c45fSAndroid Build Coastguard Worker //                       const auto h = duration_cast<hours>(s);
41*38e8c45fSAndroid Build Coastguard Worker //                       return std::to_string(h.count()) + " hours"s;
42*38e8c45fSAndroid Build Coastguard Worker //                     },
43*38e8c45fSAndroid Build Coastguard Worker //                     [](const hours& h) { return std::to_string(h.count() / 24) + " days"s; }));
44*38e8c45fSAndroid Build Coastguard Worker //
45*38e8c45fSAndroid Build Coastguard Worker template <typename... Ts, typename... Ms>
decltype(auto)46*38e8c45fSAndroid Build Coastguard Worker decltype(auto) match(std::variant<Ts...>& variant, Ms&&... matchers) {
47*38e8c45fSAndroid Build Coastguard Worker   const auto matcher = details::Matcher{std::forward<Ms>(matchers)...};
48*38e8c45fSAndroid Build Coastguard Worker   static_assert(details::is_exhaustive_match_v<decltype(matcher), Ts&...>, "Non-exhaustive match");
49*38e8c45fSAndroid Build Coastguard Worker 
50*38e8c45fSAndroid Build Coastguard Worker   return details::Match<Ts...>::match(variant, matcher);
51*38e8c45fSAndroid Build Coastguard Worker }
52*38e8c45fSAndroid Build Coastguard Worker 
53*38e8c45fSAndroid Build Coastguard Worker template <typename... Ts, typename... Ms>
decltype(auto)54*38e8c45fSAndroid Build Coastguard Worker decltype(auto) match(const std::variant<Ts...>& variant, Ms&&... matchers) {
55*38e8c45fSAndroid Build Coastguard Worker   const auto matcher = details::Matcher{std::forward<Ms>(matchers)...};
56*38e8c45fSAndroid Build Coastguard Worker   static_assert(details::is_exhaustive_match_v<decltype(matcher), const Ts&...>,
57*38e8c45fSAndroid Build Coastguard Worker                 "Non-exhaustive match");
58*38e8c45fSAndroid Build Coastguard Worker 
59*38e8c45fSAndroid Build Coastguard Worker   return details::Match<Ts...>::match(variant, matcher);
60*38e8c45fSAndroid Build Coastguard Worker }
61*38e8c45fSAndroid Build Coastguard Worker 
62*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl
63