| // Copyright 2016 The Android Open Source Project |
| // |
| // This software is licensed under the terms of the GNU General Public |
| // License version 2, as published by the Free Software Foundation, and |
| // may be copied, distributed, and modified under those terms. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| #pragma once |
| |
| #include "aemu/base/TypeTraits.h" |
| |
| #include <initializer_list> |
| #include <set> |
| #include <map> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <utility> |
| |
| // A set of convenience functions for map and set lookups. They allow a simpler |
| // syntax, e.g. |
| // if (auto val = find(map, "key")) { |
| // <process the value> |
| // } |
| // ... or |
| // auto value = find(funcThatReturnsMap(), "other_key"); |
| // if (!value) ... |
| // |
| // Note: these don't work for multimaps, as there's no single value |
| // to return (and, more importantly, as those are completely useless). |
| |
| namespace android { |
| namespace base { |
| |
| // Helper predicates that check if the template argument is a map / set / |
| // a mutlikey collection of any kind. |
| // These are used as a constraints for the lookup functions to get better error |
| // messages if the arguments don't support the map interface. |
| template <class T> |
| using is_any_map = std::integral_constant< |
| bool, |
| is_template_instantiation_of<T, std::map>::value || |
| is_template_instantiation_of<T, std::unordered_map>::value>; |
| |
| template <class T> |
| using is_any_set = std::integral_constant< |
| bool, |
| is_template_instantiation_of<T, std::set>::value || |
| is_template_instantiation_of<T, std::unordered_set>::value>; |
| |
| template <class T> |
| using is_any_multikey = std::integral_constant< |
| bool, |
| is_template_instantiation_of<T, std::multimap>::value || |
| is_template_instantiation_of<T, std::unordered_multimap>::value || |
| is_template_instantiation_of<T, std::multiset>::value || |
| is_template_instantiation_of<T, std::unordered_multiset>::value>; |
| |
| template <class T, class = enable_if<is_any_map<T>>> |
| const typename T::mapped_type* find(const T& map, |
| const typename T::key_type& key) { |
| const auto it = map.find(key); |
| if (it == map.end()) { |
| return nullptr; |
| } |
| |
| return &it->second; |
| } |
| |
| // Version that returns a modifiable value. |
| template <class T, class = enable_if<is_any_map<T>>> |
| typename T::mapped_type* find(T& map, const typename T::key_type& key) { |
| auto it = map.find(key); |
| if (it == map.end()) { |
| return nullptr; |
| } |
| |
| return &it->second; |
| } |
| |
| // Version with a default, returns a _copy_ because of the possible fallback |
| // to a default - it might be destroyed after the call. |
| template <class T, |
| class U = typename T::mapped_type, |
| class = enable_if_c< |
| is_any_map<T>::value && |
| std::is_convertible<U, typename T::mapped_type>::value>> |
| typename T::mapped_type findOrDefault(const T& map, |
| const typename T::key_type& key, |
| U&& defaultVal = {}) { |
| if (auto valPtr = find(map, key)) { |
| return *valPtr; |
| } |
| return defaultVal; |
| } |
| |
| // Version that finds the first of the values passed in |keys| in the order they |
| // are passed. E.g., the following code finds '2' as the first value in |keys|: |
| // set<int> s = {1, 2, 3}; |
| // auto val = findFirstOf(s, {2, 1}); |
| // EXPECT_EQ(2, *val); |
| template <class T, class = enable_if<is_any_map<T>>> |
| const typename T::mapped_type* findFirstOf( |
| const T& map, |
| std::initializer_list<typename T::key_type> keys) { |
| for (const auto& key : keys) { |
| if (const auto valPtr = find(map, key)) { |
| return valPtr; |
| } |
| } |
| return nullptr; |
| } |
| |
| template <class T, class = enable_if<is_any_map<T>>> |
| typename T::mapped_type* findFirstOf( |
| T& map, |
| std::initializer_list<typename T::key_type> keys) { |
| for (const auto& key : keys) { |
| if (const auto valPtr = find(map, key)) { |
| return valPtr; |
| } |
| } |
| return nullptr; |
| } |
| |
| // Version that finds first of the passed |key| values or returns the |
| // |defaultVal| if none were found. |
| template <class T, |
| class U, |
| class = enable_if_c< |
| is_any_map<T>::value && |
| std::is_convertible<U, typename T::mapped_type>::value>> |
| typename T::mapped_type findFirstOfOrDefault( |
| const T& map, |
| std::initializer_list<typename T::key_type> keys, |
| U&& defaultVal) { |
| if (const auto valPtr = findFirstOf(map, keys)) { |
| return *valPtr; |
| } |
| return std::forward<U>(defaultVal); |
| } |
| |
| template <class T, |
| class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value || |
| is_any_multikey<T>::value>> |
| bool contains(const T& c, const typename T::key_type& key) { |
| const auto it = c.find(key); |
| return it != c.end(); |
| } |
| |
| template <class T, |
| class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value || |
| is_any_multikey<T>::value>> |
| bool containsAnyOf(const T& c, |
| std::initializer_list<typename T::key_type> keys) { |
| for (const auto& key : keys) { |
| if (contains(c, key)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace base |
| } // namespace android |