Commit 9d5aa289 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Chromium LUCI CQ

[base] Move Contains to dedicated header

This change moves base::Contains into a new base/containers/contains.h
header. This organizes base/stl_util.h a bit, which has become somewhat
of a dumping ground.

Bug: 970209
Change-Id: I7f0df1a1cbfb323f060f2b7a67bcf9c139aa589e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2578941Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835094}
parent 7796a4d4
...@@ -188,6 +188,7 @@ component("base") { ...@@ -188,6 +188,7 @@ component("base") {
"containers/checked_iterators.h", "containers/checked_iterators.h",
"containers/checked_range.h", "containers/checked_range.h",
"containers/circular_deque.h", "containers/circular_deque.h",
"containers/contains.h",
"containers/contiguous_iterator.h", "containers/contiguous_iterator.h",
"containers/fixed_flat_map.h", "containers/fixed_flat_map.h",
"containers/fixed_flat_set.h", "containers/fixed_flat_set.h",
...@@ -2744,6 +2745,7 @@ if (build_base_unittests) { ...@@ -2744,6 +2745,7 @@ if (build_base_unittests) {
"containers/checked_iterators_unittest.cc", "containers/checked_iterators_unittest.cc",
"containers/checked_range_unittest.cc", "containers/checked_range_unittest.cc",
"containers/circular_deque_unittest.cc", "containers/circular_deque_unittest.cc",
"containers/contains_unittest.cc",
"containers/contiguous_iterator_unittest.cc", "containers/contiguous_iterator_unittest.cc",
"containers/fixed_flat_map_unittest.cc", "containers/fixed_flat_map_unittest.cc",
"containers/fixed_flat_set_unittest.cc", "containers/fixed_flat_set_unittest.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CONTAINERS_CONTAINS_H_
#define BASE_CONTAINERS_CONTAINS_H_
#include <iterator>
#include <type_traits>
#include "base/template_util.h"
namespace base {
namespace internal {
// Utility type traits used for specializing base::Contains() below.
template <typename Container, typename Element, typename = void>
struct HasFindWithNpos : std::false_type {};
template <typename Container, typename Element>
struct HasFindWithNpos<
Container,
Element,
void_t<decltype(std::declval<const Container&>().find(
std::declval<const Element&>()) != Container::npos)>>
: std::true_type {};
template <typename Container, typename Element, typename = void>
struct HasFindWithEnd : std::false_type {};
template <typename Container, typename Element>
struct HasFindWithEnd<Container,
Element,
void_t<decltype(std::declval<const Container&>().find(
std::declval<const Element&>()) !=
std::declval<const Container&>().end())>>
: std::true_type {};
template <typename Container, typename Element, typename = void>
struct HasContains : std::false_type {};
template <typename Container, typename Element>
struct HasContains<Container,
Element,
void_t<decltype(std::declval<const Container&>().contains(
std::declval<const Element&>()))>> : std::true_type {};
} // namespace internal
// General purpose implementation to check if |container| contains |value|.
template <typename Container,
typename Value,
std::enable_if_t<
!internal::HasFindWithNpos<Container, Value>::value &&
!internal::HasFindWithEnd<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* = nullptr>
bool Contains(const Container& container, const Value& value) {
using std::begin;
using std::end;
return std::find(begin(container), end(container), value) != end(container);
}
// Specialized Contains() implementation for when |container| has a find()
// member function and a static npos member, but no contains() member function.
template <typename Container,
typename Value,
std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* =
nullptr>
bool Contains(const Container& container, const Value& value) {
return container.find(value) != Container::npos;
}
// Specialized Contains() implementation for when |container| has a find()
// and end() member function, but no contains() member function.
template <typename Container,
typename Value,
std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* =
nullptr>
bool Contains(const Container& container, const Value& value) {
return container.find(value) != container.end();
}
// Specialized Contains() implementation for when |container| has a contains()
// member function.
template <
typename Container,
typename Value,
std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
bool Contains(const Container& container, const Value& value) {
return container.contains(value);
}
} // namespace base
#endif // BASE_CONTAINERS_CONTAINS_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/containers/contains.h"
#include <set>
#include <string>
#include "base/containers/flat_set.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(ContainsTest, GenericContains) {
const char allowed_chars[] = {'a', 'b', 'c', 'd'};
EXPECT_TRUE(Contains(allowed_chars, 'a'));
EXPECT_FALSE(Contains(allowed_chars, 'z'));
EXPECT_FALSE(Contains(allowed_chars, 0));
const char allowed_chars_including_nul[] = "abcd";
EXPECT_TRUE(Contains(allowed_chars_including_nul, 0));
}
TEST(ContainsTest, ContainsWithFindAndNpos) {
std::string str = "abcd";
EXPECT_TRUE(Contains(str, 'a'));
EXPECT_FALSE(Contains(str, 'z'));
EXPECT_FALSE(Contains(str, 0));
}
TEST(ContainsTest, ContainsWithFindAndEnd) {
std::set<int> set = {1, 2, 3, 4};
EXPECT_TRUE(Contains(set, 1));
EXPECT_FALSE(Contains(set, 5));
EXPECT_FALSE(Contains(set, 0));
}
TEST(ContainsTest, ContainsWithContains) {
flat_set<int> set = {1, 2, 3, 4};
EXPECT_TRUE(Contains(set, 1));
EXPECT_FALSE(Contains(set, 5));
EXPECT_FALSE(Contains(set, 0));
}
} // namespace base
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <vector> #include <vector>
#include "base/check.h" #include "base/check.h"
#include "base/containers/contains.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/ranges/algorithm.h" #include "base/ranges/algorithm.h"
#include "base/template_util.h" #include "base/template_util.h"
...@@ -51,38 +52,6 @@ constexpr bool IsRandomAccessIter = ...@@ -51,38 +52,6 @@ constexpr bool IsRandomAccessIter =
std::is_same<typename std::iterator_traits<Iter>::iterator_category, std::is_same<typename std::iterator_traits<Iter>::iterator_category,
std::random_access_iterator_tag>::value; std::random_access_iterator_tag>::value;
// Utility type traits used for specializing base::Contains() below.
template <typename Container, typename Element, typename = void>
struct HasFindWithNpos : std::false_type {};
template <typename Container, typename Element>
struct HasFindWithNpos<
Container,
Element,
void_t<decltype(std::declval<const Container&>().find(
std::declval<const Element&>()) != Container::npos)>>
: std::true_type {};
template <typename Container, typename Element, typename = void>
struct HasFindWithEnd : std::false_type {};
template <typename Container, typename Element>
struct HasFindWithEnd<Container,
Element,
void_t<decltype(std::declval<const Container&>().find(
std::declval<const Element&>()) !=
std::declval<const Container&>().end())>>
: std::true_type {};
template <typename Container, typename Element, typename = void>
struct HasContains : std::false_type {};
template <typename Container, typename Element>
struct HasContains<Container,
Element,
void_t<decltype(std::declval<const Container&>().contains(
std::declval<const Element&>()))>> : std::true_type {};
} // namespace internal } // namespace internal
// C++14 implementation of C++17's std::size(): // C++14 implementation of C++17's std::size():
...@@ -219,51 +188,6 @@ STLCount(const Container& container, const T& val) { ...@@ -219,51 +188,6 @@ STLCount(const Container& container, const T& val) {
return std::count(container.begin(), container.end(), val); return std::count(container.begin(), container.end(), val);
} }
// General purpose implementation to check if |container| contains |value|.
template <typename Container,
typename Value,
std::enable_if_t<
!internal::HasFindWithNpos<Container, Value>::value &&
!internal::HasFindWithEnd<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* = nullptr>
bool Contains(const Container& container, const Value& value) {
using std::begin;
using std::end;
return std::find(begin(container), end(container), value) != end(container);
}
// Specialized Contains() implementation for when |container| has a find()
// member function and a static npos member, but no contains() member function.
template <typename Container,
typename Value,
std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* =
nullptr>
bool Contains(const Container& container, const Value& value) {
return container.find(value) != Container::npos;
}
// Specialized Contains() implementation for when |container| has a find()
// and end() member function, but no contains() member function.
template <typename Container,
typename Value,
std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
!internal::HasContains<Container, Value>::value>* =
nullptr>
bool Contains(const Container& container, const Value& value) {
return container.find(value) != container.end();
}
// Specialized Contains() implementation for when |container| has a contains()
// member function.
template <
typename Container,
typename Value,
std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
bool Contains(const Container& container, const Value& value) {
return container.contains(value);
}
// O(1) implementation of const casting an iterator for any sequence, // O(1) implementation of const casting an iterator for any sequence,
// associative or unordered associative container in the STL. // associative or unordered associative container in the STL.
// //
......
...@@ -605,41 +605,6 @@ TEST(Erase, IsNotIn) { ...@@ -605,41 +605,6 @@ TEST(Erase, IsNotIn) {
EXPECT_EQ(expected, lhs); EXPECT_EQ(expected, lhs);
} }
TEST(STLUtilTest, GenericContains) {
const char allowed_chars[] = {'a', 'b', 'c', 'd'};
EXPECT_TRUE(Contains(allowed_chars, 'a'));
EXPECT_FALSE(Contains(allowed_chars, 'z'));
EXPECT_FALSE(Contains(allowed_chars, 0));
const char allowed_chars_including_nul[] = "abcd";
EXPECT_TRUE(Contains(allowed_chars_including_nul, 0));
}
TEST(STLUtilTest, ContainsWithFindAndNpos) {
std::string str = "abcd";
EXPECT_TRUE(Contains(str, 'a'));
EXPECT_FALSE(Contains(str, 'z'));
EXPECT_FALSE(Contains(str, 0));
}
TEST(STLUtilTest, ContainsWithFindAndEnd) {
std::set<int> set = {1, 2, 3, 4};
EXPECT_TRUE(Contains(set, 1));
EXPECT_FALSE(Contains(set, 5));
EXPECT_FALSE(Contains(set, 0));
}
TEST(STLUtilTest, ContainsWithContains) {
flat_set<int> set = {1, 2, 3, 4};
EXPECT_TRUE(Contains(set, 1));
EXPECT_FALSE(Contains(set, 5));
EXPECT_FALSE(Contains(set, 0));
}
TEST(STLUtilTest, InsertOrAssign) { TEST(STLUtilTest, InsertOrAssign) {
std::map<std::string, int> my_map; std::map<std::string, int> my_map;
auto result = InsertOrAssign(my_map, "Hello", 42); auto result = InsertOrAssign(my_map, "Hello", 42);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment