[libcxx-commits] [libcxx] [libc++][ranges] Implement `ranges::stride_view`. (PR #65200)

Will Hawkins via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 2 19:08:00 PST 2024


================
@@ -0,0 +1,372 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator(__iterator<!_Const> __i)
+//    requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+//                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+
+#include <ranges>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+struct NotSimpleViewIterBegin : InputIterBase<NotSimpleViewIterBegin> {};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterBegin : InputIterBase<NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterBegin() = default;
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewConstIterBegin&&) {}
+  constexpr NotSimpleViewConstIterBegin& operator=(const NotSimpleViewConstIterBegin&) {}
+  constexpr NotSimpleViewConstIterBegin& operator=(NotSimpleViewConstIterBegin&&) {}
+
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewConstIterBegin&) {}
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewIterBegin&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewIterBegin&&)
+    requires MoveConvertible
+  {}
+};
+
+struct NotSimpleViewIterEnd : InputIterBase<NotSimpleViewIterEnd> {};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterEnd : InputIterBase<NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterEnd() = default;
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewConstIterEnd&&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd& operator=(NotSimpleViewConstIterEnd&&) {}
+
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewIterEnd&&)
+    requires MoveConvertible
+  {}
+};
+
+constexpr bool operator==(const NotSimpleViewIterBegin&, const NotSimpleViewIterEnd&) { return true; }
+constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIterBegin&) { return true; }
+
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+template <bool CopyConvertible, bool MoveConvertible>
+constexpr bool
+operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+  return true;
+}
+
+/*
+ * Goal: We will need a way to get a stride_view<true>::__iterator and a
+ * stride_view<false>::__iterator because those are the two possible types
+ * of the stride_view::__iterator constructor. The template value is determined
+ * by whether the stride_view::__iterator is derivative of a stride_view over a
+ * view that is simple.
+ *
+ * So, first things first, we need to build a stride_view over a (non-)simple view.
+ * There are (at least) two ways that a view can be non-simple:
+ * 1. The iterator type for const begin is different than the iterator type for begin
+ * 2. The iterator type for const end is different that the iterator type for end
+ *
+ * So, let's create two different classes where that is the case so that we can test
+ * for those conditions individually. We parameterize with a template to decide
+ * whether to
+ * 1. enable converting constructors between the non-const and the const version.
+ * That feature is important for testing the stride_view::__iterator<true> converting
+ * constructor from a stride_view::_iterator<false> iterator.
+ * 2. enable copyability. That feature is important for testing whether the requirement
+ * the that copy constructor for the stride_view::__iterator<false> type actually moves
+ * the underlying iterator.
+ */
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentBegin : std::ranges::view_base {
+  constexpr NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible> begin() const { return {}; }
+  constexpr NotSimpleViewIterBegin begin() { return {}; }
+
+  constexpr NotSimpleViewIterEnd end() const { return {}; }
+};
+
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentEnd : std::ranges::view_base {
+  constexpr NotSimpleViewIterBegin begin() const { return {}; }
+  constexpr NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible> end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
+
+constexpr bool non_simple_view_iter_ctor_test() {
+  using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+  using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+  using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
+  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, NotSimpleStrideViewIter>);
+  return true;
+}
+
+constexpr bool non_const_iterator_copy_ctor() {
+  // All tests share the following general configuration.
+  //
+  // Instantiate a stride view StrideView over a non-simple view (NotSimpleViewBeingStrided) whose
+  // 1. std::ranges::iterator_t<StrideView> base's type is NotSimpleViewBeingStridedIterator
+  // 2. std::ranges::iterator_t<const StrideView> base's type is NotSimpleViewBeingStridedConstIterator
+  // 3. NotSimpleViewBeingStridedIterator is ONLY move-convertible to NotSimpleViewBeingStridedConstIterator
+  // 4. std::ranges::sentinel_t are the same whether SV is const or not.
+  // 4. the type of StrideView::end is the same whether StrideView is const or not.
+  // 5. the type of StrideView::begin is stride_view::iterator<true> when StrideView is const and
----------------
hawkinsw wrote:

Great eyes!

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


More information about the libcxx-commits mailing list