• 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 // Determines if a container contains a value. This is a simplified version of the C++23
28 // std::ranges::contains function.
29 //
30 //   const ftl::StaticVector vector = {1, 2, 3};
31 //   assert(ftl::contains(vector, 1));
32 //
33 // TODO: Remove in C++23.
34 template <typename Container, typename Value>
35 auto contains(const Container& container, const Value& value) -> bool {
36   return std::find(container.begin(), container.end(), value) != container.end();
37 }
38 
39 // Adapter for std::find_if that converts the return value from iterator to optional.
40 //
41 //   const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
42 //   assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv);
43 //
44 template <typename Container, typename Predicate, typename V = typename Container::value_type>
45 constexpr auto find_if(const Container& container, Predicate&& predicate)
46     -> Optional<std::reference_wrapper<const V>> {
47   const auto it = std::find_if(std::cbegin(container), std::cend(container),
48                                std::forward<Predicate>(predicate));
49   if (it == std::cend(container)) return {};
50   return std::cref(*it);
51 }
52 
53 // Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs.
54 //
55 //   const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
56 //       12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
57 //
58 //   using Map = decltype(map);
59 //
60 //   assert(14 == ftl::find_if(map, [](const auto& pair) {
61 //                  return pair.second.size() == 3;
62 //                }).transform(ftl::to_key<Map>));
63 //
64 //   const auto opt = ftl::find_if(map, [](const auto& pair) {
65 //                      return pair.second.size() == 1;
66 //                    }).transform(ftl::to_mapped_ref<Map>);
67 //
68 //   assert(opt);
69 //   assert(opt->get() == ftl::StaticVector("tiramisu"sv));
70 //
71 template <typename Map, typename Pair = typename Map::value_type,
72           typename Key = typename Map::key_type>
73 constexpr auto to_key(const Pair& pair) -> Key {
74   return pair.first;
75 }
76 
77 template <typename Map, typename Pair = typename Map::value_type,
78           typename Mapped = typename Map::mapped_type>
79 constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> {
80   return std::cref(pair.second);
81 }
82 
83 // Combinator for ftl::Optional<T>::or_else when T is std::reference_wrapper<const V>. Given a
84 // lambda argument that returns a `constexpr` value, ftl::static_ref<T> binds a reference to a
85 // static T initialized to that constant.
86 //
87 //   const ftl::SmallMap map = ftl::init::map(13, "tiramisu"sv)(14, "upside-down cake"sv);
88 //   assert("???"sv ==
89 //          map.get(20).or_else(ftl::static_ref<std::string_view>([] { return "???"sv; }))->get());
90 //
91 //   using Map = decltype(map);
92 //
93 //   assert("snow cone"sv ==
94 //          ftl::find_if(map, [](const auto& pair) { return pair.second.front() == 's'; })
95 //              .transform(ftl::to_mapped_ref<Map>)
96 //              .or_else(ftl::static_ref<std::string_view>([] { return "snow cone"sv; }))
97 //              ->get());
98 //
99 template <typename T, typename F>
static_ref(F && f)100 constexpr auto static_ref(F&& f) {
101   return [f = std::forward<F>(f)] {
102     constexpr auto kInitializer = f();
103     static const T kValue = kInitializer;
104     return Optional(std::cref(kValue));
105   };
106 }
107 
108 }  // namespace android::ftl
109