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