1 // Copyright 2021 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BASE_CONTAINERS_CONTAINS_H_ 6 #define THIRD_PARTY_BASE_CONTAINERS_CONTAINS_H_ 7 8 #include <algorithm> 9 #include <iterator> 10 #include <type_traits> 11 12 #include "third_party/base/template_util.h" 13 14 namespace pdfium { 15 16 namespace internal { 17 18 // Small helper to detect whether a given type has a nested `key_type` typedef. 19 // Used below to catch misuses of the API for associative containers. 20 template <typename T, typename SFINAE = void> 21 struct HasKeyType : std::false_type {}; 22 23 template <typename T> 24 struct HasKeyType<T, std::void_t<typename T::key_type>> : std::true_type {}; 25 26 // Utility type traits used for specializing base::Contains() below. 27 template <typename Container, typename Element, typename = void> 28 struct HasFindWithNpos : std::false_type {}; 29 30 template <typename Container, typename Element> 31 struct HasFindWithNpos< 32 Container, 33 Element, 34 std::void_t<decltype(std::declval<const Container&>().find( 35 std::declval<const Element&>()) != 36 Container::npos)>> : std::true_type {}; 37 38 template <typename Container, typename Element, typename = void> 39 struct HasFindWithEnd : std::false_type {}; 40 41 template <typename Container, typename Element> 42 struct HasFindWithEnd< 43 Container, 44 Element, 45 std::void_t<decltype(std::declval<const Container&>().find( 46 std::declval<const Element&>()) != 47 std::declval<const Container&>().end())>> 48 : std::true_type {}; 49 50 template <typename Container, typename Element, typename = void> 51 struct HasContains : std::false_type {}; 52 53 template <typename Container, typename Element> 54 struct HasContains< 55 Container, 56 Element, 57 std::void_t<decltype(std::declval<const Container&>().contains( 58 std::declval<const Element&>()))>> : std::true_type {}; 59 60 } // namespace internal 61 62 // General purpose implementation to check if |container| contains |value|. 63 template <typename Container, 64 typename Value, 65 std::enable_if_t< 66 !internal::HasFindWithNpos<Container, Value>::value && 67 !internal::HasFindWithEnd<Container, Value>::value && 68 !internal::HasContains<Container, Value>::value>* = nullptr> 69 bool Contains(const Container& container, const Value& value) { 70 static_assert( 71 !internal::HasKeyType<Container>::value, 72 "Error: About to perform linear search on an associative container. " 73 "Either use a more generic comparator (e.g. std::less<>) or, if a linear " 74 "search is desired, provide an explicit projection parameter."); 75 using std::begin; 76 using std::end; 77 return std::find(begin(container), end(container), value) != end(container); 78 } 79 80 // Specialized Contains() implementation for when |container| has a find() 81 // member function and a static npos member, but no contains() member function. 82 template <typename Container, 83 typename Value, 84 std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value && 85 !internal::HasContains<Container, Value>::value>* = 86 nullptr> 87 bool Contains(const Container& container, const Value& value) { 88 return container.find(value) != Container::npos; 89 } 90 91 // Specialized Contains() implementation for when |container| has a find() 92 // and end() member function, but no contains() member function. 93 template <typename Container, 94 typename Value, 95 std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value && 96 !internal::HasContains<Container, Value>::value>* = 97 nullptr> 98 bool Contains(const Container& container, const Value& value) { 99 return container.find(value) != container.end(); 100 } 101 102 // Specialized Contains() implementation for when |container| has a contains() 103 // member function. 104 template < 105 typename Container, 106 typename Value, 107 std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr> 108 bool Contains(const Container& container, const Value& value) { 109 return container.contains(value); 110 } 111 112 } // namespace pdfium 113 114 #endif // THIRD_PARTY_BASE_CONTAINERS_CONTAINS_H_ 115