• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License for more details.
11 
12 #pragma once
13 
14 #include "aemu/base/TypeTraits.h"
15 
16 #include <initializer_list>
17 #include <set>
18 #include <map>
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <utility>
22 
23 // A set of convenience functions for map and set lookups. They allow a simpler
24 // syntax, e.g.
25 //   if (auto val = find(map, "key")) {
26 //       <process the value>
27 //   }
28 // ... or
29 //   auto value = find(funcThatReturnsMap(), "other_key");
30 //   if (!value) ...
31 //
32 // Note: these don't work for multimaps, as there's no single value
33 //  to return (and, more importantly, as those are completely useless).
34 
35 namespace android {
36 namespace base {
37 
38 // Helper predicates that check if the template argument is a map / set /
39 // a mutlikey collection of any kind.
40 // These are used as a constraints for the lookup functions to get better error
41 // messages if the arguments don't support the map interface.
42 template <class T>
43 using is_any_map = std::integral_constant<
44         bool,
45         is_template_instantiation_of<T, std::map>::value ||
46                 is_template_instantiation_of<T, std::unordered_map>::value>;
47 
48 template <class T>
49 using is_any_set = std::integral_constant<
50         bool,
51         is_template_instantiation_of<T, std::set>::value ||
52                 is_template_instantiation_of<T, std::unordered_set>::value>;
53 
54 template <class T>
55 using is_any_multikey = std::integral_constant<
56         bool,
57         is_template_instantiation_of<T, std::multimap>::value ||
58                 is_template_instantiation_of<T, std::unordered_multimap>::value ||
59                 is_template_instantiation_of<T, std::multiset>::value ||
60                 is_template_instantiation_of<T, std::unordered_multiset>::value>;
61 
62 template <class T, class = enable_if<is_any_map<T>>>
find(const T & map,const typename T::key_type & key)63 const typename T::mapped_type* find(const T& map,
64                                     const typename T::key_type& key) {
65     const auto it = map.find(key);
66     if (it == map.end()) {
67         return nullptr;
68     }
69 
70     return &it->second;
71 }
72 
73 // Version that returns a modifiable value.
74 template <class T, class = enable_if<is_any_map<T>>>
find(T & map,const typename T::key_type & key)75 typename T::mapped_type* find(T& map, const typename T::key_type& key) {
76     auto it = map.find(key);
77     if (it == map.end()) {
78         return nullptr;
79     }
80 
81     return &it->second;
82 }
83 
84 // Version with a default, returns a _copy_ because of the possible fallback
85 // to a default - it might be destroyed after the call.
86 template <class T,
87           class U = typename T::mapped_type,
88           class = enable_if_c<
89                   is_any_map<T>::value &&
90                   std::is_convertible<U, typename T::mapped_type>::value>>
91 typename T::mapped_type findOrDefault(const T& map,
92                                       const typename T::key_type& key,
93                                       U&& defaultVal = {}) {
94     if (auto valPtr = find(map, key)) {
95         return *valPtr;
96     }
97     return defaultVal;
98 }
99 
100 // Version that finds the first of the values passed in |keys| in the order they
101 // are passed. E.g., the following code finds '2' as the first value in |keys|:
102 //   set<int> s = {1, 2, 3};
103 //   auto val = findFirstOf(s, {2, 1});
104 //   EXPECT_EQ(2, *val);
105 template <class T, class = enable_if<is_any_map<T>>>
findFirstOf(const T & map,std::initializer_list<typename T::key_type> keys)106 const typename T::mapped_type* findFirstOf(
107         const T& map,
108         std::initializer_list<typename T::key_type> keys) {
109     for (const auto& key : keys) {
110         if (const auto valPtr = find(map, key)) {
111             return valPtr;
112         }
113     }
114     return nullptr;
115 }
116 
117 template <class T, class = enable_if<is_any_map<T>>>
findFirstOf(T & map,std::initializer_list<typename T::key_type> keys)118 typename T::mapped_type* findFirstOf(
119         T& map,
120         std::initializer_list<typename T::key_type> keys) {
121     for (const auto& key : keys) {
122         if (const auto valPtr = find(map, key)) {
123             return valPtr;
124         }
125     }
126     return nullptr;
127 }
128 
129 // Version that finds first of the passed |key| values or returns the
130 // |defaultVal| if none were found.
131 template <class T,
132           class U,
133           class = enable_if_c<
134                   is_any_map<T>::value &&
135                   std::is_convertible<U, typename T::mapped_type>::value>>
findFirstOfOrDefault(const T & map,std::initializer_list<typename T::key_type> keys,U && defaultVal)136 typename T::mapped_type findFirstOfOrDefault(
137         const T& map,
138         std::initializer_list<typename T::key_type> keys,
139         U&& defaultVal) {
140     if (const auto valPtr = findFirstOf(map, keys)) {
141         return *valPtr;
142     }
143     return std::forward<U>(defaultVal);
144 }
145 
146 template <class T,
147           class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
148                               is_any_multikey<T>::value>>
contains(const T & c,const typename T::key_type & key)149 bool contains(const T& c, const typename T::key_type& key) {
150     const auto it = c.find(key);
151     return it != c.end();
152 }
153 
154 template <class T,
155           class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
156                               is_any_multikey<T>::value>>
containsAnyOf(const T & c,std::initializer_list<typename T::key_type> keys)157 bool containsAnyOf(const T& c,
158                    std::initializer_list<typename T::key_type> keys) {
159     for (const auto& key : keys) {
160         if (contains(c, key)) {
161             return true;
162         }
163     }
164     return false;
165 }
166 
167 }  // namespace base
168 }  // namespace android
169