FTL: Add find_if
Bug: 185536303
Test: ftl_test
Change-Id: I16b63d63da181c7f79d62af9d7a91639342d8c95
diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h
new file mode 100644
index 0000000..c5ff03b
--- /dev/null
+++ b/include/ftl/algorithm.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include <ftl/optional.h>
+
+namespace android::ftl {
+
+// Adapter for std::find_if that converts the return value from iterator to optional.
+//
+// const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
+// assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv);
+//
+template <typename Container, typename Predicate, typename V = typename Container::value_type>
+constexpr auto find_if(const Container& container, Predicate&& predicate)
+ -> Optional<std::reference_wrapper<const V>> {
+ const auto it = std::find_if(std::cbegin(container), std::cend(container),
+ std::forward<Predicate>(predicate));
+ if (it == std::cend(container)) return {};
+ return std::cref(*it);
+}
+
+// Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs.
+//
+// const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
+// 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
+//
+// using Map = decltype(map);
+//
+// assert(14 == ftl::find_if(map, [](const auto& pair) {
+// return pair.second.size() == 3;
+// }).transform(ftl::to_key<Map>));
+//
+// const auto opt = ftl::find_if(map, [](const auto& pair) {
+// return pair.second.size() == 1;
+// }).transform(ftl::to_mapped_ref<Map>);
+//
+// assert(opt);
+// assert(opt->get() == ftl::StaticVector("tiramisu"sv));
+//
+template <typename Map, typename Pair = typename Map::value_type,
+ typename Key = typename Map::key_type>
+constexpr auto to_key(const Pair& pair) -> Key {
+ return pair.first;
+}
+
+template <typename Map, typename Pair = typename Map::value_type,
+ typename Mapped = typename Map::mapped_type>
+constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> {
+ return std::cref(pair.second);
+}
+
+} // namespace android::ftl