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