[libcxx-commits] [libcxx] a2160dd - [libc++][ranges] Implement P2474R2(`views::repeat`).
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jul 20 05:03:11 PDT 2023
Author: yrong
Date: 2023-07-20T20:03:01+08:00
New Revision: a2160dd34d56ea5440cbb805657bfee0e2228073
URL: https://github.com/llvm/llvm-project/commit/a2160dd34d56ea5440cbb805657bfee0e2228073
DIFF: https://github.com/llvm/llvm-project/commit/a2160dd34d56ea5440cbb805657bfee0e2228073.diff
LOG: [libc++][ranges] Implement P2474R2(`views::repeat`).
- Implement https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2474r2.html
- Implement LWG3875(https://cplusplus.github.io/LWG/issue3875).
Depends on D151629
Reviewed By: #libc, Mordante, philnik, var-const
Differential Revision: https://reviews.llvm.org/D141699
Added:
libcxx/include/__ranges/repeat_view.h
libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/begin.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp
libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/ReleaseNotes/17.rst
libcxx/docs/Status/Cxx23Issues.csv
libcxx/docs/Status/Cxx23Papers.csv
libcxx/docs/Status/RangesViews.csv
libcxx/include/CMakeLists.txt
libcxx/include/__ranges/drop_view.h
libcxx/include/__ranges/take_view.h
libcxx/include/module.modulemap.in
libcxx/include/ranges
libcxx/include/version
libcxx/modules/std/ranges.cppm
libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 14a251ad5fef62..79c14e08b40fff 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -352,6 +352,8 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_ranges_join_with`` *unimplemented*
--------------------------------------------------- -----------------
+ ``__cpp_lib_ranges_repeat`` ``202207L``
+ --------------------------------------------------- -----------------
``__cpp_lib_ranges_slide`` *unimplemented*
--------------------------------------------------- -----------------
``__cpp_lib_ranges_starts_ends_with`` *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/17.rst b/libcxx/docs/ReleaseNotes/17.rst
index f5b568fa4ef479..f59d597a51e32b 100644
--- a/libcxx/docs/ReleaseNotes/17.rst
+++ b/libcxx/docs/ReleaseNotes/17.rst
@@ -67,7 +67,7 @@ Implemented Papers
- P2494R2 - Relaxing range adaptors to allow for move only types
- P2585R0 - Improving default container formatting
- P0408R7 - Efficient Access to ``basic_stringbuf``'s Buffer
-
+- P2474R2 - ``views::repeat``
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index aa7b69b569b572..0324c0f4ced422 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -299,7 +299,7 @@
"`3870 <https://wg21.link/LWG3870>`__","Remove ``voidify``","February 2023","","",""
"`3871 <https://wg21.link/LWG3871>`__","Adjust note about ``terminate``","February 2023","","",""
"`3872 <https://wg21.link/LWG3872>`__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","","",""
-"`3875 <https://wg21.link/LWG3875>`__","``std::ranges::repeat_view<T, IntegerClass>::iterator`` may be ill-formed","February 2023","","","|ranges|"
+"`3875 <https://wg21.link/LWG3875>`__","``std::ranges::repeat_view<T, IntegerClass>::iterator`` may be ill-formed","February 2023","|Complete|","17.0","|ranges|"
"`3876 <https://wg21.link/LWG3876>`__","Default constructor of ``std::layout_XX::mapping`` misses precondition","February 2023","","",""
"`3877 <https://wg21.link/LWG3877>`__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","|Complete|","17.0",""
"`3878 <https://wg21.link/LWG3878>`__","import ``std;`` should guarantee initialization of standard iostreams objects","February 2023","","",""
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index c8a8c9f4d7f76d..b8ea09637e0191 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -77,7 +77,7 @@
"`P2460R2 <https://wg21.link/P2460R2>`__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","",""
"`P2465R3 <https://wg21.link/P2465R3>`__","LWG","Standard Library Modules ``std`` and ``std.compat``","July 2022","",""
"`P2467R1 <https://wg21.link/P2467R1>`__","LWG","Support exclusive mode for ``fstreams``","July 2022","",""
-"`P2474R2 <https://wg21.link/P2474R2>`__","LWG","``views::repeat``","July 2022","","","|ranges|"
+"`P2474R2 <https://wg21.link/P2474R2>`__","LWG","``views::repeat``","July 2022","|Complete|","17.0","|ranges|"
"`P2494R2 <https://wg21.link/P2494R2>`__","LWG","Relaxing range adaptors to allow for move only types","July 2022","|Complete|","17.0","|ranges|"
"`P2499R0 <https://wg21.link/P2499R0>`__","LWG","``string_view`` range constructor should be ``explicit``","July 2022","|Complete|","16.0","|ranges|"
"`P2502R2 <https://wg21.link/P2502R2>`__","LWG","``std::generator``: Synchronous Coroutine Generator for Ranges","July 2022","","","|ranges|"
diff --git a/libcxx/docs/Status/RangesViews.csv b/libcxx/docs/Status/RangesViews.csv
index b07103e4a5726a..73769de4bfb543 100644
--- a/libcxx/docs/Status/RangesViews.csv
+++ b/libcxx/docs/Status/RangesViews.csv
@@ -22,7 +22,7 @@ C++20,`istream <https://wg21.link/P1035R7>`_,Hui Xie,`D133317 <https://llvm.org/
,,,,
,,,,
,,,,
-C++23,`repeat <https://wg21.link/P2474R2>`_,Unassigned,No patch yet,Not started
+C++23,`repeat <https://wg21.link/P2474R2>`_,Yrong,`D141699 <https://llvm.org/D141699>`_,✅
C++23,`cartesian_product <https://wg21.link/P2374R4>`_,Unassigned,No patch yet,Not started
C++23,`zip <https://wg21.link/P2321R2>`_,Hui Xie,`D122806 <https://llvm.org/D122806>`_,✅
C++23,`zip_transform <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not started
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cfb367e3a4a480..b7c15a27128523 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -637,6 +637,7 @@ set(files
__ranges/rbegin.h
__ranges/ref_view.h
__ranges/rend.h
+ __ranges/repeat_view.h
__ranges/reverse_view.h
__ranges/single_view.h
__ranges/size.h
diff --git a/libcxx/include/__ranges/drop_view.h b/libcxx/include/__ranges/drop_view.h
index cdf00cadeea940..f10476f0011e73 100644
--- a/libcxx/include/__ranges/drop_view.h
+++ b/libcxx/include/__ranges/drop_view.h
@@ -30,6 +30,7 @@
#include <__ranges/iota_view.h>
#include <__ranges/non_propagating_cache.h>
#include <__ranges/range_adaptor.h>
+#include <__ranges/repeat_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__ranges/view_interface.h>
@@ -267,6 +268,32 @@ struct __fn {
ranges::end(__rng),
std::__to_unsigned_like(__dist - __clamped)
);}
+// clang-format off
+#if _LIBCPP_STD_VER >= 23
+ // [range.drop.overview]: the `repeat_view` "_RawRange models sized_range" case.
+ template <class _Range,
+ convertible_to<range_
diff erence_t<_Range>> _Np,
+ class _RawRange = remove_cvref_t<_Range>,
+ class _Dist = range_
diff erence_t<_Range>>
+ requires (__is_repeat_specialization<_RawRange> && sized_range<_RawRange>)
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const
+ noexcept(noexcept(views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n)))))
+ -> decltype( views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))))
+ { return views::repeat(*__range.__value_, ranges::distance(__range) - std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))); }
+
+ // [range.drop.overview]: the `repeat_view` "otherwise" case.
+ template <class _Range,
+ convertible_to<range_
diff erence_t<_Range>> _Np,
+ class _RawRange = remove_cvref_t<_Range>,
+ class _Dist = range_
diff erence_t<_Range>>
+ requires (__is_repeat_specialization<_RawRange> && !sized_range<_RawRange>)
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI
+ constexpr auto operator()(_Range&& __range, _Np&&) const
+ noexcept(noexcept(_LIBCPP_AUTO_CAST(std::forward<_Range>(__range))))
+ -> decltype( _LIBCPP_AUTO_CAST(std::forward<_Range>(__range)))
+ { return _LIBCPP_AUTO_CAST(std::forward<_Range>(__range)); }
+#endif
+// clang-format on
// [range.drop.overview]: the "otherwise" case.
template <class _Range, convertible_to<range_
diff erence_t<_Range>> _Np,
@@ -274,6 +301,9 @@ struct __fn {
// Note: without specifically excluding the other cases, GCC sees this overload as ambiguous with the other
// overloads.
requires (!(__is_empty_view<_RawRange> ||
+#if _LIBCPP_STD_VER >= 23
+ __is_repeat_specialization<_RawRange> ||
+#endif
(__is_subrange_specialization_with_store_size<_RawRange> &&
sized_range<_RawRange> &&
random_access_range<_RawRange>) ||
diff --git a/libcxx/include/__ranges/repeat_view.h b/libcxx/include/__ranges/repeat_view.h
new file mode 100644
index 00000000000000..fddf4baac89a08
--- /dev/null
+++ b/libcxx/include/__ranges/repeat_view.h
@@ -0,0 +1,260 @@
+// -*- 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_REPEAT_VIEW_H
+#define _LIBCPP___RANGES_REPEAT_VIEW_H
+
+#include <__concepts/constructible.h>
+#include <__concepts/same_as.h>
+#include <__concepts/semiregular.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/unreachable_sentinel.h>
+#include <__memory/addressof.h>
+#include <__ranges/iota_view.h>
+#include <__ranges/movable_box.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/is_object.h>
+#include <__type_traits/make_unsigned.h>
+#include <__type_traits/remove_cv.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+#include <__utility/move.h>
+#include <__utility/piecewise_construct.h>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <class _Tp>
+concept __integer_like_with_usable_
diff erence_type =
+ __signed_integer_like<_Tp> || (__integer_like<_Tp> && weakly_incrementable<_Tp>);
+
+template <class _Tp>
+struct __repeat_view_iterator_
diff erence {
+ using type = _IotaDiffT<_Tp>;
+};
+
+template <__signed_integer_like _Tp>
+struct __repeat_view_iterator_
diff erence<_Tp> {
+ using type = _Tp;
+};
+
+template <class _Tp>
+using __repeat_view_iterator_
diff erence_t = typename __repeat_view_iterator_
diff erence<_Tp>::type;
+
+namespace views::__drop {
+struct __fn;
+} // namespace views::__drop
+
+namespace views::__take {
+struct __fn;
+} // namespace views::__take
+
+template <move_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
+ requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> &&
+ (__integer_like_with_usable_
diff erence_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>))
+class repeat_view : public view_interface<repeat_view<_Tp, _Bound>> {
+ friend struct views::__take::__fn;
+ friend struct views::__drop::__fn;
+ class __iterator;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI repeat_view()
+ requires default_initializable<_Tp>
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(const _Tp& __value, _Bound __bound_sentinel = _Bound())
+ requires copy_constructible<_Tp>
+ : __value_(in_place, __value), __bound_(__bound_sentinel) {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(__bound_ >= 0, "The value of bound must be greater than or equal to 0");
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(_Tp&& __value, _Bound __bound_sentinel = _Bound())
+ : __value_(in_place, std::move(__value)), __bound_(__bound_sentinel) {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(__bound_ >= 0, "The value of bound must be greater than or equal to 0");
+ }
+
+ template <class... _TpArgs, class... _BoundArgs>
+ requires(constructible_from<_Tp, _TpArgs...> && constructible_from<_Bound, _BoundArgs...>)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit repeat_view(
+ piecewise_construct_t, tuple<_TpArgs...> __value_args, tuple<_BoundArgs...> __bound_args = tuple<>{})
+ : __value_(in_place, std::make_from_tuple<_Tp>(std::move(__value_args))),
+ __bound_(std::make_from_tuple<_Bound>(std::move(__bound_args))) {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(
+ __bound_ >= 0, "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative");
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator(std::addressof(*__value_)); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const
+ requires(!same_as<_Bound, unreachable_sentinel_t>)
+ {
+ return __iterator(std::addressof(*__value_), __bound_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr unreachable_sentinel_t end() const noexcept { return unreachable_sentinel; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ requires(!same_as<_Bound, unreachable_sentinel_t>)
+ {
+ return std::__to_unsigned_like(__bound_);
+ }
+
+private:
+ __movable_box<_Tp> __value_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Bound __bound_ = _Bound();
+};
+
+template <class _Tp, class _Bound>
+repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
+
+// [range.repeat.iterator]
+template <move_constructible _Tp, semiregular _Bound>
+ requires(is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> &&
+ (__integer_like_with_usable_
diff erence_type<_Bound> || same_as<_Bound, unreachable_sentinel_t>))
+class repeat_view<_Tp, _Bound>::__iterator {
+ friend class repeat_view;
+
+ using _IndexT = conditional_t<same_as<_Bound, unreachable_sentinel_t>, ptr
diff _t, _Bound>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(const _Tp* __value, _IndexT __bound_sentinel = _IndexT())
+ : __value_(__value), __current_(__bound_sentinel) {}
+
+public:
+ using iterator_concept = random_access_iterator_tag;
+ using iterator_category = random_access_iterator_tag;
+ using value_type = _Tp;
+ using
diff erence_type = __repeat_view_iterator_
diff erence_t<_IndexT>;
+
+ _LIBCPP_HIDE_FROM_ABI __iterator() = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const noexcept { return *__value_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ ++__current_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
+ auto __tmp = *this;
+ ++*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(__current_ > 0, "The value of bound must be greater than or equal to 0");
+ --__current_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) {
+ auto __tmp = *this;
+ --*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(
diff erence_type __n) {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(__current_ + __n >= 0, "The value of bound must be greater than or equal to 0");
+ __current_ += __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(
diff erence_type __n) {
+ if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
+ _LIBCPP_ASSERT(__current_ - __n >= 0, "The value of bound must be greater than or equal to 0");
+ __current_ -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](
diff erence_type __n) const noexcept { return *(*this + __n); }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
+ return __x.__current_ == __y.__current_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) {
+ return __x.__current_ <=> __y.__current_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i,
diff erence_type __n) {
+ __i += __n;
+ return __i;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(
diff erence_type __n, __iterator __i) {
+ __i += __n;
+ return __i;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i,
diff erence_type __n) {
+ __i -= __n;
+ return __i;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr
diff erence_type operator-(const __iterator& __x, const __iterator& __y) {
+ return static_cast<
diff erence_type>(__x.__current_) - static_cast<
diff erence_type>(__y.__current_);
+ }
+
+private:
+ const _Tp* __value_ = nullptr;
+ _IndexT __current_ = _IndexT();
+};
+
+// clang-format off
+namespace views {
+namespace __repeat {
+struct __fn {
+ template <class _Tp>
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value) const
+ noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value))))
+ -> decltype( ranges::repeat_view(std::forward<_Tp>(__value)))
+ { return ranges::repeat_view(std::forward<_Tp>(__value)); }
+
+
+ template <class _Tp, class _Bound>
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel) const
+ noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel))))
+ -> decltype( ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)))
+ { return ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)); }
+};
+} // namespace __repeat
+// clang-format on
+
+inline namespace __cpo {
+inline constexpr auto repeat = __repeat::__fn{};
+} // namespace __cpo
+} // namespace views
+
+template <class _Tp>
+inline constexpr bool __is_repeat_specialization = false;
+
+template <class _Tp, class _Bound>
+inline constexpr bool __is_repeat_specialization<repeat_view<_Tp, _Bound>> = true;
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_REPEAT_VIEW_H
diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h
index 34978a7da8da1e..4204017d9249bc 100644
--- a/libcxx/include/__ranges/take_view.h
+++ b/libcxx/include/__ranges/take_view.h
@@ -31,6 +31,7 @@
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/iota_view.h>
#include <__ranges/range_adaptor.h>
+#include <__ranges/repeat_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__ranges/view_interface.h>
@@ -301,6 +302,31 @@ struct __fn {
*ranges::begin(__rng),
*ranges::begin(__rng) + std::min<_Dist>(ranges::distance(__rng), std::forward<_Np>(__n))
); }
+// clang-format off
+#if _LIBCPP_STD_VER >= 23
+ // [range.take.overview]: the `repeat_view` "_RawRange models sized_range" case.
+ template <class _Range,
+ convertible_to<range_
diff erence_t<_Range>> _Np,
+ class _RawRange = remove_cvref_t<_Range>,
+ class _Dist = range_
diff erence_t<_Range>>
+ requires(__is_repeat_specialization<_RawRange> && sized_range<_RawRange>)
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const
+ noexcept(noexcept(views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n)))))
+ -> decltype( views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))))
+ { return views::repeat(*__range.__value_, std::min<_Dist>(ranges::distance(__range), std::forward<_Np>(__n))); }
+
+ // [range.take.overview]: the `repeat_view` "otherwise" case.
+ template <class _Range,
+ convertible_to<range_
diff erence_t<_Range>> _Np,
+ class _RawRange = remove_cvref_t<_Range>,
+ class _Dist = range_
diff erence_t<_Range>>
+ requires(__is_repeat_specialization<_RawRange> && !sized_range<_RawRange>)
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Np&& __n) const
+ noexcept(noexcept(views::repeat(*__range.__value_, static_cast<_Dist>(__n))))
+ -> decltype( views::repeat(*__range.__value_, static_cast<_Dist>(__n)))
+ { return views::repeat(*__range.__value_, static_cast<_Dist>(__n)); }
+#endif
+// clang-format on
// [range.take.overview]: the "otherwise" case.
template <class _Range, convertible_to<range_
diff erence_t<_Range>> _Np,
@@ -308,6 +334,9 @@ struct __fn {
// Note: without specifically excluding the other cases, GCC sees this overload as ambiguous with the other
// overloads.
requires (!(__is_empty_view<_RawRange> ||
+#if _LIBCPP_STD_VER >= 23
+ __is_repeat_specialization<_RawRange> ||
+#endif
(__is_iota_specialization<_RawRange> &&
sized_range<_RawRange> &&
random_access_range<_RawRange>) ||
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 88de19855451fa..cfc53e5b4ba3bf 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1481,6 +1481,7 @@ module std [system] {
module rbegin { private header "__ranges/rbegin.h" }
module ref_view { private header "__ranges/ref_view.h" }
module rend { private header "__ranges/rend.h" }
+ module repeat_view { private header "__ranges/repeat_view.h" }
module reverse_view { private header "__ranges/reverse_view.h" }
module single_view { private header "__ranges/single_view.h" }
module size {
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index bcf05f55f5edbd..3bf9814e958769 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -252,6 +252,19 @@ namespace std::ranges {
template<class W, class Bound>
inline constexpr bool enable_borrowed_range<iota_view<W, Bound>> = true;
+ // [range.repeat], repeat view
+ template<class T>
+ concept integer-like-with-usable-
diff erence-type = // exposition only
+ is-signed-integer-like<T> || (is-integer-like<T> && weakly_incrementable<T>);
+
+ template<move_constructible T, semiregular Bound = unreachable_sentinel_t>
+ requires (is_object_v<T> && same_as<T, remove_cv_t<T>> &&
+ (integer-like-with-usable-
diff erence-type<Bound> ||
+ same_as<Bound, unreachable_sentinel_t>))
+ class repeat_view;
+
+ namespace views { inline constexpr unspecified repeat = unspecified; }
+
// [range.join], join view
template<input_range V>
requires view<V> && input_range<range_reference_t<V>>
@@ -370,6 +383,7 @@ namespace std {
#include <__ranges/rbegin.h>
#include <__ranges/ref_view.h>
#include <__ranges/rend.h>
+#include <__ranges/repeat_view.h>
#include <__ranges/reverse_view.h>
#include <__ranges/single_view.h>
#include <__ranges/size.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index 6f588c82b45b77..87b792467fcebd 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -158,6 +158,7 @@ __cpp_lib_ranges_chunk 202202L <ranges>
__cpp_lib_ranges_chunk_by 202202L <ranges>
__cpp_lib_ranges_iota 202202L <numeric>
__cpp_lib_ranges_join_with 202202L <ranges>
+__cpp_lib_ranges_repeat 202207L <ranges>
__cpp_lib_ranges_slide 202202L <ranges>
__cpp_lib_ranges_starts_ends_with 202106L <algorithm>
__cpp_lib_ranges_to_container 202202L <deque> <forward_list> <list>
@@ -436,6 +437,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_ranges_chunk_by 202202L
// # define __cpp_lib_ranges_iota 202202L
// # define __cpp_lib_ranges_join_with 202202L
+# define __cpp_lib_ranges_repeat 202207L
// # define __cpp_lib_ranges_slide 202202L
// # define __cpp_lib_ranges_starts_ends_with 202106L
// # define __cpp_lib_ranges_to_container 202202L
diff --git a/libcxx/modules/std/ranges.cppm b/libcxx/modules/std/ranges.cppm
index c6b000a10314c3..7e4c5435ea11c3 100644
--- a/libcxx/modules/std/ranges.cppm
+++ b/libcxx/modules/std/ranges.cppm
@@ -119,13 +119,12 @@ export namespace std {
} // namespace views
// [range.repeat], repeat view
-#if 0
using std::ranges::repeat_view;
namespace views {
using std::ranges::views::repeat;
} // namespace views
-#endif
+
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
// [range.istream], istream view
using std::ranges::basic_istream_view;
diff --git a/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
new file mode 100644
index 00000000000000..b63a0dc2d86543
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// REQUIRES: has-unix-headers
+// XFAIL: availability-verbose_abort-missing
+
+// template<class... TArgs, class... BoundArgs>
+// requires constructible_from<T, TArgs...> &&
+// constructible_from<Bound, BoundArgs...>
+// constexpr explicit repeat_view(piecewise_construct_t,
+// tuple<TArgs...> value_args, tuple<BoundArgs...> bound_args = tuple<>{});
+
+#include <ranges>
+#include <tuple>
+
+#include "check_assertion.h"
+
+// clang-format off
+int main(int, char**) {
+ using Repeat = std::ranges::repeat_view<int, int>;
+ TEST_LIBCPP_ASSERT_FAILURE(Repeat(std::piecewise_construct, std::tuple{1}, std::tuple{-1}), "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative");
+
+ return 0;
+}
+// clang-format on
diff --git a/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
new file mode 100644
index 00000000000000..7f50bff13f225f
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// REQUIRES: has-unix-headers
+// XFAIL: availability-verbose_abort-missing
+
+// constexpr explicit repeat_view(W&& value, Bound bound = Bound());
+// constexpr explicit repeat_view(const W& value, Bound bound = Bound());
+
+#include <ranges>
+
+#include "check_assertion.h"
+
+// clang-format off
+int main(int, char**) {
+ TEST_LIBCPP_ASSERT_FAILURE(std::ranges::repeat_view(0, -1), "The value of bound must be greater than or equal to 0");
+ const int val = 0;
+ TEST_LIBCPP_ASSERT_FAILURE(std::ranges::repeat_view(val, -1), "The value of bound must be greater than or equal to 0");
+
+ return 0;
+}
+// clang-format on
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index 7a1edd1798eeb1..3758c53bd34613 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -21,6 +21,7 @@
__cpp_lib_ranges_chunk 202202L [C++23]
__cpp_lib_ranges_chunk_by 202202L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
+ __cpp_lib_ranges_repeat 202207L [C++23]
__cpp_lib_ranges_slide 202202L [C++23]
__cpp_lib_ranges_zip 202110L [C++23]
*/
@@ -50,6 +51,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -80,6 +85,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -110,6 +119,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -143,6 +156,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -206,6 +223,13 @@
# endif
# endif
+# ifndef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_repeat != 202207L
+# error "__cpp_lib_ranges_repeat should have the value 202207L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should be defined in c++23"
@@ -287,6 +311,13 @@
# endif
# endif
+# ifndef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_repeat != 202207L
+# error "__cpp_lib_ranges_repeat should have the value 202207L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should be defined in c++26"
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 75991c25955442..94d28382049898 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -146,6 +146,7 @@
__cpp_lib_ranges_chunk_by 202202L [C++23]
__cpp_lib_ranges_iota 202202L [C++23]
__cpp_lib_ranges_join_with 202202L [C++23]
+ __cpp_lib_ranges_repeat 202207L [C++23]
__cpp_lib_ranges_slide 202202L [C++23]
__cpp_lib_ranges_starts_ends_with 202106L [C++23]
__cpp_lib_ranges_to_container 202202L [C++23]
@@ -707,6 +708,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -1461,6 +1466,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -2386,6 +2395,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -3581,6 +3594,10 @@
# error "__cpp_lib_ranges_join_with should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should not be defined before c++23"
# endif
@@ -4992,6 +5009,13 @@
# endif
# endif
+# ifndef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_repeat != 202207L
+# error "__cpp_lib_ranges_repeat should have the value 202207L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should be defined in c++23"
@@ -6544,6 +6568,13 @@
# endif
# endif
+# ifndef __cpp_lib_ranges_repeat
+# error "__cpp_lib_ranges_repeat should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_repeat != 202207L
+# error "__cpp_lib_ranges_repeat should have the value 202207L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_slide
# error "__cpp_lib_ranges_slide should be defined in c++26"
diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp
index 542f2cda3ee840..457b137c80457f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.drop/adaptor.pass.cpp
@@ -220,6 +220,27 @@ constexpr bool test() {
test_small_range(std::views::iota(1, 8));
}
+#if TEST_STD_VER >= 23
+ // `views::drop(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`.
+ {
+ auto repeat = std::ranges::repeat_view<int, int>(1, 8);
+ using Result = std::ranges::repeat_view<int, int>;
+ std::same_as<Result> decltype(auto) result = repeat | std::views::drop(3);
+ static_assert(std::ranges::sized_range<Result>);
+ assert(result.size() == 5);
+ assert(*result.begin() == 1);
+ }
+
+ // `views::drop(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`.
+ {
+ auto repeat = std::ranges::repeat_view<int>(1);
+ using Result = std::ranges::repeat_view<int, std::unreachable_sentinel_t>;
+ std::same_as<Result> decltype(auto) result = repeat | std::views::drop(3);
+ static_assert(!std::ranges::sized_range<Result>);
+ static_assert(std::same_as<std::unreachable_sentinel_t, decltype(result.end())>);
+ }
+#endif
+
// Test that it's possible to call `std::views::drop` with any single argument as long as the resulting closure is
// never invoked. There is no good use case for it, but it's valid.
{
diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
index 9f4a5632c82b63..8ffac8d8fab153 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
@@ -179,6 +179,27 @@ constexpr bool test() {
assert(result.size() == 3);
}
+#if TEST_STD_VER >= 23
+ // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`.
+ {
+ auto repeat = std::ranges::repeat_view<int, int>(1, 8);
+ using Result = std::ranges::repeat_view<int, int>;
+ std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
+ static_assert(std::ranges::sized_range<Result>);
+ assert(result.size() == 3);
+ assert(*result.begin() == 1);
+ }
+
+ // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`.
+ {
+ auto repeat = std::ranges::repeat_view<int>(1);
+ using Result = std::ranges::repeat_view<int, std::ranges::range_
diff erence_t<decltype(repeat)>>;
+ std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
+ assert(result.size() == 3);
+ assert(*result.begin() == 1);
+ }
+#endif
+
// When the size of the input range `s` is shorter than `n`, only `s` elements are taken.
{
test_small_range(std::span(buf));
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.pass.cpp
new file mode 100644
index 00000000000000..d8d8657a4fb188
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/begin.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, c++20
+
+// constexpr iterator begin() const;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ // Test unbound && non-const view
+ {
+ std::ranges::repeat_view<int> rv(0);
+ std::same_as<std::ranges::iterator_t<decltype(rv)>> decltype(auto) iter = rv.begin();
+ assert(*iter == 0);
+ }
+
+ // Test unbound && const view
+ {
+ const std::ranges::repeat_view<int> rv(0);
+ std::same_as<std::ranges::iterator_t<decltype(rv)>> decltype(auto) iter = rv.begin();
+ assert(*iter == 0);
+ }
+
+ // Test bound && non-const view
+ {
+ std::ranges::repeat_view<int, int> rv(1024, 10);
+ std::same_as<std::ranges::iterator_t<decltype(rv)>> decltype(auto) iter = rv.begin();
+ assert(*iter == 1024);
+ }
+
+ // Test bound && const view
+ {
+ const std::ranges::repeat_view<int, long long> rv(1024, 10);
+ std::same_as<std::ranges::iterator_t<decltype(rv)>> decltype(auto) iter = rv.begin();
+ assert(*iter == 1024);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp
new file mode 100644
index 00000000000000..454bac6e03e518
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctad.compile.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template<class T, class Bound>
+// repeat_view(T, Bound) -> repeat_view<T, Bound>;
+
+#include <concepts>
+#include <ranges>
+#include <utility>
+
+struct Empty {};
+
+// clang-format off
+static_assert(std::same_as<decltype(std::ranges::repeat_view(Empty())), std::ranges::repeat_view<Empty>>);
+static_assert(std::same_as<decltype(std::ranges::repeat_view(std::declval<Empty&>())), std::ranges::repeat_view<Empty>>);
+static_assert(std::same_as<decltype(std::ranges::repeat_view(std::declval<Empty&&>())), std::ranges::repeat_view<Empty>>);
+static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1)), std::ranges::repeat_view<int, int>>);
+static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1U)), std::ranges::repeat_view<int, unsigned>>);
+static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1UL)), std::ranges::repeat_view<int, unsigned long>>);
+// clang-format on
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..f123770b9cc4ff
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.default.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// repeat_view() requires default_initializable<T> = default;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+struct DefaultInt42 {
+ int value = 42;
+};
+
+struct Int {
+ Int(int) {}
+};
+
+static_assert(std::default_initializable<std::ranges::repeat_view<DefaultInt42>>);
+static_assert(!std::default_initializable<std::ranges::repeat_view<Int>>);
+
+constexpr bool test() {
+ std::ranges::repeat_view<DefaultInt42> rv;
+ assert((*rv.begin()).value == 42);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
new file mode 100644
index 00000000000000..5b7939ae834f6b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template<class... TArgs, class... BoundArgs>
+// requires constructible_from<T, TArgs...> &&
+// constructible_from<Bound, BoundArgs...>
+// constexpr explicit repeat_view(piecewise_construct_t,
+// tuple<TArgs...> value_args, tuple<BoundArgs...> bound_args = tuple<>{});
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+#include <tuple>
+#include <utility>
+
+struct C {};
+
+struct B {
+ int v;
+};
+
+struct A {
+ int x = 111;
+ int y = 222;
+
+ constexpr A() = default;
+ constexpr A(B b) : x(b.v), y(b.v + 1) {}
+ constexpr A(int _x, int _y) : x(_x), y(_y) {}
+};
+
+static_assert(std::constructible_from<std::ranges::repeat_view<A, int>,
+ std::piecewise_construct_t,
+ std::tuple<int, int>,
+ std::tuple<int>>);
+static_assert(std::constructible_from<std::ranges::repeat_view<A, int>,
+ std::piecewise_construct_t,
+ std::tuple<B>,
+ std::tuple<int>>);
+static_assert(std::constructible_from<std::ranges::repeat_view<A, int>,
+ std::piecewise_construct_t,
+ std::tuple<>,
+ std::tuple<int>>);
+static_assert(std::constructible_from<std::ranges::repeat_view<A>,
+ std::piecewise_construct_t,
+ std::tuple<int, int>,
+ std::tuple<std::unreachable_sentinel_t>>);
+static_assert(std::constructible_from<std::ranges::repeat_view<A>,
+ std::piecewise_construct_t,
+ std::tuple<B>,
+ std::tuple<std::unreachable_sentinel_t>>);
+static_assert(std::constructible_from<std::ranges::repeat_view<A>,
+ std::piecewise_construct_t,
+ std::tuple<>,
+ std::tuple<std::unreachable_sentinel_t>>);
+static_assert(!std::constructible_from<std::ranges::repeat_view<A, int>,
+ std::piecewise_construct_t,
+ std::tuple<C>,
+ std::tuple<int>>);
+static_assert(!std::constructible_from<std::ranges::repeat_view<A>,
+ std::piecewise_construct_t,
+ std::tuple<C>,
+ std::tuple<std::unreachable_sentinel_t>>);
+static_assert(!std::constructible_from<std::ranges::repeat_view<A, int>,
+ std::piecewise_construct_t,
+ std::tuple<int, int, int>,
+ std::tuple<int>>);
+static_assert(!std::constructible_from<std::ranges::repeat_view<A>,
+ std::piecewise_construct_t,
+ std::tuple<int, int, int>,
+ std::tuple<std::unreachable_sentinel_t>>);
+static_assert(
+ !std::constructible_from<std::ranges::repeat_view<A>, std::piecewise_construct_t, std::tuple<B>, std::tuple<int>>);
+
+constexpr bool test() {
+ {
+ std::ranges::repeat_view<A, int> rv(std::piecewise_construct, std::tuple{}, std::tuple{3});
+ assert(rv.size() == 3);
+ assert(rv[0].x == 111);
+ assert(rv[0].y == 222);
+ assert(rv.begin() + 3 == rv.end());
+ }
+ {
+ std::ranges::repeat_view<A> rv(std::piecewise_construct, std::tuple{}, std::tuple{std::unreachable_sentinel});
+ assert(rv[0].x == 111);
+ assert(rv[0].y == 222);
+ assert(rv.begin() + 300 != rv.end());
+ }
+ {
+ std::ranges::repeat_view<A, int> rv(std::piecewise_construct, std::tuple{1, 2}, std::tuple{3});
+ assert(rv.size() == 3);
+ assert(rv[0].x == 1);
+ assert(rv[0].y == 2);
+ assert(rv.begin() + 3 == rv.end());
+ }
+ {
+ std::ranges::repeat_view<A> rv(std::piecewise_construct, std::tuple{1, 2}, std::tuple{std::unreachable_sentinel});
+ assert(rv[0].x == 1);
+ assert(rv[0].y == 2);
+ assert(rv.begin() + 300 != rv.end());
+ }
+ {
+ std::ranges::repeat_view<A, int> rv(std::piecewise_construct, std::tuple{B{11}}, std::tuple{3});
+ assert(rv.size() == 3);
+ assert(rv[0].x == 11);
+ assert(rv[0].y == 12);
+ assert(rv.begin() + 3 == rv.end());
+ }
+ {
+ std::ranges::repeat_view<A> rv(std::piecewise_construct, std::tuple{B{10}}, std::tuple{std::unreachable_sentinel});
+ assert(rv[0].x == 10);
+ assert(rv[0].y == 11);
+ assert(rv.begin() + 300 != rv.end());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
new file mode 100644
index 00000000000000..733729f26f0a11
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.value.bound.pass.cpp
@@ -0,0 +1,98 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr explicit repeat_view(const T& value, Bound bound = Bound()) requires copy_constructible<T>;
+// constexpr explicit repeat_view(T&& value, Bound bound = Bound());
+
+#include <ranges>
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+
+#include "MoveOnly.h"
+
+struct Empty {};
+
+// Test explicit
+static_assert(std::is_constructible_v<std::ranges::repeat_view<Empty>, const Empty&>);
+static_assert(std::is_constructible_v<std::ranges::repeat_view<Empty>, Empty&&>);
+static_assert(std::is_constructible_v<std::ranges::repeat_view<Empty, int>, const Empty&>);
+static_assert(std::is_constructible_v<std::ranges::repeat_view<Empty, int>, Empty&&>);
+
+static_assert(!std::is_convertible_v<const Empty&, std::ranges::repeat_view<Empty>>);
+static_assert(!std::is_convertible_v<Empty&&, std::ranges::repeat_view<Empty>>);
+static_assert(!std::is_convertible_v<const Empty&, std::ranges::repeat_view<Empty, int>>);
+static_assert(!std::is_convertible_v<Empty&&, std::ranges::repeat_view<Empty, int>>);
+
+static_assert(!std::is_constructible_v<std::ranges::repeat_view<MoveOnly>, const MoveOnly&>);
+static_assert(std::is_constructible_v<std::ranges::repeat_view<MoveOnly>, MoveOnly&&>);
+
+constexpr bool test() {
+ // Move && unbound && default argument
+ {
+ std::ranges::repeat_view<Empty> rv(Empty{});
+ assert(rv.begin() + 10 != rv.end());
+ }
+
+ // Move && unbound && user-provided argument
+ {
+ std::ranges::repeat_view<Empty> rv(Empty{}, std::unreachable_sentinel);
+ assert(rv.begin() + 10 != rv.end());
+ }
+
+ // Move && bound && default argument
+ {
+ std::ranges::repeat_view<Empty, int> rv(Empty{});
+ assert(rv.begin() == rv.end());
+ }
+
+ // Move && bound && user-provided argument
+ {
+ std::ranges::repeat_view<Empty, int> rv(Empty{}, 10);
+ assert(rv.begin() + 10 == rv.end());
+ }
+
+ // Copy && unbound && default argument
+ {
+ Empty e;
+ std::ranges::repeat_view<Empty> rv(e);
+ assert(rv.begin() + 10 != rv.end());
+ }
+
+ // Copy && unbound && user-provided argument
+ {
+ Empty e;
+ std::ranges::repeat_view<Empty> rv(e, std::unreachable_sentinel);
+ assert(rv.begin() + 10 != rv.end());
+ }
+
+ // Copy && bound && default argument
+ {
+ Empty e;
+ std::ranges::repeat_view<Empty, int> rv(e);
+ assert(rv.begin() == rv.end());
+ }
+
+ // Copy && bound && user-provided argument
+ {
+ Empty e;
+ std::ranges::repeat_view<Empty, int> rv(e, 10);
+ assert(rv.begin() + 10 == rv.end());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/end.pass.cpp
new file mode 100644
index 00000000000000..32ef9ebd4a66f5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/end.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, c++20
+
+// constexpr unreachable_sentinel_t end() const noexcept;
+// constexpr iterator end() const requires (!same_as<Bound, unreachable_sentinel_t>);
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+#include <iterator>
+
+constexpr bool test() {
+ // bound
+ {
+ std::ranges::repeat_view<int, int> rv(0, 10);
+ assert(rv.begin() + 10 == rv.end());
+ std::same_as<std::ranges::iterator_t<decltype(rv)>> decltype(auto) iter = rv.end();
+ static_assert(std::same_as<decltype(*iter), const int&>);
+ for (const auto& i : rv) {
+ assert(i == 0);
+ }
+ }
+
+ // unbound
+ {
+ std::ranges::repeat_view<int> rv(0);
+ assert(rv.begin() + 10 != rv.end());
+ static_assert(std::same_as<decltype(rv.end()), std::unreachable_sentinel_t>);
+ static_assert(noexcept(rv.end()));
+ for (const auto& i : rv | std::views::take(10)) {
+ assert(i == 0);
+ }
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.pass.cpp
new file mode 100644
index 00000000000000..f7bfca68054b33
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/compare.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, c++20
+
+// repeat_view::<iterator>::operator{==,<=>}
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ // Test unbound
+ {
+ using R = std::ranges::repeat_view<int>;
+ static_assert(std::three_way_comparable<std::ranges::iterator_t<R>>);
+
+ std::ranges::repeat_view<int> r(42);
+ auto iter1 = r.begin();
+ auto iter2 = iter1 + 1;
+
+ static_assert(std::same_as<decltype(iter1 == iter2), bool>);
+
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+
+ assert(!(iter1 < iter1));
+ assert(iter1 < iter2);
+ assert(!(iter2 < iter1));
+ assert(iter1 <= iter1);
+ assert(iter1 <= iter2);
+ assert(!(iter2 <= iter1));
+ assert(!(iter1 > iter1));
+ assert(!(iter1 > iter2));
+ assert(iter2 > iter1);
+ assert(iter1 >= iter1);
+ assert(!(iter1 >= iter2));
+ assert(iter2 >= iter1);
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+ assert(!(iter1 != iter1));
+ assert(iter1 != iter2);
+ assert(!(iter2 != iter2));
+
+ assert((iter1 <=> iter2) == std::strong_ordering::less);
+ assert((iter1 <=> iter1) == std::strong_ordering::equal);
+ assert((iter2 <=> iter1) == std::strong_ordering::greater);
+
+ static_assert(std::same_as<decltype(iter1 <=> iter2), std::strong_ordering>);
+ }
+
+ // Test bound
+ {
+ using R = std::ranges::repeat_view<int, int>;
+ static_assert(std::three_way_comparable<std::ranges::iterator_t<R>>);
+
+ std::ranges::repeat_view<int, int> r(42, 10);
+ auto iter1 = r.begin();
+ auto iter2 = iter1 + 1;
+
+ static_assert(std::same_as<decltype(iter1 == iter2), bool>);
+
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+
+ assert(!(iter1 < iter1));
+ assert(iter1 < iter2);
+ assert(!(iter2 < iter1));
+ assert(iter1 <= iter1);
+ assert(iter1 <= iter2);
+ assert(!(iter2 <= iter1));
+ assert(!(iter1 > iter1));
+ assert(!(iter1 > iter2));
+ assert(iter2 > iter1);
+ assert(iter1 >= iter1);
+ assert(!(iter1 >= iter2));
+ assert(iter2 >= iter1);
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ assert(iter2 == iter2);
+ assert(!(iter1 != iter1));
+ assert(iter1 != iter2);
+ assert(!(iter2 != iter2));
+
+ assert((iter1 <=> iter2) == std::strong_ordering::less);
+ assert((iter1 <=> iter1) == std::strong_ordering::equal);
+ assert((iter2 <=> iter1) == std::strong_ordering::greater);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..fa69145e13a086
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/ctor.default.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// iterator() = default;
+
+#include <ranges>
+#include <type_traits>
+
+constexpr bool test() {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ static_assert(std::is_default_constructible_v<Iter>);
+ [[maybe_unused]] Iter iter;
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp
new file mode 100644
index 00000000000000..aa90f846bebb9b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/decrement.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator& operator--();
+// constexpr iterator operator--(int);
+
+#include <ranges>
+#include <cassert>
+
+constexpr bool test() {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ std::ranges::repeat_view<int> rv(10);
+ auto iter = rv.begin() + 10;
+
+ assert(iter-- == rv.begin() + 10);
+ assert(--iter == rv.begin() + 8);
+
+ static_assert(std::same_as<decltype(iter--), Iter>);
+ static_assert(std::same_as<decltype(--iter), Iter&>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.pass.cpp
new file mode 100644
index 00000000000000..8632300522d84a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/increment.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, c++20
+
+// constexpr iterator& operator++();
+// constexpr void operator++(int);
+
+#include <ranges>
+#include <concepts>
+#include <cassert>
+
+constexpr bool test() {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ std::ranges::repeat_view<int> rv(10);
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ auto iter = rv.begin();
+
+ assert(iter++ == rv.begin());
+ assert(++iter == rv.begin() + 2);
+
+ static_assert(std::same_as<decltype(iter++), Iter>);
+ static_assert(std::same_as<decltype(++iter), Iter&>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp
new file mode 100644
index 00000000000000..2ef09a6d921698
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/member_typedefs.compile.pass.cpp
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Test iterator category and iterator concepts.
+
+// using index-type = conditional_t<same_as<Bound, unreachable_sentinel_t>, ptr
diff _t, Bound>;
+// using iterator_concept = random_access_iterator_tag;
+// using iterator_category = random_access_iterator_tag;
+// using value_type = T;
+// using
diff erence_type = see below:
+// If is-signed-integer-like<index-type> is true, the member typedef-name
diff erence_type denotes
+// index-type. Otherwise, it denotes IOTA-DIFF-T(index-type).
+
+#include <cassert>
+#include <concepts>
+#include <cstdint>
+#include <ranges>
+#include <type_traits>
+
+constexpr bool test() {
+ // unbound
+ {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::same_as<Iter::
diff erence_type, ptr
diff _t>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ }
+
+ // bound
+ {
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::int8_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) == sizeof(std::int8_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::uint8_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) > sizeof(std::uint8_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::int16_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) == sizeof(std::int16_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::uint16_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) > sizeof(std::uint16_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::int32_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) == sizeof(std::int32_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::uint32_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) > sizeof(std::uint32_t));
+ }
+
+ {
+ using Iter = std::ranges::iterator_t<const std::ranges::repeat_view<int, std::int64_t>>;
+ static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::iterator_category, std::random_access_iterator_tag>);
+ static_assert(std::same_as<Iter::value_type, int>);
+ static_assert(std::is_signed_v<Iter::
diff erence_type>);
+ static_assert(sizeof(Iter::
diff erence_type) == sizeof(std::int64_t));
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.pass.cpp
new file mode 100644
index 00000000000000..3a373741f4c0e4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus.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, c++20
+
+// friend constexpr iterator operator-(iterator i,
diff erence_type n);
+// friend constexpr
diff erence_type operator-(const iterator& x, const iterator& y);
+
+#include <ranges>
+#include <cassert>
+#include <cstdint>
+#include <concepts>
+
+constexpr bool test() {
+ // <iterator> -
diff erence_type
+ {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ std::ranges::repeat_view<int> v(0);
+ Iter iter = v.begin() + 10;
+ assert(iter - 5 == v.begin() + 5);
+ static_assert(std::same_as<decltype(iter - 5), Iter>);
+ }
+
+ // <iterator> - <iterator>
+ {
+ // unbound
+ {
+ std::ranges::repeat_view<int> v(0);
+ auto iter1 = v.begin() + 10;
+ auto iter2 = v.begin() + 5;
+ assert(iter1 - iter2 == 5);
+ static_assert(std::same_as<decltype(iter1 - iter2), ptr
diff _t>);
+ }
+
+ // bound && signed bound sentinel
+ {
+ std::ranges::repeat_view<int, int> v(0, 20);
+ auto iter1 = v.begin() + 10;
+ auto iter2 = v.begin() + 5;
+ assert(iter1 - iter2 == 5);
+ static_assert(std::same_as<decltype(iter1 - iter2), int>);
+ }
+
+ // bound && unsigned bound sentinel
+ {
+ std::ranges::repeat_view<int, unsigned> v(0, 20);
+ auto iter1 = v.begin() + 10;
+ auto iter2 = v.begin() + 5;
+ assert(iter1 - iter2 == 5);
+ static_assert(sizeof(decltype(iter1 - iter2)) > sizeof(unsigned));
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.pass.cpp
new file mode 100644
index 00000000000000..84310e472576d6
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/minus_eq.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, c++20
+
+// constexpr iterator& operator-=(
diff erence_type n);
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ std::ranges::repeat_view<int> v(10);
+ auto iter = v.begin() + 10;
+ iter -= 5;
+ assert(iter == v.begin() + 5);
+
+ static_assert(std::same_as<decltype(iter -= 5), Iter&>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.pass.cpp
new file mode 100644
index 00000000000000..5b484a8e50d4b4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus.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, c++20
+
+// friend constexpr iterator operator+(iterator i,
diff erence_type n);
+// friend constexpr iterator operator+(
diff erence_type n, iterator i);
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ std::ranges::repeat_view<int> v(10);
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ auto iter = v.begin();
+ assert(iter + 5 == v.begin() + 5);
+ assert(5 + iter == v.begin() + 5);
+ assert(2 + iter == v.begin() + 2);
+ assert(3 + iter == v.begin() + 3);
+
+ static_assert(std::same_as<decltype(iter + 5), Iter>);
+ static_assert(std::same_as<decltype(5 + iter), Iter>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.pass.cpp
new file mode 100644
index 00000000000000..a4696d73839b6b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/plus_eq.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, c++20
+
+// constexpr iterator& operator+=(
diff erence_type n);
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ std::ranges::repeat_view<int> v(10);
+ using Iter = std::ranges::iterator_t<std::ranges::repeat_view<int>>;
+ auto iter1 = v.begin() + 10;
+ auto iter2 = v.begin() + 10;
+ assert(iter1 == iter2);
+ iter1 += 5;
+ assert(iter1 != iter2);
+ assert(iter1 == iter2 + 5);
+
+ static_assert(std::same_as<decltype(iter2 += 5), Iter&>);
+ assert(std::addressof(iter2) == std::addressof(iter2 += 5));
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp
new file mode 100644
index 00000000000000..214ee625b595ff
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/star.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr const W & operator*() const noexcept;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+constexpr bool test() {
+ // unbound
+ {
+ std::ranges::repeat_view<int> v(31);
+ auto iter = v.begin();
+
+ const int& val = *iter;
+ for (int i = 0; i < 100; ++i, ++iter) {
+ assert(*iter == 31);
+ assert(&*iter == &val);
+ }
+
+ static_assert(noexcept(*iter));
+ static_assert(std::same_as<decltype(*iter), const int&>);
+ }
+
+ // bound && one element
+ {
+ std::ranges::repeat_view<int, int> v(31, 1);
+ auto iter = v.begin();
+ assert(*iter == 31);
+ static_assert(noexcept(*iter));
+ static_assert(std::same_as<decltype(*iter), const int&>);
+ }
+
+ // bound && several elements
+ {
+ std::ranges::repeat_view<int, int> v(31, 100);
+ auto iter = v.begin();
+
+ const int& val = *iter;
+ for (int i = 0; i < 100; ++i, ++iter) {
+ assert(*iter == 31);
+ assert(&*iter == &val);
+ }
+ }
+
+ // bound && foreach
+ {
+ for (const auto& val : std::views::repeat(31, 100))
+ assert(val == 31);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp
new file mode 100644
index 00000000000000..3075168bc9d684
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/iterator/subscript.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr const W & operator[](
diff erence_type n) const noexcept;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+#include <algorithm>
+
+constexpr bool test() {
+ // unbound
+ {
+ std::ranges::repeat_view<int> v(31);
+ auto iter = v.begin();
+ assert(std::ranges::all_of(std::views::iota(0, 100), [&v](int i) { return v[i] == 31; }));
+
+ static_assert(noexcept(iter[0]));
+ static_assert(std::same_as<decltype(iter[0]), const int&>);
+ }
+
+ // bound
+ {
+ std::ranges::repeat_view<int, int> v(32);
+ auto iter = v.begin();
+ assert(std::ranges::all_of(v, [](int i) { return i == 32; }));
+ static_assert(noexcept(iter[0]));
+ static_assert(std::same_as<decltype(iter[0]), const int&>);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp
new file mode 100644
index 00000000000000..097dc94b8658e1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/size.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto size() const requires (!same_as<Bound, unreachable_sentinel_t>);
+
+#include <ranges>
+#include <numeric>
+#include <concepts>
+#include <cassert>
+#include <iterator>
+
+template <class T>
+concept has_size = requires(T&& view) {
+ { std::forward<T>(view).size() };
+};
+
+static_assert(has_size<std::ranges::repeat_view<int, int>>);
+static_assert(!has_size<std::ranges::repeat_view<int>>);
+static_assert(!has_size<std::ranges::repeat_view<int, std::unreachable_sentinel_t>>);
+
+constexpr bool test() {
+ {
+ std::ranges::repeat_view<int, int> rv(10, 20);
+ assert(rv.size() == 20);
+ }
+
+ {
+ std::ranges::repeat_view<int, int> rv(10, std::numeric_limits<int>::max());
+ assert(rv.size() == std::numeric_limits<int>::max());
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp b/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp
new file mode 100644
index 00000000000000..c174850c400984
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.repeat.view/views_repeat.pass.cpp
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template <class T>
+// views::repeat(T &&) requires constructible_from<ranges::repeat_view<T>, T>;
+
+// templaye <class T, class Bound>
+// views::repeat(T &&, Bound &&) requires constructible_from<ranges::repeat_view<T, Bound>, T, Bound>;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <tuple>
+#include <type_traits>
+
+#include "MoveOnly.h"
+
+struct NonCopyable {
+ NonCopyable(NonCopyable&) = delete;
+};
+
+struct NonDefaultCtor {
+ NonDefaultCtor(int) {}
+};
+
+struct Empty {};
+
+struct LessThan3 {
+ constexpr bool operator()(int i) const { return i < 3; }
+};
+
+struct EqualTo33 {
+ constexpr bool operator()(int i) const { return i == 33; }
+};
+
+struct Add3 {
+ constexpr int operator()(int i) const { return i + 3; }
+};
+
+// Tp is_object
+static_assert(std::is_invocable_v<decltype(std::views::repeat), int>);
+static_assert(!std::is_invocable_v<decltype(std::views::repeat), void>);
+
+// _Bound is semiregular, integer like or std::unreachable_sentinel_t
+static_assert(!std::is_invocable_v<decltype(std::views::repeat), int, Empty>);
+static_assert(!std::is_invocable_v<decltype(std::views::repeat), int, NonCopyable>);
+static_assert(!std::is_invocable_v<decltype(std::views::repeat), int, NonDefaultCtor>);
+static_assert(std::is_invocable_v<decltype(std::views::repeat), int, std::unreachable_sentinel_t>);
+
+// Tp is copy_constructible
+static_assert(!std::is_invocable_v<decltype(std::views::repeat), NonCopyable>);
+
+// Tp is move_constructible
+static_assert(std::is_invocable_v<decltype(std::views::repeat), MoveOnly>);
+
+constexpr bool test() {
+ assert(*std::views::repeat(33).begin() == 33);
+ assert(*std::views::repeat(33, 10).begin() == 33);
+ static_assert(std::same_as<decltype(std::views::repeat(42)), std::ranges::repeat_view<int>>);
+ static_assert(std::same_as<decltype(std::views::repeat(42, 3)), std::ranges::repeat_view<int, int>>);
+ static_assert(std::same_as<decltype(std::views::repeat), decltype(std::ranges::views::repeat)>);
+
+ // unbound && drop_view
+ {
+ auto r = std::views::repeat(33) | std::views::drop(3);
+ static_assert(!std::ranges::sized_range<decltype(r)>);
+ assert(*r.begin() == 33);
+ }
+
+ // bound && drop_view
+ {
+ auto r = std::views::repeat(33, 8) | std::views::drop(3);
+ static_assert(std::ranges::sized_range<decltype(r)>);
+ assert(*r.begin() == 33);
+ assert(r.size() == 5);
+ }
+
+ // unbound && take_view
+ {
+ auto r = std::views::repeat(33) | std::views::take(3);
+ static_assert(std::ranges::sized_range<decltype(r)>);
+ assert(*r.begin() == 33);
+ assert(r.size() == 3);
+ }
+
+ // bound && take_view
+ {
+ auto r = std::views::repeat(33, 8) | std::views::take(3);
+ static_assert(std::ranges::sized_range<decltype(r)>);
+ assert(*r.begin() == 33);
+ assert(r.size() == 3);
+ }
+
+ // bound && transform_view
+ {
+ auto r = std::views::repeat(33, 8) | std::views::transform(Add3{});
+ assert(*r.begin() == 36);
+ assert(r.size() == 8);
+ }
+
+ // unbound && transform_view
+ {
+ auto r = std::views::repeat(33) | std::views::transform(Add3{});
+ assert(*r.begin() == 36);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 67545f27280a6c..90a064625c93e9 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -816,6 +816,11 @@ def add_version_header(tc):
"headers": ["ranges"],
"unimplemented": True,
},
+ {
+ "name": "__cpp_lib_ranges_repeat",
+ "values": { "c++23": 202207},
+ "headers": ["ranges"],
+ },
{
"name": "__cpp_lib_ranges_slide",
"values": {"c++23": 202202},
More information about the libcxx-commits
mailing list