[libcxx-commits] [libcxx] 7b20e05 - [libcxx][ranges] Add `ranges::iota_view`.

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 13 11:31:17 PDT 2021


Author: zoecarver
Date: 2021-08-13T11:31:08-07:00
New Revision: 7b20e05c714e273ebe89d713cec61e5a022bbac6

URL: https://github.com/llvm/llvm-project/commit/7b20e05c714e273ebe89d713cec61e5a022bbac6
DIFF: https://github.com/llvm/llvm-project/commit/7b20e05c714e273ebe89d713cec61e5a022bbac6.diff

LOG: [libcxx][ranges] Add `ranges::iota_view`.

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

Added: 
    libcxx/include/__ranges/iota_view.h
    libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp
    libcxx/test/std/ranges/range.factories/range.iota.view/types.h
    libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__iterator/concepts.h
    libcxx/include/module.modulemap
    libcxx/include/ranges
    libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index e174cda1a7ca2..77239c314f787 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -138,7 +138,7 @@ Section,Description,Dependencies,Assignee,Complete
 `[range.view.ref] <http://wg21.link/range.view>`_,`ref-view <https://llvm.org/D102020>`_,[view.interface],Zoe Carver,✅
 `[range.filter] <http://wg21.link/range.filter>`_,filter_view,[range.all],Louis Dionne,Not started
 `[range.transform] <http://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,✅
-`[range.iota] <http://wg21.link/range.iota>`_,iota_view,[range.all],Zoe Carver,In Progress
+`[range.iota] <http://wg21.link/range.iota>`_,iota_view,[range.all],Zoe Carver,✅
 `[range.take] <http://wg21.link/range.take>`_,take_view,[range.all],Zoe Carver,✅
 `[range.join] <http://wg21.link/range.join>`_,join_view,[range.all],Zoe Carver,In Progress
 `[range.empty] <http://wg21.link/range.empty>`_,`empty_view <https://llvm.org/D103208>`_,[view.interface],Zoe Carver,✅

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d2760ee45ad3c..914c74c7ceb60 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -223,6 +223,7 @@ set(files
   __ranges/empty.h
   __ranges/enable_borrowed_range.h
   __ranges/enable_view.h
+  __ranges/iota_view.h
   __ranges/non_propagating_cache.h
   __ranges/ref_view.h
   __ranges/reverse_view.h

diff  --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index 6eb4aef10528a..db836bda25391 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -72,6 +72,8 @@ concept __signed_integer_like = signed_integral<_Tp>;
 
 template<class _Ip>
 concept weakly_incrementable =
+  // TODO: remove this once the clang bug is fixed (bugs.llvm.org/PR48173).
+  !same_as<_Ip, bool> && // Currently, clang does not handle bool correctly.
   movable<_Ip> &&
   requires(_Ip __i) {
     typename iter_
diff erence_t<_Ip>;

diff  --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h
new file mode 100644
index 0000000000000..f302826b02474
--- /dev/null
+++ b/libcxx/include/__ranges/iota_view.h
@@ -0,0 +1,403 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___RANGES_IOTA_VIEW_H
+#define _LIBCPP___RANGES_IOTA_VIEW_H
+
+#include <__config>
+#include <__debug>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/unreachable_sentinel.h>
+#include <__ranges/copyable_box.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/view_interface.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+#include <concepts>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+namespace ranges {
+  template<class _Int>
+  struct __get_wider_signed {
+    static auto __call() {
+           if constexpr (sizeof(_Int) < sizeof(short)) return type_identity<short>{};
+      else if constexpr (sizeof(_Int) < sizeof(int))   return type_identity<int>{};
+      else if constexpr (sizeof(_Int) < sizeof(long))  return type_identity<long>{};
+      else                                             return type_identity<long long>{};
+
+      static_assert(sizeof(_Int) <= sizeof(long long),
+        "Found integer-like type that is bigger than largest integer like type.");
+    }
+
+    using type = typename decltype(__call())::type;
+  };
+
+  template<class _Start>
+  using _IotaDiffT = typename _If<
+      (!integral<_Start> || sizeof(iter_
diff erence_t<_Start>) > sizeof(_Start)),
+      type_identity<iter_
diff erence_t<_Start>>,
+      __get_wider_signed<_Start>
+    >::type;
+
+  template<class _Iter>
+  concept __decrementable = incrementable<_Iter> && requires(_Iter __i) {
+    { --__i } -> same_as<_Iter&>;
+    { __i-- } -> same_as<_Iter>;
+  };
+
+  template<class _Iter>
+  concept __advanceable =
+    __decrementable<_Iter> && totally_ordered<_Iter> &&
+    requires(_Iter __i, const _Iter __j, const _IotaDiffT<_Iter> __n) {
+      { __i += __n } -> same_as<_Iter&>;
+      { __i -= __n } -> same_as<_Iter&>;
+      _Iter(__j + __n);
+      _Iter(__n + __j);
+      _Iter(__j - __n);
+      { __j - __j } -> convertible_to<_IotaDiffT<_Iter>>;
+    };
+
+  template<class>
+  struct __iota_iterator_category {};
+
+  template<incrementable _Tp>
+  struct __iota_iterator_category<_Tp> {
+    using iterator_category = input_iterator_tag;
+  };
+
+  template<weakly_incrementable _Start, semiregular _Bound = unreachable_sentinel_t>
+    requires __weakly_equality_comparable_with<_Start, _Bound> && copyable<_Start>
+  class iota_view : public view_interface<iota_view<_Start, _Bound>> {
+    struct __iterator : public __iota_iterator_category<_Start> {
+      friend class iota_view;
+
+      using iterator_concept =
+        _If<__advanceable<_Start>,   random_access_iterator_tag,
+        _If<__decrementable<_Start>, bidirectional_iterator_tag,
+        _If<incrementable<_Start>,   forward_iterator_tag,
+        /*Else*/                     input_iterator_tag>>>;
+
+      using value_type = _Start;
+      using 
diff erence_type = _IotaDiffT<_Start>;
+
+      _Start __value_ = _Start();
+
+      _LIBCPP_HIDE_FROM_ABI
+      __iterator() requires default_initializable<_Start> = default;
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr explicit __iterator(_Start __value) : __value_(_VSTD::move(__value)) {}
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr _Start operator*() const noexcept(is_nothrow_copy_constructible_v<_Start>) {
+        return __value_;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator& operator++() {
+        ++__value_;
+        return *this;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr void operator++(int) { ++*this; }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator operator++(int) requires incrementable<_Start> {
+        auto __tmp = *this;
+        ++*this;
+        return __tmp;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator& operator--() requires __decrementable<_Start> {
+        --__value_;
+        return *this;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator  operator--(int) requires __decrementable<_Start> {
+        auto __tmp = *this;
+        --*this;
+        return __tmp;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator& operator+=(
diff erence_type __n)
+        requires __advanceable<_Start>
+      {
+        if constexpr (__integer_like<_Start> && !__signed_integer_like<_Start>) {
+          if (__n >= 
diff erence_type(0)) {
+            __value_ += static_cast<_Start>(__n);
+          } else {
+            __value_ -= static_cast<_Start>(-__n);
+          }
+        } else {
+          __value_ += __n;
+        }
+        return *this;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr __iterator& operator-=(
diff erence_type __n)
+        requires __advanceable<_Start>
+      {
+        if constexpr (__integer_like<_Start> && !__signed_integer_like<_Start>) {
+          if (__n >= 
diff erence_type(0)) {
+            __value_ -= static_cast<_Start>(__n);
+          } else {
+            __value_ += static_cast<_Start>(-__n);
+          }
+        } else {
+          __value_ -= __n;
+        }
+        return *this;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      constexpr _Start operator[](
diff erence_type __n) const
+        requires __advanceable<_Start>
+      {
+        return _Start(__value_ + __n);
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
+        requires equality_comparable<_Start>
+      {
+        return __x.__value_ == __y.__value_;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
+        requires totally_ordered<_Start>
+      {
+        return __x.__value_ < __y.__value_;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
+        requires totally_ordered<_Start>
+      {
+        return __y < __x;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
+        requires totally_ordered<_Start>
+      {
+        return !(__y < __x);
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
+        requires totally_ordered<_Start>
+      {
+        return !(__x < __y);
+      }
+
+//       friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
+//         requires totally_ordered<_Start> && three_way_comparable<_Start>
+//       {
+//         return __x.__value_ <=> __y.__value_;
+//       }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr __iterator operator+(__iterator __i, 
diff erence_type __n)
+        requires __advanceable<_Start>
+      {
+        __i += __n;
+        return __i;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr __iterator operator+(
diff erence_type __n, __iterator __i)
+        requires __advanceable<_Start>
+      {
+        return __i + __n;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr __iterator operator-(__iterator __i, 
diff erence_type __n)
+        requires __advanceable<_Start>
+      {
+        __i -= __n;
+        return __i;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr 
diff erence_type operator-(const __iterator& __x, const __iterator& __y)
+        requires __advanceable<_Start>
+      {
+        if constexpr (__integer_like<_Start>) {
+          if constexpr (__signed_integer_like<_Start>) {
+            return 
diff erence_type(
diff erence_type(__x.__value_) - 
diff erence_type(__y.__value_));
+          }
+          if (__y.__value_ > __x.__value_) {
+            return 
diff erence_type(-
diff erence_type(__y.__value_ - __x.__value_));
+          }
+          return 
diff erence_type(__x.__value_ - __y.__value_);
+        }
+        return __x.__value_ - __y.__value_;
+      }
+    };
+
+    struct __sentinel {
+      friend class iota_view;
+
+    private:
+      _Bound __bound_ = _Bound();
+
+    public:
+      _LIBCPP_HIDE_FROM_ABI
+      __sentinel() = default;
+      constexpr explicit __sentinel(_Bound __bound) : __bound_(_VSTD::move(__bound)) {}
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) {
+        return __x.__value_ == __y.__bound_;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr iter_
diff erence_t<_Start> operator-(const __iterator& __x, const __sentinel& __y)
+        requires sized_sentinel_for<_Bound, _Start>
+      {
+        return __x.__value_ - __y.__bound_;
+      }
+
+      _LIBCPP_HIDE_FROM_ABI
+      friend constexpr iter_
diff erence_t<_Start> operator-(const __sentinel& __x, const __iterator& __y)
+        requires sized_sentinel_for<_Bound, _Start>
+      {
+        return -(__y - __x);
+      }
+    };
+
+    _Start __value_ = _Start();
+    _Bound __bound_ = _Bound();
+
+  public:
+    _LIBCPP_HIDE_FROM_ABI
+    iota_view() requires default_initializable<_Start> = default;
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr explicit iota_view(_Start __value) : __value_(_VSTD::move(__value)) { }
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr iota_view(type_identity_t<_Start> __value, type_identity_t<_Bound> __bound)
+      : __value_(_VSTD::move(__value)), __bound_(_VSTD::move(__bound)) {
+      // Validate the precondition if possible.
+      if constexpr (totally_ordered_with<_Start, _Bound>) {
+        _LIBCPP_ASSERT(ranges::less_equal()(__value_, __bound_),
+                       "Precondition violated: value is greater than bound.");
+      }
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr iota_view(__iterator __first, __iterator __last)
+      requires same_as<_Start, _Bound>
+      : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last.__value_)) {}
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr iota_view(__iterator __first, _Bound __last)
+      requires same_as<_Bound, unreachable_sentinel_t>
+      : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last)) {}
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr iota_view(__iterator __first, __sentinel __last)
+      requires (!same_as<_Start, _Bound> && !same_as<_Start, unreachable_sentinel_t>)
+      : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last.__bound_)) {}
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr __iterator begin() const { return __iterator{__value_}; }
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto end() const {
+      if constexpr (same_as<_Bound, unreachable_sentinel_t>)
+        return unreachable_sentinel;
+      else
+        return __sentinel{__bound_};
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr __iterator end() const requires same_as<_Start, _Bound> {
+      return __iterator{__bound_};
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto size() const
+      requires (same_as<_Start, _Bound> && __advanceable<_Start>) ||
+               (integral<_Start> && integral<_Bound>) ||
+               sized_sentinel_for<_Bound, _Start>
+    {
+      if constexpr (__integer_like<_Start> && __integer_like<_Bound>) {
+        if (__value_ < 0) {
+          if (__bound_ < 0) {
+            return _VSTD::__to_unsigned_like(-__value_) - _VSTD::__to_unsigned_like(-__bound_);
+          }
+          return _VSTD::__to_unsigned_like(__bound_) + _VSTD::__to_unsigned_like(-__value_);
+        }
+        return _VSTD::__to_unsigned_like(__bound_) - _VSTD::__to_unsigned_like(__value_);
+      }
+      return _VSTD::__to_unsigned_like(__bound_ - __value_);
+    }
+  };
+
+  template<class _Start, class _Bound>
+    requires (!__integer_like<_Start> || !__integer_like<_Bound> ||
+              (__signed_integer_like<_Start> == __signed_integer_like<_Bound>))
+  iota_view(_Start, _Bound) -> iota_view<_Start, _Bound>;
+
+  template<class _Start, class _Bound>
+  inline constexpr bool enable_borrowed_range<iota_view<_Start, _Bound>> = true;
+} // namespace ranges
+
+namespace views {
+namespace __iota {
+  struct __fn {
+    template<class _Start>
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto operator()(_Start&& __start) const
+      noexcept(noexcept(ranges::iota_view(_VSTD::forward<_Start>(__start))))
+            -> decltype(ranges::iota_view(_VSTD::forward<_Start>(__start)))
+    {
+                 return ranges::iota_view(_VSTD::forward<_Start>(__start));
+    }
+
+    template<class _Start, class _Bound>
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto operator()(_Start&& __start, _Bound&& __bound) const
+      noexcept(noexcept(ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound))))
+            -> decltype(ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound)))
+    {
+                 return ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound));
+    }
+  };
+} // namespace __iota
+
+inline namespace __cpo {
+  inline constexpr auto iota = __iota::__fn{};
+}
+} // namespace views
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_IOTA_VIEW_H

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index f7c899c5fe535..079dff201804b 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -658,6 +658,7 @@ module std [system] {
       module empty_view             { private header "__ranges/empty_view.h"            }
       module enable_borrowed_range  { private header "__ranges/enable_borrowed_range.h" }
       module enable_view            { private header "__ranges/enable_view.h"           }
+      module iota_view              { private header "__ranges/iota_view.h"             }
       module non_propagating_cache  { private header "__ranges/non_propagating_cache.h" }
       module ref_view               { private header "__ranges/ref_view.h"              }
       module reverse_view           { private header "__ranges/reverse_view.h"          }

diff  --git a/libcxx/include/ranges b/libcxx/include/ranges
index 49e79647739c8..df8d4194ffa14 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -177,6 +177,13 @@ namespace std::ranges {
   template<copy_constructible T>
     requires is_object_v<T>
   class single_view;
+
+  template<weakly_incrementable W, semiregular Bound = unreachable_sentinel_t>
+    requires weakly-equality-comparable-with<W, Bound> && copyable<W>
+  class iota_view;
+
+  template<class W, class Bound>
+    inline constexpr bool enable_borrowed_range<iota_view<W, Bound>> = true;
 }
 
 */
@@ -199,6 +206,7 @@ namespace std::ranges {
 #include <__ranges/empty_view.h>
 #include <__ranges/enable_borrowed_range.h>
 #include <__ranges/enable_view.h>
+#include <__ranges/iota_view.h>
 #include <__ranges/ref_view.h>
 #include <__ranges/reverse_view.h>
 #include <__ranges/take_view.h>

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp
new file mode 100644
index 0000000000000..8b2d4cad2da25
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp
@@ -0,0 +1,16 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}}
+#include <__ranges/iota_view.h>

diff  --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp
index a3198357bbb76..5fad38d4d6cfd 100644
--- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp
@@ -30,6 +30,7 @@ static_assert(!std::weakly_incrementable<int&>);
 static_assert(!std::weakly_incrementable<int()>);
 static_assert(!std::weakly_incrementable<int (*)()>);
 static_assert(!std::weakly_incrementable<int (&)()>);
+static_assert(!std::weakly_incrementable<bool>);
 
 struct S {};
 static_assert(!std::weakly_incrementable<int S::*>);

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp
new file mode 100644
index 0000000000000..16b80b19ef3b3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iterator begin() const;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+template<class T>
+constexpr void testType() {
+  {
+    std::ranges::iota_view<T> io(T(0));
+    assert(*io.begin() == T(0));
+  }
+  {
+    std::ranges::iota_view<T> io(T(10));
+    assert(*io.begin() == T(10));
+    assert(*std::move(io).begin() == T(10));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(0));
+    assert(*io.begin() == T(0));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(10));
+    assert(*io.begin() == T(10));
+  }
+}
+
+constexpr bool test() {
+  testType<SomeInt>();
+  testType<long long>();
+  testType<unsigned long long>();
+  testType<signed long>();
+  testType<unsigned long>();
+  testType<int>();
+  testType<unsigned>();
+  testType<short>();
+  testType<unsigned short>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..7fbf987463652
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class W, class Bound>
+//   inline constexpr bool enable_borrowed_range<iota_view<W, Bound>> = true;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+#include "types.h"
+
+static_assert(std::ranges::enable_borrowed_range<std::ranges::iota_view<int, int>>);
+static_assert(std::ranges::enable_borrowed_range<std::ranges::iota_view<int, std::unreachable_sentinel_t>>);
+static_assert(std::ranges::enable_borrowed_range<std::ranges::iota_view<int, IntComparableWith<int>>>);

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..d1f4e5a5f4503
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class W, class Bound>
+//     requires (!is-integer-like<W> || !is-integer-like<Bound> ||
+//               (is-signed-integer-like<W> == is-signed-integer-like<Bound>))
+//     iota_view(W, Bound) -> iota_view<W, Bound>;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+#include "types.h"
+
+template<class T, class U>
+concept CanDeduce = requires(const T& t, const U& u) {
+  std::ranges::iota_view(t, u);
+};
+
+void test() {
+  static_assert(std::same_as<
+    decltype(std::ranges::iota_view(0, 0)),
+    std::ranges::iota_view<int, int>
+  >);
+
+  static_assert(std::same_as<
+    decltype(std::ranges::iota_view(0)),
+    std::ranges::iota_view<int, std::unreachable_sentinel_t>
+  >);
+
+  static_assert(std::same_as<
+    decltype(std::ranges::iota_view(0, std::unreachable_sentinel)),
+    std::ranges::iota_view<int, std::unreachable_sentinel_t>
+  >);
+
+  static_assert(std::same_as<
+    decltype(std::ranges::iota_view(0, IntComparableWith(0))),
+    std::ranges::iota_view<int, IntComparableWith<int>>
+  >);
+
+  static_assert( CanDeduce<int, int>);
+  static_assert(!CanDeduce<int, unsigned>);
+  static_assert(!CanDeduce<unsigned, int>);
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..724656429f7d6
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// iota_view() requires default_­initializable<W> = default;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view<Int42<DefaultTo42>> io;
+    assert((*io.begin()).value_ == 42);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  static_assert(!std::default_initializable<Int42<ValueCtor>>);
+  static_assert( std::default_initializable<Int42<DefaultTo42>>);
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp
new file mode 100644
index 0000000000000..61eb8a2d16732
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iota_view(iterator first, see below last);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view commonView(SomeInt(0), SomeInt(10));
+    std::ranges::iota_view<SomeInt, SomeInt> io(commonView.begin(), commonView.end());
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+
+  {
+    std::ranges::iota_view unreachableSent(SomeInt(0));
+    std::ranges::iota_view<SomeInt> io(unreachableSent.begin(), std::unreachable_sentinel);
+    assert(std::ranges::next(io.begin(), 10) != io.end());
+  }
+
+  {
+    std::ranges::iota_view 
diff erentTypes(SomeInt(0), IntComparableWith(SomeInt(10)));
+    std::ranges::iota_view<SomeInt, IntComparableWith<SomeInt>> io(
diff erentTypes.begin(), 
diff erentTypes.end());
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
+

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp
new file mode 100644
index 0000000000000..21f5558f61d81
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare
+
+// constexpr iota_view(type_identity_t<W> value, type_identity_t<Bound> bound);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(0), SomeInt(10));
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+
+  {
+    std::ranges::iota_view<SomeInt> io(SomeInt(0), std::unreachable_sentinel);
+    assert(std::ranges::next(io.begin(), 10) != io.end());
+  }
+
+  {
+    std::ranges::iota_view<SomeInt, IntComparableWith<SomeInt>> io(SomeInt(0), IntComparableWith(SomeInt(10)));
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+
+  {
+    // This is allowed only when using the constructor (not the deduction guide).
+    std::ranges::iota_view<int, unsigned> signedUnsigned(0, 10);
+    assert(std::ranges::next(signedUnsigned.begin(), 10) == signedUnsigned.end());
+  }
+
+  {
+    // This is allowed only when using the constructor (not the deduction guide).
+    std::ranges::iota_view<unsigned, int> signedUnsigned(0, 10);
+    assert(std::ranges::next(signedUnsigned.begin(), 10) == signedUnsigned.end());
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
+

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp
new file mode 100644
index 0000000000000..cc65b9368a2f9
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr explicit iota_view(W value);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+struct SomeIntComparable {
+  using 
diff erence_type = int;
+
+  SomeInt value_;
+  constexpr SomeIntComparable() : value_(SomeInt(10)) {}
+
+  friend constexpr bool operator==(SomeIntComparable lhs, SomeIntComparable rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+  friend constexpr bool operator==(SomeIntComparable lhs, SomeInt rhs) {
+    return lhs.value_ == rhs;
+  }
+  friend constexpr bool operator==(SomeInt lhs, SomeIntComparable rhs) {
+    return lhs == rhs.value_;
+  }
+
+  friend constexpr 
diff erence_type operator-(SomeIntComparable lhs, SomeIntComparable rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr SomeIntComparable& operator++() { ++value_; return *this; }
+  constexpr SomeIntComparable  operator++(int) { auto tmp = *this; ++value_; return tmp; }
+  constexpr SomeIntComparable  operator--() { --value_; return *this; }
+};
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view<SomeInt> io(SomeInt(42));
+    assert((*io.begin()).value_ == 42);
+    // Check that end returns std::unreachable_sentinel.
+    assert(io.end() != io.begin());
+    static_assert(std::same_as<decltype(io.end()), std::unreachable_sentinel_t>);
+  }
+
+  {
+    std::ranges::iota_view<SomeInt, SomeIntComparable> io(SomeInt(0));
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+  {
+    static_assert(!std::is_convertible_v<std::ranges::iota_view<SomeInt>, SomeInt>);
+    static_assert( std::is_constructible_v<std::ranges::iota_view<SomeInt>, SomeInt>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp
new file mode 100644
index 0000000000000..418a52a3b9d2f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare
+
+// constexpr auto end() const;
+// constexpr iterator end() const requires same_as<W, Bound>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+template<class T, class U>
+constexpr void testType(U u) {
+  {
+    std::ranges::iota_view<T, U> io(T(0), u);
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+  }
+  {
+    std::ranges::iota_view<T, U> io(T(10), u);
+    assert(io.begin() == io.end());
+    assert(io.begin() == std::move(io).end());
+  }
+  {
+    const std::ranges::iota_view<T, U> io(T(0), u);
+    assert(std::ranges::next(io.begin(), 10) == io.end());
+    assert(std::ranges::next(io.begin(), 10) == std::move(io).end());
+  }
+  {
+    const std::ranges::iota_view<T, U> io(T(10), u);
+    assert(io.begin() == io.end());
+  }
+
+  {
+    std::ranges::iota_view<T> io(T(0), std::unreachable_sentinel);
+    assert(io.begin() != io.end());
+    assert(std::ranges::next(io.begin()) != io.end());
+    assert(std::ranges::next(io.begin(), 10) != io.end());
+  }
+  {
+    const std::ranges::iota_view<T> io(T(0), std::unreachable_sentinel);
+    assert(io.begin() != io.end());
+    assert(std::ranges::next(io.begin()) != io.end());
+    assert(std::ranges::next(io.begin(), 10) != io.end());
+  }
+}
+
+constexpr bool test() {
+  testType<SomeInt>(SomeInt(10));
+  testType<SomeInt>(IntComparableWith(SomeInt(10)));
+  testType<signed long>(IntComparableWith<signed long>(10));
+  testType<unsigned long>(IntComparableWith<unsigned long>(10));
+  testType<int>(IntComparableWith<int>(10));
+  testType<int>(int(10));
+  testType<int>(unsigned(10));
+  testType<unsigned>(unsigned(10));
+  testType<unsigned>(int(10));
+  testType<unsigned>(IntComparableWith<unsigned>(10));
+  testType<short>(short(10));
+  testType<short>(IntComparableWith<short>(10));
+  testType<unsigned short>(IntComparableWith<unsigned short>(10));
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp
new file mode 100644
index 0000000000000..6ef4751c64408
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// friend constexpr bool operator<(const iterator& x, const iterator& y)
+//   requires totally_ordered<W>;
+// friend constexpr bool operator>(const iterator& x, const iterator& y)
+//   requires totally_ordered<W>;
+// friend constexpr bool operator<=(const iterator& x, const iterator& y)
+//   requires totally_ordered<W>;
+// friend constexpr bool operator>=(const iterator& x, const iterator& y)
+//   requires totally_ordered<W>;
+// friend constexpr bool operator==(const iterator& x, const iterator& y)
+//   requires equality_comparable<W>;
+
+// TODO: test spaceship operator once it's implemented.
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  {
+    const std::ranges::iota_view<int> io(0);
+    assert(                  io.begin()  ==                   io.begin() );
+    assert(                  io.begin()  != std::ranges::next(io.begin()));
+    assert(                  io.begin()  <  std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >                    io.begin() );
+    assert(                  io.begin()  <= std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >=                   io.begin() );
+    assert(                  io.begin()  <=                   io.begin() );
+    assert(                  io.begin()  >=                   io.begin() );
+  }
+  {
+    std::ranges::iota_view<int> io(0);
+    assert(                  io.begin()  ==                   io.begin() );
+    assert(                  io.begin()  != std::ranges::next(io.begin()));
+    assert(                  io.begin()  <  std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >                    io.begin() );
+    assert(                  io.begin()  <= std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >=                   io.begin() );
+    assert(                  io.begin()  <=                   io.begin() );
+    assert(                  io.begin()  >=                   io.begin() );
+  }
+  {
+    const std::ranges::iota_view<SomeInt> io(SomeInt(0));
+    assert(                  io.begin()  ==                   io.begin() );
+    assert(                  io.begin()  != std::ranges::next(io.begin()));
+    assert(                  io.begin()  <  std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >                    io.begin() );
+    assert(                  io.begin()  <= std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >=                   io.begin() );
+    assert(                  io.begin()  <=                   io.begin() );
+    assert(                  io.begin()  >=                   io.begin() );
+  }
+  {
+    std::ranges::iota_view<SomeInt> io(SomeInt(0));
+    assert(                  io.begin()  ==                   io.begin() );
+    assert(                  io.begin()  != std::ranges::next(io.begin()));
+    assert(                  io.begin()  <  std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >                    io.begin() );
+    assert(                  io.begin()  <= std::ranges::next(io.begin()));
+    assert(std::ranges::next(io.begin()) >=                   io.begin() );
+    assert(                  io.begin()  <=                   io.begin() );
+    assert(                  io.begin()  >=                   io.begin() );
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..ac8075dba9143
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// iterator() requires default_initializable<W> = default;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  using Iter = std::ranges::iterator_t<std::ranges::iota_view<Int42<DefaultTo42>>>;
+  Iter iter;
+  assert((*iter).value_ == 42);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp
new file mode 100644
index 0000000000000..8395dde50df4f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr explicit iterator(W value);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  {
+    using Iter = std::ranges::iterator_t<std::ranges::iota_view<int>>;
+    auto iter = Iter(42);
+    assert(*iter == 42);
+  }
+  {
+    using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt>>;
+    auto iter = Iter(SomeInt(42));
+    assert(*iter == SomeInt(42));
+  }
+  {
+    using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt>>;
+    static_assert(!std::is_convertible_v<Iter, SomeInt>);
+    static_assert( std::is_constructible_v<Iter, SomeInt>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp
new file mode 100644
index 0000000000000..a17dc3f99f472
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iterator& operator--() requires decrementable<W>;
+// constexpr iterator operator--(int) requires decrementable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+template<class T>
+concept Decrementable =
+  requires(T i) {
+    --i;
+  } ||
+  requires(T i) {
+    i--;
+  };
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view<int> io(0);
+    auto iter1 = std::next(io.begin());
+    auto iter2 = std::next(io.begin());
+    assert(iter1 == iter2);
+    assert(--iter1 != iter2--);
+    assert(iter1 == iter2);
+
+    static_assert(!std::is_reference_v<decltype(iter2--)>);
+    static_assert( std::is_reference_v<decltype(--iter2)>);
+    static_assert(std::same_as<std::remove_reference_t<decltype(--iter2)>, decltype(iter2--)>);
+  }
+  {
+    std::ranges::iota_view io(SomeInt(0));
+    auto iter1 = std::next(io.begin());
+    auto iter2 = std::next(io.begin());
+    assert(iter1 == iter2);
+    assert(--iter1 != iter2--);
+    assert(iter1 == iter2);
+
+    static_assert(!std::is_reference_v<decltype(iter2--)>);
+    static_assert( std::is_reference_v<decltype(--iter2)>);
+    static_assert(std::same_as<std::remove_reference_t<decltype(--iter2)>, decltype(iter2--)>);
+  }
+
+  static_assert(!Decrementable<std::ranges::iota_view<NotDecrementable>>);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp
new file mode 100644
index 0000000000000..cbc143e20a0d6
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iterator& operator++();
+// constexpr void operator++(int);
+// constexpr iterator operator++(int) requires incrementable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  {
+    std::ranges::iota_view<int> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(++iter1 != iter2++);
+    assert(iter1 == iter2);
+
+    static_assert(!std::is_reference_v<decltype(iter2++)>);
+    static_assert( std::is_reference_v<decltype(++iter2)>);
+    static_assert(std::same_as<std::remove_reference_t<decltype(++iter2)>, decltype(iter2++)>);
+  }
+  {
+    std::ranges::iota_view io(SomeInt(0));
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(++iter1 != iter2++);
+    assert(iter1 == iter2);
+
+    static_assert(!std::is_reference_v<decltype(iter2++)>);
+    static_assert( std::is_reference_v<decltype(++iter2)>);
+    static_assert(std::same_as<std::remove_reference_t<decltype(++iter2)>, decltype(iter2++)>);
+  }
+
+  {
+    std::ranges::iota_view<NotIncrementable> io(NotIncrementable(0));
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(++iter1 != iter2);
+    iter2++;
+    assert(iter1 == iter2);
+
+    static_assert(std::same_as<decltype(iter2++), void>);
+    static_assert(std::is_reference_v<decltype(++iter2)>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp
new file mode 100644
index 0000000000000..26d6bafbe5eed
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp
@@ -0,0 +1,163 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// Test iterator category and iterator concepts.
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+struct Decrementable {
+  using 
diff erence_type = int;
+
+  auto operator<=>(const Decrementable&) const = default;
+
+  constexpr Decrementable& operator++();
+  constexpr Decrementable  operator++(int);
+  constexpr Decrementable& operator--();
+  constexpr Decrementable  operator--(int);
+};
+
+struct Incrementable {
+  using 
diff erence_type = int;
+
+  auto operator<=>(const Incrementable&) const = default;
+
+  constexpr Incrementable& operator++();
+  constexpr Incrementable  operator++(int);
+};
+
+struct BigType {
+  char buffer[128];
+
+  using 
diff erence_type = int;
+
+  auto operator<=>(const BigType&) const = default;
+
+  constexpr BigType& operator++();
+  constexpr BigType  operator++(int);
+};
+
+struct CharDifferenceType {
+  using 
diff erence_type = signed char;
+
+  auto operator<=>(const CharDifferenceType&) const = default;
+
+  constexpr CharDifferenceType& operator++();
+  constexpr CharDifferenceType  operator++(int);
+};
+
+template<class T>
+concept HasIteratorCategory = requires { typename std::ranges::iterator_t<T>::iterator_category; };
+
+void test() {
+  {
+    const std::ranges::iota_view<char> io(0);
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, char>);
+    static_assert(sizeof(Iter::
diff erence_type) > sizeof(char));
+    static_assert(std::is_signed_v<Iter::
diff erence_type>);
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<short> io(0);
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, short>);
+    static_assert(sizeof(Iter::
diff erence_type) > sizeof(short));
+    static_assert(std::is_signed_v<Iter::
diff erence_type>);
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<int> io(0);
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, int>);
+    static_assert(sizeof(Iter::
diff erence_type) > sizeof(int));
+    static_assert(std::is_signed_v<Iter::
diff erence_type>);
+    // If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct 
diff erence type.
+#if INTPTR_MAX == INT32_MAX || defined(_WIN32)
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, long long>);
+#else
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, long>);
+#endif
+  }
+  {
+    const std::ranges::iota_view<long> io(0);
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, long>);
+    // Same as below, if there is no type larger than long, we can just use that.
+    static_assert(sizeof(Iter::
diff erence_type) >= sizeof(long));
+    static_assert(std::is_signed_v<Iter::
diff erence_type>);
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, long long>);
+  }
+  {
+    const std::ranges::iota_view<long long> io(0);
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, long long>);
+    // No integer is larger than long long, so it is OK to use long long as the 
diff erence type here:
+    // https://eel.is/c++draft/range.iota.view#1.3
+    static_assert(sizeof(Iter::
diff erence_type) >= sizeof(long long));
+    static_assert(std::is_signed_v<Iter::
diff erence_type>);
+    LIBCPP_STATIC_ASSERT(std::same_as<Iter::
diff erence_type, long long>);
+  }
+  {
+    const std::ranges::iota_view<Decrementable> io;
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::bidirectional_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, Decrementable>);
+    static_assert(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<Incrementable> io;
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, Incrementable>);
+    static_assert(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<NotIncrementable> io(NotIncrementable(0));
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::input_iterator_tag>);
+    static_assert(!HasIteratorCategory<std::ranges::iota_view<NotIncrementable>>);
+    static_assert(std::same_as<Iter::value_type, NotIncrementable>);
+    static_assert(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<BigType> io;
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, BigType>);
+    static_assert(std::same_as<Iter::
diff erence_type, int>);
+  }
+  {
+    const std::ranges::iota_view<CharDifferenceType> io;
+    using Iter = decltype(io.begin());
+    static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
+    static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<Iter::value_type, CharDifferenceType>);
+    static_assert(std::same_as<Iter::
diff erence_type, signed char>);
+  }
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp
new file mode 100644
index 0000000000000..f4181801a948f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp
@@ -0,0 +1,179 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// friend constexpr iterator operator-(iterator i, 
diff erence_type n)
+//   requires advanceable<W>;
+// friend constexpr 
diff erence_type operator-(const iterator& x, const iterator& y)
+//   requires advanceable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+// If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct 
diff erence type.
+#if INTPTR_MAX == INT32_MAX || defined(_WIN32)
+using IntDiffT = long long;
+#else
+using IntDiffT = long;
+#endif
+
+constexpr bool test() {
+  // <iterator> - 
diff erence_type
+  {
+    // When "_Start" is signed integer like.
+    {
+      std::ranges::iota_view<int> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 == iter2);
+      assert(iter1 - 5 != iter2);
+      assert(iter1 - 5 == std::ranges::prev(iter2, 5));
+
+      static_assert(!std::is_reference_v<decltype(iter2 - 5)>);
+    }
+
+    // When "_Start" is not integer like.
+    {
+      std::ranges::iota_view io(SomeInt(0));
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 == iter2);
+      assert(iter1 - 5 != iter2);
+      assert(iter1 - 5 == std::ranges::prev(iter2, 5));
+
+      static_assert(!std::is_reference_v<decltype(iter2 - 5)>);
+    }
+
+    // When "_Start" is unsigned integer like and n is greater than or equal to zero.
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 == iter2);
+      assert(iter1 - 5 != iter2);
+      assert(iter1 - 5 == std::ranges::prev(iter2, 5));
+
+      static_assert(!std::is_reference_v<decltype(iter2 - 5)>);
+    }
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - 0 == iter2);
+    }
+
+    // When "_Start" is unsigned integer like and n is less than zero.
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - 5 != iter2);
+      assert(iter1 - 5 == std::ranges::prev(iter2, 5));
+
+      static_assert(!std::is_reference_v<decltype(iter2 - 5)>);
+    }
+  }
+
+  // <iterator> - <iterator>
+  {
+    // When "_Start" is signed integer like.
+    {
+      std::ranges::iota_view<int> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 5);
+      assert(iter1 - iter2 == 5);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+    {
+      std::ranges::iota_view<int> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == 0);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+    {
+      std::ranges::iota_view<int> io(0);
+      auto iter1 = std::next(io.begin(), 5);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == -5);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+
+    // When "_Start" is unsigned integer like and y > x.
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 5);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == -5);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+
+    // When "_Start" is unsigned integer like and x >= y.
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 5);
+      assert(iter1 - iter2 == 5);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+    {
+      std::ranges::iota_view<unsigned> io(0);
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == 0);
+
+      LIBCPP_STATIC_ASSERT(std::same_as<decltype(iter1 - iter2), IntDiffT>);
+    }
+
+    // When "_Start" is not integer like.
+    {
+      std::ranges::iota_view io(SomeInt(0));
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 5);
+      assert(iter1 - iter2 == 5);
+
+      static_assert(std::same_as<decltype(iter1 - iter2), int>);
+    }
+    {
+      std::ranges::iota_view io(SomeInt(0));
+      auto iter1 = std::next(io.begin(), 10);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == 0);
+
+      static_assert(std::same_as<decltype(iter1 - iter2), int>);
+    }
+    {
+      std::ranges::iota_view io(SomeInt(0));
+      auto iter1 = std::next(io.begin(), 5);
+      auto iter2 = std::next(io.begin(), 10);
+      assert(iter1 - iter2 == -5);
+
+      static_assert(std::same_as<decltype(iter1 - iter2), int>);
+    }
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp
new file mode 100644
index 0000000000000..6616ebbb0a2ae
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iterator& operator-=(
diff erence_type n)
+//   requires advanceable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  // When "_Start" is signed integer like.
+  {
+    std::ranges::iota_view<int> io(0);
+    auto iter1 = std::next(io.begin(), 10);
+    auto iter2 = std::next(io.begin(), 10);
+    assert(iter1 == iter2);
+    iter1 -= 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::prev(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 -= 5)>);
+  }
+
+  // When "_Start" is not integer like.
+  {
+    std::ranges::iota_view io(SomeInt(0));
+    auto iter1 = std::next(io.begin(), 10);
+    auto iter2 = std::next(io.begin(), 10);
+    assert(iter1 == iter2);
+    iter1 -= 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::prev(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 -= 5)>);
+  }
+
+  // When "_Start" is unsigned integer like and n is greater than or equal to zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = std::next(io.begin(), 10);
+    auto iter2 = std::next(io.begin(), 10);
+    assert(iter1 == iter2);
+    iter1 -= 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::prev(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 -= 5)>);
+  }
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = std::next(io.begin(), 10);
+    auto iter2 = std::next(io.begin(), 10);
+    assert(iter1 == iter2);
+    iter1 -= 0;
+    assert(iter1 == iter2);
+  }
+
+  // When "_Start" is unsigned integer like and n is less than zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = std::next(io.begin(), 10);
+    auto iter2 = std::next(io.begin(), 10);
+    assert(iter1 == iter2);
+    iter1 -= -5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 -= -5)>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp
new file mode 100644
index 0000000000000..b844900b3dd42
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// friend constexpr iterator operator+(iterator i, 
diff erence_type n)
+//   requires advanceable<W>;
+// friend constexpr iterator operator+(
diff erence_type n, iterator i)
+//   requires advanceable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  // When "_Start" is signed integer like.
+  {
+    std::ranges::iota_view<int> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(iter1 + 5 != iter2);
+    assert(iter1 + 5 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  // When "_Start" is not integer like.
+  {
+    std::ranges::iota_view io(SomeInt(0));
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(iter1 + 5 != iter2);
+    assert(iter1 + 5 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  // When "_Start" is unsigned integer like and n is greater than or equal to zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(iter1 + 5 != iter2);
+    assert(iter1 + 5 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(iter1 + 0 == iter2);
+  }
+
+  // When "_Start" is unsigned integer like and n is less than zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    assert(iter1 + 5 != iter2);
+    assert(iter1 + 5 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp
new file mode 100644
index 0000000000000..db3e6bdbcf287
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr iterator& operator+=(
diff erence_type n)
+//   requires advanceable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  // When "_Start" is signed integer like.
+  {
+    std::ranges::iota_view<int> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    iter1 += 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  // When "_Start" is not integer like.
+  {
+    std::ranges::iota_view io(SomeInt(0));
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    iter1 += 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  // When "_Start" is unsigned integer like and n is greater than or equal to zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    iter1 += 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    iter1 += 0;
+    assert(iter1 == iter2);
+  }
+
+  // When "_Start" is unsigned integer like and n is less than zero.
+  {
+    std::ranges::iota_view<unsigned> io(0);
+    auto iter1 = io.begin();
+    auto iter2 = io.begin();
+    assert(iter1 == iter2);
+    iter1 += 5;
+    assert(iter1 != iter2);
+    assert(iter1 == std::ranges::next(iter2, 5));
+
+    static_assert(std::is_reference_v<decltype(iter2 += 5)>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp
new file mode 100644
index 0000000000000..492d7333fa9a0
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare
+
+// constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v<W>);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+struct NotNoexceptCopy {
+  using 
diff erence_type = int;
+
+  int value_;
+  constexpr explicit NotNoexceptCopy(int value = 0) : value_(value) {}
+  NotNoexceptCopy(const NotNoexceptCopy&) noexcept(false) = default;
+
+  bool operator==(const NotNoexceptCopy&) const = default;
+
+  friend constexpr NotNoexceptCopy& operator+=(NotNoexceptCopy &lhs, const NotNoexceptCopy& rhs) {
+    lhs.value_ += rhs.value_; return lhs;
+  }
+  friend constexpr NotNoexceptCopy& operator-=(NotNoexceptCopy &lhs, const NotNoexceptCopy& rhs) {
+    lhs.value_ -= rhs.value_; return lhs;
+  }
+
+  friend constexpr NotNoexceptCopy operator+(NotNoexceptCopy lhs, NotNoexceptCopy rhs) {
+    return NotNoexceptCopy{lhs.value_ + rhs.value_};
+  }
+  friend constexpr int operator-(NotNoexceptCopy lhs, NotNoexceptCopy rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr NotNoexceptCopy& operator++()     { ++value_; return *this; }
+  constexpr void              operator++(int) { ++value_;               }
+};
+
+template<class T>
+constexpr void testType() {
+  {
+    std::ranges::iota_view<T> io(T(0));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i, ++iter)
+      assert(*iter == T(i));
+
+    static_assert(noexcept(*iter) == !std::same_as<T, NotNoexceptCopy>);
+  }
+  {
+    std::ranges::iota_view<T> io(T(10));
+    auto iter = io.begin();
+    for (int i = 10; i < 100; ++i, ++iter)
+      assert(*iter == T(i));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(0));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i, ++iter)
+      assert(*iter == T(i));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(10));
+    auto iter = io.begin();
+    for (int i = 10; i < 100; ++i, ++iter)
+      assert(*iter == T(i));
+  }
+}
+
+constexpr bool test() {
+  testType<SomeInt>();
+  testType<NotNoexceptCopy>();
+  testType<signed long>();
+  testType<unsigned long>();
+  testType<int>();
+  testType<unsigned>();
+  testType<short>();
+  testType<unsigned short>();
+
+  // Tests a mix of signed unsigned types.
+  {
+    const std::ranges::iota_view<int, unsigned> io(0, 10);
+    auto iter = io.begin();
+    for (int i = 0; i < 10; ++i, ++iter)
+      assert(*iter == i);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp
new file mode 100644
index 0000000000000..0fe4ea7048ca7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr W operator[](
diff erence_type n) const
+//   requires advanceable<W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+template<class T>
+constexpr void testType() {
+  {
+    std::ranges::iota_view<T> io(T(0));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i)
+      assert(iter[i] == T(i));
+  }
+  {
+    std::ranges::iota_view<T> io(T(10));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i)
+      assert(iter[i] == T(i + 10));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(0));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i)
+      assert(iter[i] == T(i));
+  }
+  {
+    const std::ranges::iota_view<T> io(T(10));
+    auto iter = io.begin();
+    for (int i = 0; i < 100; ++i)
+      assert(iter[i] == T(i + 10));
+  }
+}
+
+constexpr bool test() {
+  testType<SomeInt>();
+  testType<signed long>();
+  testType<unsigned long>();
+  testType<int>();
+  testType<unsigned>();
+  testType<short>();
+  testType<unsigned short>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp
new file mode 100644
index 0000000000000..b125f76de9e49
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// Test that iota_view conforms to range and view concepts.
+
+#include <ranges>
+
+#include "types.h"
+
+struct Decrementable {
+  using 
diff erence_type = int;
+
+  auto operator<=>(const Decrementable&) const = default;
+
+  constexpr Decrementable& operator++();
+  constexpr Decrementable  operator++(int);
+  constexpr Decrementable& operator--();
+  constexpr Decrementable  operator--(int);
+};
+
+struct Incrementable {
+  using 
diff erence_type = int;
+
+  auto operator<=>(const Incrementable&) const = default;
+
+  constexpr Incrementable& operator++();
+  constexpr Incrementable  operator++(int);
+};
+
+static_assert(std::ranges::random_access_range<std::ranges::iota_view<int>>);
+static_assert(std::ranges::random_access_range<const std::ranges::iota_view<int>>);
+static_assert(std::ranges::bidirectional_range<std::ranges::iota_view<Decrementable>>);
+static_assert(std::ranges::forward_range<std::ranges::iota_view<Incrementable>>);
+static_assert(std::ranges::input_range<std::ranges::iota_view<NotIncrementable>>);
+static_assert(std::ranges::view<std::ranges::iota_view<int>>);

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..0adb29cb46154
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// sentinel() = default;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  using Sent = std::ranges::sentinel_t<std::ranges::iota_view<Int42<DefaultTo42>, IntComparableWith<Int42<DefaultTo42>>>>;
+  using Iter = std::ranges::iterator_t<std::ranges::iota_view<Int42<DefaultTo42>, IntComparableWith<Int42<DefaultTo42>>>>;
+  assert(Sent() == Iter());
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp
new file mode 100644
index 0000000000000..ebb273873e2bc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr explicit sentinel(Bound bound);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  {
+    using Sent = std::ranges::sentinel_t<std::ranges::iota_view<int, IntSentinelWith<int>>>;
+    using Iter = std::ranges::iterator_t<std::ranges::iota_view<int, IntSentinelWith<int>>>;
+    auto sent = Sent(IntSentinelWith<int>(42));
+    assert(sent == Iter(42));
+  }
+  {
+    using Sent = std::ranges::sentinel_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
+    using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
+    auto sent = Sent(IntSentinelWith<SomeInt>(SomeInt(42)));
+    assert(sent == Iter(SomeInt(42)));
+  }
+  {
+    using Sent = std::ranges::sentinel_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
+    static_assert(!std::is_convertible_v<Sent, IntSentinelWith<SomeInt>>);
+    static_assert( std::is_constructible_v<Sent, IntSentinelWith<SomeInt>>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp
new file mode 100644
index 0000000000000..b4b9d01fabd1a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// friend constexpr bool operator==(const iterator& x, const sentinel& y);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "../types.h"
+
+constexpr bool test() {
+  {
+    const std::ranges::iota_view<int, IntComparableWith<int>> io(0, IntComparableWith<int>(10));
+    auto iter = io.begin();
+    auto sent = io.end();
+    assert(iter != sent);
+    assert(iter + 10 == sent);
+  }
+  {
+    std::ranges::iota_view<int, IntComparableWith<int>> io(0, IntComparableWith<int>(10));
+    auto iter = io.begin();
+    auto sent = io.end();
+    assert(iter != sent);
+    assert(iter + 10 == sent);
+  }
+  {
+    const std::ranges::iota_view io(SomeInt(0), IntComparableWith(SomeInt(10)));
+    auto iter = io.begin();
+    auto sent = io.end();
+    assert(iter != sent);
+    assert(iter + 10 == sent);
+  }
+  {
+    std::ranges::iota_view io(SomeInt(0), IntComparableWith(SomeInt(10)));
+    auto iter = io.begin();
+    auto sent = io.end();
+    assert(iter != sent);
+    assert(iter + 10 == sent);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp
new file mode 100644
index 0000000000000..6fd02878ca655
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// friend constexpr iter_
diff erence_t<W> operator-(const iterator& x, const sentinel& y)
+//   requires sized_­sentinel_­for<Bound, W>;
+// friend constexpr iter_
diff erence_t<W> operator-(const sentinel& x, const iterator& y)
+//   requires sized_­sentinel_­for<Bound, W>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "../types.h"
+
+template<class T>
+concept MinusInvocable = requires(std::ranges::iota_view<T, IntSentinelWith<T>> io) {
+  io.end() - io.begin();
+};
+
+constexpr bool test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto outIter = random_access_iterator<int*>(buffer);
+    std::ranges::iota_view<random_access_iterator<int*>, IntSentinelWith<random_access_iterator<int*>>> io(
+      outIter, IntSentinelWith<random_access_iterator<int*>>(std::ranges::next(outIter, 8)));
+    auto iter = io.begin();
+    auto sent = io.end();
+    assert(iter - sent == -8);
+    assert(sent - iter == 8);
+  }
+  {
+    auto outIter = random_access_iterator<int*>(buffer);
+    const std::ranges::iota_view<random_access_iterator<int*>, IntSentinelWith<random_access_iterator<int*>>> io(
+      outIter, IntSentinelWith<random_access_iterator<int*>>(std::ranges::next(outIter, 8)));
+    const auto iter = io.begin();
+    const auto sent = io.end();
+    assert(iter - sent == -8);
+    assert(sent - iter == 8);
+  }
+
+  {
+    // The minus operator requires that "W" is an input_or_output_iterator.
+    static_assert(!MinusInvocable<int>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp
new file mode 100644
index 0000000000000..4491b0f60eabe
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto size() const requires see below;
+
+#include <ranges>
+#include <cassert>
+#include <limits>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+  // Both are integer like and both are less than zero.
+  {
+    const std::ranges::iota_view<int, int> io(-10, -5);
+    assert(io.size() == 5);
+  }
+  {
+    const std::ranges::iota_view<int, int> io(-10, -10);
+    assert(io.size() == 0);
+  }
+
+  // Both are integer like and "value_" is less than zero.
+  {
+    const std::ranges::iota_view<int, int> io(-10, 10);
+    assert(io.size() == 20);
+  }
+  {
+// TODO: this is invalid with the current implementation. We need to file an LWG issue to
+// fix this. Essentially the issue is: An int's min and max are -2147483648 and 2147483647
+// which means the negated min cannot be represented as an integer; it needs to be cast to
+// an unsigned type first. That seems to be what the
+// to-unsigned-like(bound_) + to-unsigned-like(-value_))
+// part of https://eel.is/c++draft/range.iota#view-15 is doing, but I think it's doing it
+// wrong. It should be to-unsigned-like(bound_) - to-unsigned-like(value_)) (cast to
+// unsigned first).
+//     const std::ranges::iota_view<int, int> io(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
+//     assert(io.size() == (static_cast<unsigned>(std::numeric_limits<int>::max()) * 2) + 1);
+  }
+
+  // It is UB for "bound_" to be less than "value_" i.e.: iota_view<int, int> io(10, -5).
+
+  // Both are integer like and neither less than zero.
+  {
+    const std::ranges::iota_view<int, int> io(10, 20);
+    assert(io.size() == 10);
+  }
+  {
+    const std::ranges::iota_view<int, int> io(10, 10);
+    assert(io.size() == 0);
+  }
+  {
+    const std::ranges::iota_view<int, int> io(0, 0);
+    assert(io.size() == 0);
+  }
+  {
+    const std::ranges::iota_view<int, int> io(0, std::numeric_limits<int>::max());
+    assert(io.size() == std::numeric_limits<int>::max());
+  }
+
+  // Neither are integer like.
+  {
+    const std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(-20), SomeInt(-10));
+    assert(io.size() == 10);
+  }
+  {
+    const std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(-10), SomeInt(-10));
+    assert(io.size() == 0);
+  }
+  {
+    const std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(0), SomeInt(0));
+    assert(io.size() == 0);
+  }
+  {
+    const std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(10), SomeInt(20));
+    assert(io.size() == 10);
+  }
+  {
+    const std::ranges::iota_view<SomeInt, SomeInt> io(SomeInt(10), SomeInt(10));
+    assert(io.size() == 0);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp
new file mode 100644
index 0000000000000..73c4a349194a2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+#include <ranges>
+
+// Test that we SFINAE away iota_view<bool>.
+
+template<class T> std::ranges::iota_view<T> f(int);
+template<class T> void f(...);
+
+void test() {
+  f<bool>(42);
+}

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/types.h b/libcxx/test/std/ranges/range.factories/range.iota.view/types.h
new file mode 100644
index 0000000000000..a6eb1b4d537aa
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/types.h
@@ -0,0 +1,212 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H
+#define TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H
+
+#include "test_macros.h"
+
+struct SomeInt {
+  using 
diff erence_type = int;
+
+  int value_;
+  constexpr explicit SomeInt(int value = 0) : value_(value) {}
+
+  auto operator<=>(const SomeInt&) const = default;
+
+  friend constexpr SomeInt& operator+=(SomeInt &lhs, const SomeInt& rhs) {
+    lhs.value_ += rhs.value_; return lhs;
+  }
+  friend constexpr SomeInt& operator-=(SomeInt &lhs, const SomeInt& rhs) {
+    lhs.value_ -= rhs.value_; return lhs;
+  }
+
+  friend constexpr SomeInt& operator+=(SomeInt &lhs, 
diff erence_type rhs) {
+    lhs.value_ += rhs; return lhs;
+  }
+  friend constexpr SomeInt& operator-=(SomeInt &lhs, 
diff erence_type rhs) {
+    lhs.value_ -= rhs; return lhs;
+  }
+
+  friend constexpr SomeInt operator+(SomeInt lhs, SomeInt rhs) {
+    return SomeInt{lhs.value_ + rhs.value_};
+  }
+  friend constexpr int operator-(SomeInt lhs, SomeInt rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  friend constexpr SomeInt operator+(SomeInt lhs, 
diff erence_type rhs) {
+    return SomeInt{lhs.value_ + rhs};
+  }
+  friend constexpr int operator-(SomeInt lhs, 
diff erence_type rhs) {
+    return lhs.value_ - rhs;
+  }
+
+  friend constexpr SomeInt operator+(
diff erence_type lhs, SomeInt rhs) {
+    return SomeInt{lhs + rhs.value_};
+  }
+  friend constexpr int operator-(
diff erence_type lhs, SomeInt rhs) {
+    return lhs - rhs.value_;
+  }
+
+  constexpr SomeInt& operator++() { ++value_; return *this; }
+  constexpr SomeInt  operator++(int) { auto tmp = *this; ++value_; return tmp; }
+  constexpr SomeInt& operator--() { --value_; return *this; }
+  constexpr SomeInt  operator--(int) { auto tmp = *this; --value_; return tmp; }
+};
+
+template<class T>
+struct IntComparableWith {
+  using 
diff erence_type = std::iter_
diff erence_t<T>;
+
+  T value_;
+  constexpr explicit IntComparableWith(T value = T()) : value_(value) {}
+
+  friend constexpr bool operator==(IntComparableWith lhs, IntComparableWith rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+  friend constexpr bool operator==(IntComparableWith lhs, T rhs) {
+    return lhs.value_ == rhs;
+  }
+  friend constexpr bool operator==(T lhs, IntComparableWith rhs) {
+    return lhs == rhs.value_;
+  }
+
+  friend constexpr IntComparableWith operator+(IntComparableWith lhs, IntComparableWith rhs) {
+    return IntComparableWith{lhs.value_ + rhs.value_};
+  }
+  friend constexpr 
diff erence_type operator-(IntComparableWith lhs, IntComparableWith rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr IntComparableWith& operator++() { ++value_; return *this; }
+  constexpr IntComparableWith  operator++(int) { auto tmp = *this; ++value_; return tmp; }
+  constexpr IntComparableWith  operator--() { --value_; return *this; }
+};
+
+template<class T>
+struct IntSentinelWith {
+  using 
diff erence_type = std::iter_
diff erence_t<T>;
+
+  T value_;
+  constexpr explicit IntSentinelWith(T value = T()) : value_(value) {}
+
+  friend constexpr bool operator==(IntSentinelWith lhs, IntSentinelWith rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+  friend constexpr bool operator==(IntSentinelWith lhs, T rhs) {
+    return lhs.value_ == rhs;
+  }
+  friend constexpr bool operator==(T lhs, IntSentinelWith rhs) {
+    return lhs == rhs.value_;
+  }
+
+  friend constexpr IntSentinelWith operator+(IntSentinelWith lhs, IntSentinelWith rhs) {
+    return IntSentinelWith{lhs.value_ + rhs.value_};
+  }
+  friend constexpr 
diff erence_type operator-(IntSentinelWith lhs, IntSentinelWith rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+  friend constexpr 
diff erence_type operator-(IntSentinelWith lhs, T rhs) {
+    return lhs.value_ - rhs;
+  }
+  friend constexpr 
diff erence_type operator-(T lhs, IntSentinelWith rhs) {
+    return lhs - rhs.value_;
+  }
+
+  constexpr IntSentinelWith& operator++() { ++value_; return *this; }
+  constexpr IntSentinelWith  operator++(int) { auto tmp = *this; ++value_; return tmp; }
+  constexpr IntSentinelWith  operator--() { --value_; return *this; }
+};
+
+struct NotIncrementable {
+  using 
diff erence_type = int;
+
+  int value_;
+  constexpr explicit NotIncrementable(int value = 0) : value_(value) {}
+
+  bool operator==(const NotIncrementable&) const = default;
+
+  friend constexpr NotIncrementable& operator+=(NotIncrementable &lhs, const NotIncrementable& rhs) {
+    lhs.value_ += rhs.value_; return lhs;
+  }
+  friend constexpr NotIncrementable& operator-=(NotIncrementable &lhs, const NotIncrementable& rhs) {
+    lhs.value_ -= rhs.value_; return lhs;
+  }
+
+  friend constexpr NotIncrementable operator+(NotIncrementable lhs, NotIncrementable rhs) {
+    return NotIncrementable{lhs.value_ + rhs.value_};
+  }
+  friend constexpr int operator-(NotIncrementable lhs, NotIncrementable rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr NotIncrementable& operator++()    { ++value_; return *this; }
+  constexpr void              operator++(int) { ++value_;               }
+  constexpr NotIncrementable& operator--()    { --value_; return *this; }
+};
+static_assert(!std::incrementable<NotIncrementable>);
+
+struct NotDecrementable {
+  using 
diff erence_type = int;
+
+  int value_;
+  constexpr explicit NotDecrementable(int value = 0) : value_(value) {}
+
+  bool operator==(const NotDecrementable&) const = default;
+
+  friend constexpr NotDecrementable& operator+=(NotDecrementable &lhs, const NotDecrementable& rhs) {
+    lhs.value_ += rhs.value_; return lhs;
+  }
+  friend constexpr NotDecrementable& operator-=(NotDecrementable &lhs, const NotDecrementable& rhs) {
+    lhs.value_ -= rhs.value_; return lhs;
+  }
+
+  friend constexpr NotDecrementable operator+(NotDecrementable lhs, NotDecrementable rhs) {
+    return NotDecrementable{lhs.value_ + rhs.value_};
+  }
+  friend constexpr int operator-(NotDecrementable lhs, NotDecrementable rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr NotDecrementable& operator++()    { ++value_; return *this; }
+  constexpr void              operator++(int) { ++value_;               }
+};
+
+enum CtorKind { DefaultTo42, ValueCtor };
+
+template<CtorKind CK>
+struct Int42 {
+  using 
diff erence_type = int;
+
+  int value_;
+  constexpr explicit Int42(int value) : value_(value) {}
+  constexpr explicit Int42() requires (CK == DefaultTo42)
+    : value_(42) {}
+
+  bool operator==(const Int42&) const = default;
+
+  friend constexpr Int42& operator+=(Int42 &lhs, const Int42& rhs) {
+    lhs.value_ += rhs.value_; return lhs;
+  }
+  friend constexpr Int42& operator-=(Int42 &lhs, const Int42& rhs) {
+    lhs.value_ -= rhs.value_; return lhs;
+  }
+
+  friend constexpr Int42 operator+(Int42 lhs, Int42 rhs) {
+    return Int42{lhs.value_ + rhs.value_};
+  }
+  friend constexpr int operator-(Int42 lhs, Int42 rhs) {
+    return lhs.value_ - rhs.value_;
+  }
+
+  constexpr Int42& operator++()    { ++value_; return *this; }
+  constexpr void   operator++(int) { ++value_;               }
+};
+
+#endif // TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H

diff  --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
new file mode 100644
index 0000000000000..661285585095c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// views::iota
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+#include "types.h"
+
+template<class T, class U>
+constexpr void testType(U u) {
+  // Test that this generally does the right thing.
+  // Test with only one argument.
+  {
+    assert(*std::views::iota(T(0)).begin() == T(0));
+  }
+  {
+    const auto io = std::views::iota(T(10));
+    assert(*io.begin() == T(10));
+  }
+  // Test with two arguments.
+  {
+    assert(*std::views::iota(T(0), u).begin() == T(0));
+  }
+  {
+    const auto io = std::views::iota(T(10), u);
+    assert(*io.begin() == T(10));
+  }
+  // Test that we return the correct type.
+  {
+    ASSERT_SAME_TYPE(decltype(std::views::iota(T(10))), std::ranges::iota_view<T>);
+    ASSERT_SAME_TYPE(decltype(std::views::iota(T(10), u)), std::ranges::iota_view<T, U>);
+  }
+  // Test that this is semiregular.
+  // Note: we cannot test perfect forwarding because both T and U must be copyable.
+  {
+    static_assert(std::semiregular<std::remove_const_t<decltype(std::views::iota)>>);
+  }
+}
+
+struct X {};
+
+constexpr bool test() {
+  testType<SomeInt>(SomeInt(10));
+  testType<SomeInt>(IntComparableWith(SomeInt(10)));
+  testType<signed long>(IntComparableWith<signed long>(10));
+  testType<unsigned long>(IntComparableWith<unsigned long>(10));
+  testType<int>(IntComparableWith<int>(10));
+  testType<int>(int(10));
+  testType<unsigned>(unsigned(10));
+  testType<unsigned>(IntComparableWith<unsigned>(10));
+  testType<short>(short(10));
+  testType<short>(IntComparableWith<short>(10));
+  testType<unsigned short>(IntComparableWith<unsigned short>(10));
+
+  {
+    static_assert( std::is_invocable_v<decltype(std::views::iota), int>);
+    static_assert(!std::is_invocable_v<decltype(std::views::iota), X>);
+    static_assert( std::is_invocable_v<decltype(std::views::iota), int, int>);
+    static_assert(!std::is_invocable_v<decltype(std::views::iota), int, X>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}


        


More information about the libcxx-commits mailing list