[flang-commits] [flang] [libc++] Implement ranges::contains (PR #65148)

Konstantin Varlamov via flang-commits flang-commits at lists.llvm.org
Thu Sep 7 21:15:45 PDT 2023


================
@@ -0,0 +1,190 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
+//     requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
+//     constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {});       // since C++23
+
+// template<input_range R, class T, class Proj = identity>
+//     requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
+//     constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {});                 // since C++23
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <vector>
+
+#include "almost_satisfies_types.h"
+#include "boolean_testable.h"
+#include "test_iterators.h"
+
+struct NotEqualityComparable {};
+
+template <class Iter, class Sent = Iter>
+concept HasContainsIt = requires(Iter iter, Sent sent) { std::ranges::contains(iter, sent, *iter); };
+
+static_assert(HasContainsIt<int*>);
+static_assert(!HasContainsIt<NotEqualityComparable*>);
+static_assert(!HasContainsIt<InputIteratorNotDerivedFrom>);
+static_assert(!HasContainsIt<InputIteratorNotIndirectlyReadable>);
+static_assert(!HasContainsIt<InputIteratorNotInputOrOutputIterator>);
+static_assert(!HasContainsIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
+static_assert(!HasContainsIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
+
+static_assert(!HasContainsIt<int*, int>);
+static_assert(!HasContainsIt<int, int*>);
+
+template <class Range, class ValT>
+concept HasContainsR = requires(Range range) { std::ranges::contains(range, ValT{}); };
+
+static_assert(HasContainsR<std::array<int, 1>, int>);
+static_assert(!HasContainsR<int, int>);
+static_assert(!HasContainsR<std::array<NotEqualityComparable, 1>, NotEqualityComparable>);
+static_assert(!HasContainsR<InputRangeNotDerivedFrom, int>);
+static_assert(!HasContainsR<InputRangeNotIndirectlyReadable, int>);
+static_assert(!HasContainsR<InputRangeNotInputOrOutputIterator, int>);
+static_assert(!HasContainsR<InputRangeNotSentinelSemiregular, int>);
+static_assert(!HasContainsR<InputRangeNotSentinelEqualityComparableWith, int>);
+
+static std::vector<int> comparable_data;
+
+// clang-format off
+template <class Iter, class Sent = Iter>
+constexpr void test_iterators() {
+  using ValueT = std::iter_value_t<Iter>;
+  {  // simple tests
+    {
+      ValueT a[] = {1, 2, 3, 4, 5, 6};
----------------
var-const wrote:

@EricWF I think it's just conceptually simpler. Consider:
```cpp
// A
{
  int input[] = {5, 7, 8, 13, 3, 6};
  assert(ranges::contains(in, in + std::size(in), 3));
}
{
  int input[] = {48, 16, 32, 45, 99, 128, 37, 64, 15};
  assert(ranges::contains(in, 64));
}

// B
{
  int input[] = {5, 7, 8, 13, 3, 6};
  assert(ranges::contains(in, in + std::size(in), 3));
}
{
  int input[] = {5, 7, 8, 13, 3, 6};
  assert(ranges::contains(in, 3));
}

// C
int input[] = {5, 7, 8, 13, 3, 6};
{
  assert(ranges::contains(in, in + std::size(in), 3));
}
{
  assert(ranges::contains(in, 3));
}
```

IMO while `A` is valid, it's overly complicated for no reason -- now the reader has to examine both input sequences to understand (or verify) what the test is doing. `B` is better because now there is no unnecessary divergence, but there is still some overhead to see if the sequences are the same or not. `C` removes that overhead, however small, and also most directly conveys the underlying idea (we are running equivalent tests on the two overloads of the function). The fact that it reduces the line count is also nice but not the primary motivation.

https://github.com/llvm/llvm-project/pull/65148


More information about the flang-commits mailing list