You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
5.6 KiB
172 lines
5.6 KiB
// Copyright 2020 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#pragma once
|
|
|
|
#include "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 std::forward<U>(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
|