xref: /aosp_15_r20/external/cronet/base/containers/contains.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_CONTAINS_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_CONTAINS_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <type_traits>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/ranges/ranges.h"
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker namespace base {
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace internal {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker // Small helper to detect whether a given type has a nested `key_type` typedef.
19*6777b538SAndroid Build Coastguard Worker // Used below to catch misuses of the API for associative containers.
20*6777b538SAndroid Build Coastguard Worker template <typename T, typename SFINAE = void>
21*6777b538SAndroid Build Coastguard Worker struct HasKeyType : std::false_type {};
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker template <typename T>
24*6777b538SAndroid Build Coastguard Worker struct HasKeyType<T, std::void_t<typename T::key_type>> : std::true_type {};
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // Probe whether a `contains` member function exists and return the result of
27*6777b538SAndroid Build Coastguard Worker // `container.contains(value)` if this is a valid expression. This is the
28*6777b538SAndroid Build Coastguard Worker // highest priority option.
29*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value>
30*6777b538SAndroid Build Coastguard Worker constexpr auto ContainsImpl(const Container& container,
31*6777b538SAndroid Build Coastguard Worker                             const Value& value,
32*6777b538SAndroid Build Coastguard Worker                             priority_tag<2>)
33*6777b538SAndroid Build Coastguard Worker     -> decltype(container.contains(value)) {
34*6777b538SAndroid Build Coastguard Worker   return container.contains(value);
35*6777b538SAndroid Build Coastguard Worker }
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker // Probe whether a `find` member function exists and whether its return value
38*6777b538SAndroid Build Coastguard Worker // can be compared with `container.end()`. Intended for STL style maps and sets
39*6777b538SAndroid Build Coastguard Worker // that lack a `contains` member function.
40*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value>
41*6777b538SAndroid Build Coastguard Worker constexpr auto ContainsImpl(const Container& container,
42*6777b538SAndroid Build Coastguard Worker                             const Value& value,
43*6777b538SAndroid Build Coastguard Worker                             priority_tag<1>)
44*6777b538SAndroid Build Coastguard Worker     -> decltype(container.find(value) != container.end()) {
45*6777b538SAndroid Build Coastguard Worker   return container.find(value) != container.end();
46*6777b538SAndroid Build Coastguard Worker }
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker // Probe whether a `find` member function exists and whether its return value
49*6777b538SAndroid Build Coastguard Worker // can be compared with `Container::npos`. Intended for STL style strings that
50*6777b538SAndroid Build Coastguard Worker // lack a `contains` member function.
51*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value>
52*6777b538SAndroid Build Coastguard Worker constexpr auto ContainsImpl(const Container& container,
53*6777b538SAndroid Build Coastguard Worker                             const Value& value,
54*6777b538SAndroid Build Coastguard Worker                             priority_tag<1>)
55*6777b538SAndroid Build Coastguard Worker     -> decltype(container.find(value) != Container::npos) {
56*6777b538SAndroid Build Coastguard Worker   return container.find(value) != Container::npos;
57*6777b538SAndroid Build Coastguard Worker }
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker // Generic fallback option, using a linear search over `container` to find
60*6777b538SAndroid Build Coastguard Worker // `value`. Has the lowest priority. This will not compile for associative
61*6777b538SAndroid Build Coastguard Worker // containers, as this likely is a performance bug.
62*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value>
63*6777b538SAndroid Build Coastguard Worker constexpr bool ContainsImpl(const Container& container,
64*6777b538SAndroid Build Coastguard Worker                             const Value& value,
65*6777b538SAndroid Build Coastguard Worker                             priority_tag<0>) {
66*6777b538SAndroid Build Coastguard Worker   static_assert(
67*6777b538SAndroid Build Coastguard Worker       !HasKeyType<Container>::value,
68*6777b538SAndroid Build Coastguard Worker       "Error: About to perform linear search on an associative container. "
69*6777b538SAndroid Build Coastguard Worker       "Either use a more generic comparator (e.g. std::less<>) or, if a linear "
70*6777b538SAndroid Build Coastguard Worker       "search is desired, provide an explicit projection parameter.");
71*6777b538SAndroid Build Coastguard Worker   return ranges::find(container, value) != ranges::end(container);
72*6777b538SAndroid Build Coastguard Worker }
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker }  // namespace internal
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker // A general purpose utility to check whether `container` contains `value`. This
77*6777b538SAndroid Build Coastguard Worker // will probe whether a `contains` or `find` member function on `container`
78*6777b538SAndroid Build Coastguard Worker // exists, and fall back to a generic linear search over `container`.
79*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value>
80*6777b538SAndroid Build Coastguard Worker constexpr bool Contains(const Container& container, const Value& value) {
81*6777b538SAndroid Build Coastguard Worker   return internal::ContainsImpl(container, value, internal::priority_tag<2>());
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker // Overload that allows to provide an additional projection invocable. This
85*6777b538SAndroid Build Coastguard Worker // projection will be applied to every element in `container` before comparing
86*6777b538SAndroid Build Coastguard Worker // it with `value`. This will always perform a linear search.
87*6777b538SAndroid Build Coastguard Worker template <typename Container, typename Value, typename Proj>
88*6777b538SAndroid Build Coastguard Worker constexpr bool Contains(const Container& container,
89*6777b538SAndroid Build Coastguard Worker                         const Value& value,
90*6777b538SAndroid Build Coastguard Worker                         Proj proj) {
91*6777b538SAndroid Build Coastguard Worker   return ranges::find(container, value, std::move(proj)) !=
92*6777b538SAndroid Build Coastguard Worker          ranges::end(container);
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker }  // namespace base
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_CONTAINS_H_
98