[libc++] Remove incorrect default constructor in cpp17_input_iterator
authorLouis Dionne <ldionne.2@gmail.com>
Wed, 15 Dec 2021 16:26:47 +0000 (11:26 -0500)
committerLouis Dionne <ldionne.2@gmail.com>
Tue, 4 Jan 2022 19:33:51 +0000 (14:33 -0500)
AFAICT, Cpp17InputIterators are not required to be default constructible,
since that requirement is added in Cpp17ForwardIterator. Hence, our
archetype for Cpp17InputIterator should not be default constructible.
Removing that constructor has a ripple effect on a couple of tests that
were making incorrect assumptions. Notably:

- Some tests were using cpp17_input_iterator as a sentinel for itself.
  That is not valid, because a cpp17_input_iterator is not semiregular
  anymore after the change (and hence it doesn't satisfy sentinel_for).

- Some tests were using a stride-counted cpp17_input_iterator as the
  sentinel for a range. This doesn't work anymore because of the problem
  above, so these tests were changed not to check stride counts for
  input iterators.

- Some tests were default constructing cpp17_input_iterator when a simple
  alternative was available -- those have been changed to use that alternative.

Differential Revision: https://reviews.llvm.org/D115806

19 files changed:
libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.addressof.compile.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp
libcxx/test/std/iterators/predef.iterators/counted.iterator/ctor.default.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/member_types.compile.pass.cpp
libcxx/test/std/ranges/range.req/range.range/sentinel_t.compile.pass.cpp
libcxx/test/std/ranges/range.req/range.refinements/common_range.compile.pass.cpp
libcxx/test/std/ranges/range.req/range.refinements/input_range.compile.pass.cpp
libcxx/test/std/ranges/range.utility/range.subrange/advance.pass.cpp
libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
libcxx/test/support/test_iterators.h

index a8eb860..f831109 100644 (file)
 #include "operator_hijacker.h"
 #include "test_iterators.h"
 
-void test() {
+void test(cpp17_input_iterator<operator_hijacker*> i) {
   {
     std::vector<operator_hijacker> v;
-    cpp17_input_iterator<std::vector<operator_hijacker>::iterator> i;
     v.insert(v.end(), i, i);
   }
   {
index 19475c3..ca8dcb8 100644 (file)
@@ -179,7 +179,7 @@ int main(int, char**)
 
     {
         std::vector<adl::S> s;
-        s.insert(s.end(), cpp17_input_iterator<adl::S*>(), cpp17_input_iterator<adl::S*>());
+        s.insert(s.end(), cpp17_input_iterator<adl::S*>(nullptr), cpp17_input_iterator<adl::S*>(nullptr));
     }
 
   return 0;
index 165b0b0..90f9aba 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <array>
 #include <cassert>
+#include <cstddef>
 
 #include "test_iterators.h"
 
@@ -44,61 +45,103 @@ private:
   std::ptrdiff_t count_ = 0;
 };
 
-template <std::input_or_output_iterator It, std::sentinel_for<It> Sent = It>
-constexpr void check_assignable_case(std::ptrdiff_t const n) {
+template <class It, class Sent = It>
+constexpr void check_assignable_case() {
   auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-  auto first = stride_counting_iterator(It(range.begin()));
-  std::ranges::advance(first, stride_counting_iterator(Sent(It(range.begin() + n))));
-  assert(first.base().base() == range.begin() + n);
-  assert(first.stride_count() == 0); // because we got here by assigning from last, not by incrementing
+
+  for (std::ptrdiff_t n = 0; n != 9; ++n) {
+    {
+      It first(range.begin());
+      Sent last(It(range.begin() + n));
+      std::ranges::advance(first, last);
+      assert(base(first) == range.begin() + n);
+    }
+
+    // Count operations
+    if constexpr (std::is_same_v<It, Sent>) {
+      stride_counting_iterator<It> first(It(range.begin()));
+      stride_counting_iterator<It> last(It(range.begin() + n));
+      std::ranges::advance(first, last);
+      assert(first.base().base() == range.begin() + n);
+      assert(first.stride_count() == 0); // because we got here by assigning from last, not by incrementing
+    }
+  }
 }
 
-template <std::input_or_output_iterator It>
-constexpr void check_sized_sentinel_case(std::ptrdiff_t const n) {
+template <class It>
+constexpr void check_sized_sentinel_case() {
   auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-  auto first = stride_counting_iterator(It(range.begin()));
-  std::ranges::advance(first, distance_apriori_sentinel(n));
-
-  assert(first.base().base() == range.begin() + n);
-  if constexpr (std::random_access_iterator<It>) {
-    assert(first.stride_count() == 1);
-    assert(first.stride_displacement() == 1);
-  } else {
-    assert(first.stride_count() == n);
-    assert(first.stride_displacement() == n);
+
+  for (std::ptrdiff_t n = 0; n != 9; ++n) {
+    {
+      It first(range.begin());
+      distance_apriori_sentinel last(n);
+      std::ranges::advance(first, last);
+      assert(base(first) == range.begin() + n);
+    }
+
+    // Count operations
+    {
+      stride_counting_iterator<It> first(It(range.begin()));
+      distance_apriori_sentinel last(n);
+      std::ranges::advance(first, last);
+
+      assert(first.base().base() == range.begin() + n);
+      if constexpr (std::random_access_iterator<It>) {
+        assert(first.stride_count() == 1);
+        assert(first.stride_displacement() == 1);
+      } else {
+        assert(first.stride_count() == n);
+        assert(first.stride_displacement() == n);
+      }
+    }
   }
 }
 
-template <std::input_or_output_iterator It>
-constexpr void check_sentinel_case(std::ptrdiff_t const n) {
+template <class It>
+constexpr void check_sentinel_case() {
   auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-  auto first = stride_counting_iterator(It(range.begin()));
-  auto const last = It(range.begin() + n);
-  std::ranges::advance(first, sentinel_wrapper(last));
-  assert(first.base() == last);
-  assert(first.stride_count() == n);
+
+  for (std::ptrdiff_t n = 0; n != 9; ++n) {
+    {
+      It first(range.begin());
+      sentinel_wrapper<It> last(It(range.begin() + n));
+      std::ranges::advance(first, last);
+      assert(base(first) == range.begin() + n);
+    }
+
+    // Count operations
+    {
+      stride_counting_iterator<It> first(It(range.begin()));
+      sentinel_wrapper<It> last(It(range.begin() + n));
+      std::ranges::advance(first, last);
+      assert(first.base() == last);
+      assert(first.stride_count() == n);
+    }
+  }
 }
 
 constexpr bool test() {
-  check_assignable_case<cpp17_input_iterator<range_t::const_iterator> >(1);
-  check_assignable_case<forward_iterator<range_t::const_iterator> >(3);
-  check_assignable_case<bidirectional_iterator<range_t::const_iterator> >(4);
-  check_assignable_case<random_access_iterator<range_t::const_iterator> >(5);
-  check_assignable_case<contiguous_iterator<range_t::const_iterator> >(6);
-
-  check_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(7);
-  check_sized_sentinel_case<cpp20_input_iterator<range_t::const_iterator> >(6);
-  check_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(5);
-  check_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
-  check_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(3);
-  check_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(2);
-
-  check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1);
+  using It = range_t::const_iterator;
+  check_assignable_case<cpp17_input_iterator<It>, sentinel_wrapper<cpp17_input_iterator<It>>>();
+  check_assignable_case<forward_iterator<It>>();
+  check_assignable_case<bidirectional_iterator<It>>();
+  check_assignable_case<random_access_iterator<It>>();
+  check_assignable_case<contiguous_iterator<It>>();
+
+  check_sized_sentinel_case<cpp17_input_iterator<It>>();
+  check_sized_sentinel_case<cpp20_input_iterator<It>>();
+  check_sized_sentinel_case<forward_iterator<It>>();
+  check_sized_sentinel_case<bidirectional_iterator<It>>();
+  check_sized_sentinel_case<random_access_iterator<It>>();
+  check_sized_sentinel_case<contiguous_iterator<It>>();
+
+  check_sentinel_case<cpp17_input_iterator<It>>();
   // cpp20_input_iterator not copyable, so is omitted
-  check_sentinel_case<forward_iterator<range_t::const_iterator> >(3);
-  check_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
-  check_sentinel_case<random_access_iterator<range_t::const_iterator> >(5);
-  check_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6);
+  check_sentinel_case<forward_iterator<It>>();
+  check_sentinel_case<bidirectional_iterator<It>>();
+  check_sentinel_case<random_access_iterator<It>>();
+  check_sentinel_case<contiguous_iterator<It>>();
   return true;
 }
 
index 3554a34..3c0e9d8 100644 (file)
 
 #include <iterator>
 #include <cassert>
+#include <type_traits>
 
 #include "test_iterators.h"
 
-template <std::input_or_output_iterator It>
-constexpr void check(It it, std::ptrdiff_t n, It last) {
+template <class It, class Sent = It>
+constexpr void check(It it, std::ptrdiff_t n, Sent last) {
   {
     It result = std::ranges::next(it, n, last);
     assert(result == last);
   }
 
   // Count the number of operations
-  {
+  if constexpr (std::is_same_v<It, Sent>) {
     stride_counting_iterator<It> strided_it(it);
     stride_counting_iterator<It> strided_last(last);
     stride_counting_iterator<It> result = std::ranges::next(strided_it, n, strided_last);
@@ -46,13 +47,13 @@ constexpr void check(It it, std::ptrdiff_t n, It last) {
 constexpr bool test() {
   int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
-  check(cpp17_input_iterator(&range[0]), 1, cpp17_input_iterator(&range[1]));
+  check(cpp17_input_iterator(&range[0]), 1, sentinel_wrapper(cpp17_input_iterator(&range[1])));
   check(forward_iterator(&range[0]), 2, forward_iterator(&range[2]));
   check(bidirectional_iterator(&range[2]), 6, bidirectional_iterator(&range[8]));
   check(random_access_iterator(&range[3]), 2, random_access_iterator(&range[5]));
   check(contiguous_iterator(&range[0]), 5, contiguous_iterator(&range[5]));
 
-  check(cpp17_input_iterator(&range[0]), 0, cpp17_input_iterator(&range[0]));
+  check(cpp17_input_iterator(&range[0]), 0, sentinel_wrapper(cpp17_input_iterator(&range[0])));
   check(forward_iterator(&range[0]), 0, forward_iterator(&range[0]));
   check(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
   check(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
index 354cdff..545e01b 100644 (file)
 
 using range_t = std::array<int, 10>;
 
+// Sentinel type that can be assigned to an iterator. This is to test the case where
+// std::ranges::next uses assignment instead of successive increments below.
+template <class It>
+class assignable_sentinel {
+public:
+    explicit assignable_sentinel() = default;
+    constexpr explicit assignable_sentinel(const It& it) : base_(base(it)) {}
+    constexpr operator It() const { return It(base_); }
+    constexpr bool operator==(const It& other) const { return base_ == base(other); }
+    friend constexpr It base(const assignable_sentinel& s) { return It(s.base_); }
+private:
+    decltype(base(std::declval<It>())) base_;
+};
+
 class distance_apriori_sentinel {
 public:
   distance_apriori_sentinel() = default;
@@ -45,39 +59,39 @@ private:
   std::ptrdiff_t count_ = 0;
 };
 
-template <std::input_or_output_iterator It>
-constexpr void check_assignable(It it, It last, int const* expected) {
+template <bool Count, typename It>
+constexpr void check_assignable(int* it, int* last, int const* expected) {
   {
-    It result = std::ranges::next(std::move(it), std::move(last));
-    assert(&*result == expected);
+    It result = std::ranges::next(It(it), assignable_sentinel(It(last)));
+    assert(base(result) == expected);
   }
 
   // Count operations
-  {
-    auto strided_it = stride_counting_iterator(std::move(it));
-    auto strided_last = stride_counting_iterator(std::move(last));
-    auto result = std::ranges::next(std::move(strided_it), std::move(strided_last));
-    assert(&*result == expected);
+  if constexpr (Count) {
+    auto strided_it = stride_counting_iterator(It(it));
+    auto strided_last = assignable_sentinel(stride_counting_iterator(It(last)));
+    stride_counting_iterator<It> result = std::ranges::next(std::move(strided_it), std::move(strided_last));
+    assert(base(result.base()) == expected);
     assert(result.stride_count() == 0); // because we got here by assigning from last, not by incrementing
   }
 }
 
-template <std::input_or_output_iterator It>
-constexpr void check_sized_sentinel(It it, It last, int const* expected) {
-  auto n = (last.base() - it.base());
+template <typename It>
+constexpr void check_sized_sentinel(int* it, int* last, int const* expected) {
+  auto n = (last - it);
 
   {
     auto sent = distance_apriori_sentinel(n);
-    auto result = std::ranges::next(std::move(it), sent);
-    assert(&*result == expected);
+    auto result = std::ranges::next(It(it), sent);
+    assert(base(result) == expected);
   }
 
   // Count operations
   {
-    auto strided_it = stride_counting_iterator(std::move(it));
+    auto strided_it = stride_counting_iterator(It(it));
     auto sent = distance_apriori_sentinel(n);
     auto result = std::ranges::next(std::move(strided_it), sent);
-    assert(&*result == expected);
+    assert(base(result.base()) == expected);
 
     if constexpr (std::random_access_iterator<It>) {
       assert(result.stride_count() == 1); // should have used exactly one +=
@@ -89,22 +103,22 @@ constexpr void check_sized_sentinel(It it, It last, int const* expected) {
   }
 }
 
-template <std::input_or_output_iterator It>
-constexpr void check_sentinel(It it, It last, int const* expected) {
-  auto n = (last.base() - it.base());
+template <bool Count, typename It>
+constexpr void check_sentinel(int* it, int* last, int const* expected) {
+  auto n = (last - it);
 
   {
-    auto sent = sentinel_wrapper(last);
-    It result = std::ranges::next(std::move(it), sent);
-    assert(&*result == expected);
+    auto sent = sentinel_wrapper(It(last));
+    It result = std::ranges::next(It(it), sent);
+    assert(base(result) == expected);
   }
 
   // Count operations
-  {
-    auto strided_it = stride_counting_iterator(it);
-    auto sent = sentinel_wrapper(stride_counting_iterator(last));
+  if constexpr (Count) {
+    auto strided_it = stride_counting_iterator(It(it));
+    auto sent = sentinel_wrapper(stride_counting_iterator(It(last)));
     stride_counting_iterator result = std::ranges::next(std::move(strided_it), sent);
-    assert(&*result == expected);
+    assert(base(result.base()) == expected);
     assert(result.stride_count() == n); // must have used ++ until it hit the sentinel
   }
 }
@@ -112,25 +126,25 @@ constexpr void check_sentinel(It it, It last, int const* expected) {
 constexpr bool test() {
   int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
-  check_assignable(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[2]), &range[2]);
-  check_assignable(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
-  check_assignable(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
-  check_assignable(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
-  check_assignable(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
+  check_assignable<false, cpp17_input_iterator<int*>>(  &range[0], &range[2], &range[2]);
+  check_assignable<true,  forward_iterator<int*>>(      &range[0], &range[3], &range[3]);
+  check_assignable<true,  bidirectional_iterator<int*>>(&range[0], &range[4], &range[4]);
+  check_assignable<true,  random_access_iterator<int*>>(&range[0], &range[5], &range[5]);
+  check_assignable<true,  contiguous_iterator<int*>>(   &range[0], &range[6], &range[6]);
 
-  check_sized_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[7]), &range[7]);
-  check_sized_sentinel(cpp20_input_iterator(&range[0]), cpp20_input_iterator(&range[6]), &range[6]);
-  check_sized_sentinel(forward_iterator(&range[0]), forward_iterator(&range[5]), &range[5]);
-  check_sized_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
-  check_sized_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[3]), &range[3]);
-  check_sized_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[2]), &range[2]);
+  check_sized_sentinel<cpp17_input_iterator<int*>>(  &range[0], &range[7], &range[7]);
+  check_sized_sentinel<cpp20_input_iterator<int*>>(  &range[0], &range[6], &range[6]);
+  check_sized_sentinel<forward_iterator<int*>>(      &range[0], &range[5], &range[5]);
+  check_sized_sentinel<bidirectional_iterator<int*>>(&range[0], &range[4], &range[4]);
+  check_sized_sentinel<random_access_iterator<int*>>(&range[0], &range[3], &range[3]);
+  check_sized_sentinel<contiguous_iterator<int*>>(   &range[0], &range[2], &range[2]);
 
-  check_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[1]), &range[1]);
+  check_sentinel<false, cpp17_input_iterator<int*>>(  &range[0], &range[1], &range[1]);
   // cpp20_input_iterator not copyable, so is omitted
-  check_sentinel(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
-  check_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
-  check_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
-  check_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
+  check_sentinel<true,  forward_iterator<int*>>(      &range[0], &range[3], &range[3]);
+  check_sentinel<true,  bidirectional_iterator<int*>>(&range[0], &range[4], &range[4]);
+  check_sentinel<true,  random_access_iterator<int*>>(&range[0], &range[5], &range[5]);
+  check_sentinel<true,  contiguous_iterator<int*>>(   &range[0], &range[6], &range[6]);
   return true;
 }
 
index 70c1d42..b5b00ad 100644 (file)
 #include "test_iterators.h"
 
 constexpr bool test() {
-  static_assert( std::default_initializable<std::counted_iterator<cpp17_input_iterator<int*>>>);
-  static_assert(!std::default_initializable<std::counted_iterator<cpp20_input_iterator<int*>>>);
+  static_assert(!std::default_initializable<std::counted_iterator<cpp17_input_iterator<int*>>>);
+  static_assert( std::default_initializable<std::counted_iterator<forward_iterator<int*>>>);
 
-  std::counted_iterator<cpp17_input_iterator<int*>> iter;
-  assert(iter.base() == cpp17_input_iterator<int*>());
+  std::counted_iterator<forward_iterator<int*>> iter;
+  assert(iter.base() == forward_iterator<int*>());
   assert(iter.count() == 0);
 
   return true;
index 40a9e7f..04d3d6e 100644 (file)
@@ -29,7 +29,7 @@ test()
 
 int main(int, char**)
 {
-    test<cpp17_input_iterator<char*> >();
+    // we don't have a test iterator that is both input and default-constructible, so not testing that case
     test<forward_iterator<char*> >();
     test<bidirectional_iterator<char*> >();
     test<random_access_iterator<char*> >();
index c6dcef9..a55d7a3 100644 (file)
@@ -28,7 +28,7 @@ void
 test(U u)
 {
     const std::move_iterator<U> r2(u);
-    std::move_iterator<It> r1;
+    std::move_iterator<It> r1(It(nullptr));
     std::move_iterator<It>& rr = (r1 = r2);
     assert(r1.base() == u);
     assert(&rr == &r1);
index 52bae5b..709e2f9 100644 (file)
@@ -23,16 +23,16 @@ struct DefaultCtorParent : std::ranges::view_base {
   T *ptr_;
   constexpr DefaultCtorParent(T *ptr) : ptr_(ptr) {}
 
-  constexpr cpp17_input_iterator<T *> begin() { return cpp17_input_iterator<T *>(ptr_); }
-  constexpr cpp17_input_iterator<const T *> begin() const { return cpp17_input_iterator<const T *>(ptr_); }
+  constexpr forward_iterator<T *> begin() { return forward_iterator<T *>(ptr_); }
+  constexpr forward_iterator<const T *> begin() const { return forward_iterator<const T *>(ptr_); }
   constexpr T *end() { return ptr_ + 4; }
   constexpr const T *end() const { return ptr_ + 4; }
 };
 
 template<class T>
-constexpr bool operator==(const cpp17_input_iterator<T*> &lhs, const T *rhs) { return lhs.base() == rhs; }
+constexpr bool operator==(const forward_iterator<T*> &lhs, const T *rhs) { return lhs.base() == rhs; }
 template<class T>
-constexpr bool operator==(const T *lhs, const cpp17_input_iterator<T*> &rhs) { return rhs.base() == lhs; }
+constexpr bool operator==(const T *lhs, const forward_iterator<T*> &rhs) { return rhs.base() == lhs; }
 
 constexpr bool test() {
   using Base = DefaultCtorParent<ChildView>;
index acf7ca1..ba960d4 100644 (file)
 
 template<class T>
 struct ForwardView : std::ranges::view_base {
-  friend forward_iterator<T*> begin(ForwardView&) { return forward_iterator<T*>(nullptr); }
-  friend forward_iterator<T*> begin(ForwardView const&) { return forward_iterator<T*>(nullptr); }
-  friend forward_iterator<T*> end(ForwardView&) { return forward_iterator<T*>(nullptr); }
-  friend forward_iterator<T*> end(ForwardView const&) { return forward_iterator<T*>(nullptr); }
+  forward_iterator<T*> begin() const;
+  sentinel_wrapper<forward_iterator<T*>> end() const;
 };
 
 template<class T>
 struct InputView : std::ranges::view_base {
-  friend cpp17_input_iterator<T*> begin(InputView&) { return cpp17_input_iterator<T*>(nullptr); }
-  friend cpp17_input_iterator<T*> begin(InputView const&) { return cpp17_input_iterator<T*>(nullptr); }
-  friend cpp17_input_iterator<T*> end(InputView&) { return cpp17_input_iterator<T*>(nullptr); }
-  friend cpp17_input_iterator<T*> end(InputView const&) { return cpp17_input_iterator<T*>(nullptr); }
+  cpp17_input_iterator<T*> begin() const;
+  sentinel_wrapper<cpp17_input_iterator<T*>> end() const;
 };
 
 template<class T>
index 5288ed6..267a4c9 100644 (file)
@@ -25,6 +25,6 @@
 static_assert(std::same_as<std::ranges::sentinel_t<test_range<cpp20_input_iterator> >, sentinel>);
 static_assert(std::same_as<std::ranges::sentinel_t<test_range<cpp20_input_iterator> const>, sentinel>);
 static_assert(std::same_as<std::ranges::sentinel_t<test_non_const_range<cpp20_input_iterator> >, sentinel>);
-static_assert(std::same_as<std::ranges::sentinel_t<test_common_range<cpp17_input_iterator> >, cpp17_input_iterator<int*> >);
-static_assert(std::same_as<std::ranges::sentinel_t<test_common_range<cpp17_input_iterator> const>, cpp17_input_iterator<int const*> >);
-static_assert(std::same_as<std::ranges::sentinel_t<test_non_const_common_range<cpp17_input_iterator> >, cpp17_input_iterator<int*> >);
+static_assert(std::same_as<std::ranges::sentinel_t<test_common_range<forward_iterator> >, forward_iterator<int*> >);
+static_assert(std::same_as<std::ranges::sentinel_t<test_common_range<forward_iterator> const>, forward_iterator<int const*> >);
+static_assert(std::same_as<std::ranges::sentinel_t<test_non_const_common_range<forward_iterator> >, forward_iterator<int*> >);
index dd606be..0ee8eed 100644 (file)
 #include <ranges>
 
 #include "test_iterators.h"
-#include "test_range.h"
 
+template<class It>             struct Common { It begin() const; It end() const; };
+template<class It>             struct NonCommon { It begin() const; sentinel_wrapper<It> end() const; };
+template<class It, class Sent> struct Range { It begin() const; Sent end() const; };
 
+static_assert(!std::ranges::common_range<Common<cpp17_input_iterator<int*>>>); // not a sentinel for itself
+static_assert(!std::ranges::common_range<Common<cpp20_input_iterator<int*>>>); // not a sentinel for itself
+static_assert( std::ranges::common_range<Common<forward_iterator<int*>>>);
+static_assert( std::ranges::common_range<Common<bidirectional_iterator<int*>>>);
+static_assert( std::ranges::common_range<Common<random_access_iterator<int*>>>);
+static_assert( std::ranges::common_range<Common<contiguous_iterator<int*>>>);
+static_assert( std::ranges::common_range<Common<int*>>);
 
-static_assert(!std::ranges::common_range<test_range<cpp17_input_iterator> >);
-static_assert(!std::ranges::common_range<test_range<cpp17_input_iterator> const>);
+static_assert(!std::ranges::common_range<NonCommon<cpp17_input_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<cpp20_input_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<forward_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<bidirectional_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<random_access_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<contiguous_iterator<int*>>>);
+static_assert(!std::ranges::common_range<NonCommon<int*>>);
 
-static_assert(!std::ranges::common_range<test_non_const_range<cpp17_input_iterator> >);
-static_assert(!std::ranges::common_range<test_non_const_range<cpp17_input_iterator> const>);
+// Test when begin() and end() only differ by their constness.
+static_assert(!std::ranges::common_range<Range<int*, int const*>>);
 
-static_assert(std::ranges::common_range<test_common_range<cpp17_input_iterator> >);
-static_assert(std::ranges::common_range<test_common_range<cpp17_input_iterator> const>);
+// Simple test with a sized_sentinel.
+static_assert(!std::ranges::common_range<Range<int*, sized_sentinel<int*>>>);
 
-static_assert(std::ranges::common_range<test_non_const_common_range<cpp17_input_iterator> >);
-static_assert(!std::ranges::common_range<test_non_const_common_range<cpp17_input_iterator> const>);
+// Make sure cv-qualification doesn't impact the concept when begin() and end() have matching qualifiers.
+static_assert( std::ranges::common_range<Common<forward_iterator<int*>> const>);
+static_assert(!std::ranges::common_range<NonCommon<forward_iterator<int*>> const>);
 
-struct subtly_not_common {
-  int* begin() const;
+// Test with a range that's a common_range only when const-qualified.
+struct Range1 {
+  int* begin();
+  int const* begin() const;
   int const* end() const;
 };
-static_assert(std::ranges::range<subtly_not_common> && !std::ranges::common_range<subtly_not_common>);
-static_assert(std::ranges::range<subtly_not_common const> && !std::ranges::common_range<subtly_not_common const>);
+static_assert(!std::ranges::common_range<Range1>);
+static_assert( std::ranges::common_range<Range1 const>);
 
-struct common_range_non_const_only {
+// Test with a range that's a common_range only when not const-qualified.
+struct Range2 {
   int* begin() const;
   int* end();
   int const* end() const;
 };
-static_assert(std::ranges::range<common_range_non_const_only>&& std::ranges::common_range<common_range_non_const_only>);
-static_assert(std::ranges::range<common_range_non_const_only const> && !std::ranges::common_range<common_range_non_const_only const>);
-
-struct common_range_const_only {
-  int* begin();
-  int const* begin() const;
-  int const* end() const;
-};
-static_assert(std::ranges::range<common_range_const_only> && !std::ranges::common_range<common_range_const_only>);
-static_assert(std::ranges::range<common_range_const_only const>&& std::ranges::common_range<common_range_const_only const>);
+static_assert( std::ranges::common_range<Range2>);
+static_assert(!std::ranges::common_range<Range2 const>);
index 1a2b66c..c27c972 100644 (file)
@@ -32,14 +32,14 @@ static_assert(std::ranges::input_range<test_non_const_range<cpp20_input_iterator
 static_assert(!std::ranges::input_range<test_non_const_range<cpp17_input_iterator> const>);
 static_assert(!std::ranges::input_range<test_non_const_range<cpp20_input_iterator> const>);
 
-static_assert(std::ranges::input_range<test_common_range<cpp17_input_iterator> >);
+static_assert(std::ranges::input_range<test_common_range<forward_iterator> >);
 static_assert(!std::ranges::input_range<test_common_range<cpp20_input_iterator> >);
 
-static_assert(std::ranges::input_range<test_common_range<cpp17_input_iterator> const>);
+static_assert(std::ranges::input_range<test_common_range<forward_iterator> const>);
 static_assert(!std::ranges::input_range<test_common_range<cpp20_input_iterator> const>);
 
-static_assert(std::ranges::input_range<test_non_const_common_range<cpp17_input_iterator> >);
+static_assert(std::ranges::input_range<test_non_const_common_range<forward_iterator> >);
 static_assert(!std::ranges::input_range<test_non_const_common_range<cpp20_input_iterator> >);
 
-static_assert(!std::ranges::input_range<test_non_const_common_range<cpp17_input_iterator> const>);
+static_assert(!std::ranges::input_range<test_non_const_common_range<forward_iterator> const>);
 static_assert(!std::ranges::input_range<test_non_const_common_range<cpp20_input_iterator> const>);
index 336af63..419a47f 100644 (file)
@@ -31,7 +31,7 @@ constexpr bool test() {
   assert(a4.begin() == globalBuff + 4);
   assert(a4.size() == 4);
 
-  std::ranges::subrange<InputIter> b(InputIter(globalBuff), InputIter(globalBuff + 8));
+  std::ranges::subrange<InputIter, sentinel_wrapper<InputIter>> b(InputIter(globalBuff), sentinel_wrapper(InputIter(globalBuff + 8)));
   auto b1 = std::move(b).next();
   assert(b1.begin().base() == globalBuff + 1);
 
index 34b5d41..07c5586 100644 (file)
@@ -178,9 +178,9 @@ int main(int, char**)
     typedef ThrowingIterator<char> TIter;
     typedef cpp17_input_iterator<TIter> IIter;
     const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-    test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
-    test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
-    test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+    test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter(TIter()));
+    test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter(TIter()));
+    test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter(TIter()));
 
     test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
index f8b10c6..87f3885 100644 (file)
@@ -178,9 +178,9 @@ int main(int, char**)
     typedef ThrowingIterator<char> TIter;
     typedef cpp17_input_iterator<TIter> IIter;
     const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-    test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
-    test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
-    test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+    test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter(TIter()));
+    test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter(TIter()));
+    test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter(TIter()));
 
     test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
index 1f0b12f..e0e7ff9 100644 (file)
@@ -156,9 +156,9 @@ int main(int, char**)
     typedef ThrowingIterator<char> TIter;
     typedef cpp17_input_iterator<TIter> IIter;
     const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-    test_exceptions(S(), 0, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
-    test_exceptions(S(), 0, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
-    test_exceptions(S(), 0, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+    test_exceptions(S(), 0, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter(TIter()));
+    test_exceptions(S(), 0, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter(TIter()));
+    test_exceptions(S(), 0, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter(TIter()));
 
     test_exceptions(S(), 0, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), 0, TIter(s, s+10, 5, TIter::TADereference), TIter());
index 9ce4a37..ea6f234 100644 (file)
@@ -1008,9 +1008,9 @@ int main(int, char**)
     typedef ThrowingIterator<char> TIter;
     typedef cpp17_input_iterator<TIter> IIter;
     const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
-    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
-    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter(TIter()));
+    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter(TIter()));
+    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter(TIter()));
 
     test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 5, TIter::TADereference), TIter());
index 4bf082b..36f7cae 100644 (file)
@@ -66,7 +66,6 @@ public:
 
     TEST_CONSTEXPR_CXX14 It base() const {return it_;}
 
-    TEST_CONSTEXPR_CXX14 cpp17_input_iterator() : it_() {}
     explicit TEST_CONSTEXPR_CXX14 cpp17_input_iterator(It it) : it_(it) {}
     template <class U, class T>
         TEST_CONSTEXPR_CXX14 cpp17_input_iterator(const cpp17_input_iterator<U, T>& u) :it_(u.it_) {}