blob: 26ede76e6241ec9ecf8418f77a7d645a54552dc7 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#pragma once
#include "android/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,
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