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