• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 The Android Open Source Project
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 <algorithm>
20 #include <functional>
21 #include <utility>
22 
23 #include <ftl/optional.h>
24 
25 namespace android::ftl {
26 
27 // Adapter for std::find_if that converts the return value from iterator to optional.
28 //
29 //   const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
30 //   assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv);
31 //
32 template <typename Container, typename Predicate, typename V = typename Container::value_type>
33 constexpr auto find_if(const Container& container, Predicate&& predicate)
34     -> Optional<std::reference_wrapper<const V>> {
35   const auto it = std::find_if(std::cbegin(container), std::cend(container),
36                                std::forward<Predicate>(predicate));
37   if (it == std::cend(container)) return {};
38   return std::cref(*it);
39 }
40 
41 // Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs.
42 //
43 //   const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
44 //       12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
45 //
46 //   using Map = decltype(map);
47 //
48 //   assert(14 == ftl::find_if(map, [](const auto& pair) {
49 //                  return pair.second.size() == 3;
50 //                }).transform(ftl::to_key<Map>));
51 //
52 //   const auto opt = ftl::find_if(map, [](const auto& pair) {
53 //                      return pair.second.size() == 1;
54 //                    }).transform(ftl::to_mapped_ref<Map>);
55 //
56 //   assert(opt);
57 //   assert(opt->get() == ftl::StaticVector("tiramisu"sv));
58 //
59 template <typename Map, typename Pair = typename Map::value_type,
60           typename Key = typename Map::key_type>
61 constexpr auto to_key(const Pair& pair) -> Key {
62   return pair.first;
63 }
64 
65 template <typename Map, typename Pair = typename Map::value_type,
66           typename Mapped = typename Map::mapped_type>
67 constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> {
68   return std::cref(pair.second);
69 }
70 
71 // Combinator for ftl::Optional<T>::or_else when T is std::reference_wrapper<const V>. Given a
72 // lambda argument that returns a `constexpr` value, ftl::static_ref<T> binds a reference to a
73 // static T initialized to that constant.
74 //
75 //   const ftl::SmallMap map = ftl::init::map(13, "tiramisu"sv)(14, "upside-down cake"sv);
76 //   assert("???"sv ==
77 //          map.get(20).or_else(ftl::static_ref<std::string_view>([] { return "???"sv; }))->get());
78 //
79 //   using Map = decltype(map);
80 //
81 //   assert("snow cone"sv ==
82 //          ftl::find_if(map, [](const auto& pair) { return pair.second.front() == 's'; })
83 //              .transform(ftl::to_mapped_ref<Map>)
84 //              .or_else(ftl::static_ref<std::string_view>([] { return "snow cone"sv; }))
85 //              ->get());
86 //
87 template <typename T, typename F>
static_ref(F && f)88 constexpr auto static_ref(F&& f) {
89   return [f = std::forward<F>(f)] {
90     constexpr auto kInitializer = f();
91     static const T kValue = kInitializer;
92     return Optional(std::cref(kValue));
93   };
94 }
95 
96 }  // namespace android::ftl
97