find.h 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_FIND_H_
  5. #define CARBON_COMMON_FIND_H_
  6. #include <concepts>
  7. #include <type_traits>
  8. #include "llvm/ADT/STLExtras.h"
  9. namespace Carbon {
  10. namespace Internal {
  11. template <typename Range>
  12. using RangePointerType = typename std::iterator_traits<decltype(std::begin(
  13. std::declval<Range>()))>::pointer;
  14. template <typename Range>
  15. using RangeValueType = typename std::iterator_traits<decltype(std::begin(
  16. std::declval<Range>()))>::value_type;
  17. template <typename Range, typename Pred>
  18. concept IsValidFindPredicate =
  19. requires(const RangeValueType<Range>& elem, Pred pred) {
  20. { pred(elem) } -> std::convertible_to<bool>;
  21. };
  22. template <typename A, typename B>
  23. concept IsComparable = requires(const A& a, const B& b) {
  24. { a == b } -> std::convertible_to<bool>;
  25. };
  26. template <typename Range>
  27. concept RangeValueHasNoneType = requires {
  28. { RangeValueType<Range>::None } -> std::convertible_to<RangeValueType<Range>>;
  29. };
  30. } // namespace Internal
  31. // Finds a value in the given `range` by testing the `predicate`. Returns a
  32. // pointer to the value from the range on success, and nullptr if nothing is
  33. // found.
  34. //
  35. // This is similar to `std::find_if()` but returns a pointer to the value
  36. // instead of an iterator that must be tested against `end()`.
  37. template <typename Range, typename Pred>
  38. requires Internal::IsValidFindPredicate<Range, Pred>
  39. constexpr auto FindIfOrNull(Range&& range, Pred predicate)
  40. -> Internal::RangePointerType<Range> {
  41. auto it = llvm::find_if(range, predicate);
  42. if (it != range.end()) {
  43. return std::addressof(*it);
  44. } else {
  45. return nullptr;
  46. }
  47. }
  48. // Finds a value in the given `range` by testing the `predicate` and returns a
  49. // copy of it. If no match is found, returns `T::None` where the input range is
  50. // over values of type `T`.
  51. template <typename Range, typename Pred>
  52. requires Internal::IsValidFindPredicate<Range, Pred> &&
  53. Internal::RangeValueHasNoneType<Range> &&
  54. std::copy_constructible<Internal::RangeValueType<Range>>
  55. constexpr auto FindIfOrNone(Range&& range, Pred predicate)
  56. -> Internal::RangeValueType<Range> {
  57. auto it = llvm::find_if(range, predicate);
  58. if (it != range.end()) {
  59. return *it;
  60. } else {
  61. return Internal::RangeValueType<Range>::None;
  62. }
  63. }
  64. // Finds a value in the given `range` by comparing to `query`. Returns a
  65. // pointer to the value from the range on success, and nullptr if nothing is
  66. // found.
  67. //
  68. // This is similar to `std::find_if()` but returns a pointer to the value
  69. // instead of an iterator that must be tested against `end()`.
  70. template <typename Range, typename Query = Internal::RangeValueType<Range>>
  71. requires Internal::IsComparable<Query, Internal::RangeValueType<Range>>
  72. constexpr auto Contains(Range&& range, const Query& query) -> bool {
  73. return llvm::find(range, query) != range.end();
  74. }
  75. } // namespace Carbon
  76. #endif // CARBON_COMMON_FIND_H_