blob: 178c9819060a3a90dc53e8b9b6c8744f4dbc02fc [file] [log] [blame]
Lingfeng Yang43459932020-10-31 01:34:58 -07001// Copyright 2020 The Android Open Source Project
Lingfeng Yangc02cb032020-10-26 14:21:25 -07002//
Lingfeng Yang43459932020-10-31 01:34:58 -07003// 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
Lingfeng Yangc02cb032020-10-26 14:21:25 -07006//
Lingfeng Yang43459932020-10-31 01:34:58 -07007// 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.
Lingfeng Yangc02cb032020-10-26 14:21:25 -070014
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
38namespace android {
39namespace 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.
45template <class T>
46using 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
51template <class T>
52using 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
57template <class T>
58using 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
65template <class T, class = enable_if<is_any_map<T>>>
66const 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.
77template <class T, class = enable_if<is_any_map<T>>>
78typename 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.
89template <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>>
94typename 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);
108template <class T, class = enable_if<is_any_map<T>>>
109const 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
120template <class T, class = enable_if<is_any_map<T>>>
121typename 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.
134template <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>>
139typename 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
149template <class T,
150 class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
151 is_any_multikey<T>::value>>
152bool contains(const T& c, const typename T::key_type& key) {
153 const auto it = c.find(key);
154 return it != c.end();
155}
156
157template <class T,
158 class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
159 is_any_multikey<T>::value>>
160bool 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