[libcxx-commits] [libcxx] 9d982c6 - [libcxx][ranges] Add `ranges::reverse_view`.
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Aug 9 15:10:08 PDT 2021
Author: zoecarver
Date: 2021-08-09T15:09:59-07:00
New Revision: 9d982c67ba01ef5fcee1e2ca946a8bd0b6747ac0
URL: https://github.com/llvm/llvm-project/commit/9d982c67ba01ef5fcee1e2ca946a8bd0b6747ac0
DIFF: https://github.com/llvm/llvm-project/commit/9d982c67ba01ef5fcee1e2ca946a8bd0b6747ac0.diff
LOG: [libcxx][ranges] Add `ranges::reverse_view`.
Differential Revision: https://reviews.llvm.org/D107096
Added:
libcxx/include/__ranges/reverse_view.h
libcxx/test/libcxx/diagnostics/detail.headers/ranges/reverse_view.module.verify.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/base.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/borrowing.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.default.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.view.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/end.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/range_concept_conformance.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/size.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.reverse/types.h
Modified:
libcxx/docs/Status/RangesPaper.csv
libcxx/include/CMakeLists.txt
libcxx/include/module.modulemap
libcxx/include/ranges
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 29ad8c3ad3ff0..daa7668166096 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -146,4 +146,4 @@ Section,Description,Dependencies,Assignee,Complete
`[range.split] <http://wg21.link/range.split>`_,split_view,[range.all],Zoe Carver,In Progress
`[range.counted] <http://wg21.link/range.counted>`_,view::counted,[range.subrange],Zoe Carver,Not started
`[range.common] <http://wg21.link/range.common>`_,common_view,[range.all],Zoe Carver,✅
-`[range.reverse] <http://wg21.link/range.reverse>`_,reverse_view,[range.all],Unassigned,Not started
+`[range.reverse] <http://wg21.link/range.reverse>`_,reverse_view,[range.all],Zoe Carver,✅
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1be2df1b5c381..765c193339127 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -199,6 +199,8 @@ set(files
__ranges/enable_view.h
__ranges/non_propagating_cache.h
__ranges/ref_view.h
+ __ranges/reverse_view.h
+ __ranges/take_view.h
__ranges/single_view.h
__ranges/size.h
__ranges/subrange.h
diff --git a/libcxx/include/__ranges/reverse_view.h b/libcxx/include/__ranges/reverse_view.h
new file mode 100644
index 0000000000000..25d3d6568cd57
--- /dev/null
+++ b/libcxx/include/__ranges/reverse_view.h
@@ -0,0 +1,112 @@
+// -*- 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_REVERSE_VIEW_H
+#define _LIBCPP___RANGES_REVERSE_VIEW_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/next.h>
+#include <__iterator/reverse_iterator.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/non_propagating_cache.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.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<view _View>
+ requires bidirectional_range<_View>
+ class reverse_view : public view_interface<reverse_view<_View>> {
+ // We cache begin() whenever ranges::next is not guaranteed O(1) to provide an
+ // amortized O(1) begin() method.
+ static constexpr bool _UseCache = !random_access_range<_View> && !common_range<_View>;
+ using _Cache = _If<_UseCache, __non_propagating_cache<reverse_iterator<iterator_t<_View>>>, __empty_cache>;
+ [[no_unique_address]] _Cache __cached_begin_ = _Cache();
+ [[no_unique_address]] _View __base_ = _View();
+
+ public:
+ _LIBCPP_HIDE_FROM_ABI
+ reverse_view() requires default_initializable<_View> = default;
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr explicit reverse_view(_View __view) : __base_(_VSTD::move(__view)) {}
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr _View base() && { return _VSTD::move(__base_); }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr reverse_iterator<iterator_t<_View>> begin() {
+ if constexpr (_UseCache)
+ if (__cached_begin_.__has_value())
+ return *__cached_begin_;
+
+ auto __tmp = _VSTD::make_reverse_iterator(ranges::next(ranges::begin(__base_), ranges::end(__base_)));
+ if constexpr (_UseCache)
+ __cached_begin_.__set(__tmp);
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr reverse_iterator<iterator_t<_View>> begin() requires common_range<_View> {
+ return _VSTD::make_reverse_iterator(ranges::end(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr auto begin() const requires common_range<const _View> {
+ return _VSTD::make_reverse_iterator(ranges::end(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr reverse_iterator<iterator_t<_View>> end() {
+ return _VSTD::make_reverse_iterator(ranges::begin(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr auto end() const requires common_range<const _View> {
+ return _VSTD::make_reverse_iterator(ranges::begin(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr auto size() requires sized_range<_View> {
+ return ranges::size(__base_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr auto size() const requires sized_range<const _View> {
+ return ranges::size(__base_);
+ }
+ };
+
+ template<class _Range>
+ reverse_view(_Range&&) -> reverse_view<views::all_t<_Range>>;
+
+ template<class _Tp>
+ inline constexpr bool enable_borrowed_range<reverse_view<_Tp>> = enable_borrowed_range<_Tp>;
+} // namespace ranges
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___RANGES_REVERSE_VIEW_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index ee6f3c3e0a4d4..7f8c3bcc9d707 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -631,6 +631,7 @@ module std [system] {
module enable_view { private header "__ranges/enable_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" }
module size { private header "__ranges/size.h" }
module single_view { private header "__ranges/single_view.h" }
module subrange { private header "__ranges/subrange.h" }
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index cd29aeee92cc5..a2243138531cc 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -154,6 +154,14 @@ namespace std::ranges {
requires (!common_range<V> && copyable<iterator_t<V>>)
class common_view;
+ // [range.reverse], reverse view
+ template<view V>
+ requires bidirectional_range<V>
+ class reverse_view;
+
+ template<class T>
+ inline constexpr bool enable_borrowed_range<reverse_view<T>> = enable_borrowed_range<T>;
+
template<class T>
inline constexpr bool enable_borrowed_range<common_view<T>> = enable_borrowed_range<T>;
@@ -188,6 +196,8 @@ namespace std::ranges {
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
#include <__ranges/ref_view.h>
+#include <__ranges/reverse_view.h>
+#include <__ranges/take_view.h>
#include <__ranges/single_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/reverse_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/reverse_view.module.verify.cpp
new file mode 100644
index 0000000000000..66c8f84ee44e8
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/reverse_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/reverse_view.h'}}
+#include <__ranges/reverse_view.h>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/base.pass.cpp
new file mode 100644
index 0000000000000..3c59ffedb3327
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/base.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr V base() const& requires copy_constructible<V> { return base_; }
+// constexpr V base() && { return std::move(base_); }
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Test common ranges.
+ {
+ // Test non-const.
+ {
+ auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.base().ptr_ == buffer);
+ assert(std::move(rev).base().ptr_ == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.base()), BidirRange);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirRange);
+ }
+ // Test const.
+ {
+ const auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.base().ptr_ == buffer);
+ assert(std::move(rev).base().ptr_ == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.base()), BidirRange);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirRange);
+ }
+ }
+ // Test non-common ranges.
+ {
+ // Test non-const (also move only).
+ {
+ auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer});
+ assert(std::move(rev).base().ptr_ == buffer);
+
+ ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange<MoveOnly>);
+ }
+ // Test const.
+ {
+ const auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer});
+ assert(rev.base().ptr_ == buffer);
+ assert(std::move(rev).base().ptr_ == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.base()), BidirSentRange<Copyable>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange<Copyable>);
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp
new file mode 100644
index 0000000000000..779bef8386fb1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp
@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr reverse_iterator<iterator_t<V>> begin();
+// constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
+// constexpr auto begin() const requires common_range<const V>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+static int globalCount = 0;
+
+struct CountedIter {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef int value_type;
+ typedef std::ptr
diff _t
diff erence_type;
+ typedef int* pointer;
+ typedef int& reference;
+ typedef CountedIter self;
+
+ pointer ptr_;
+ CountedIter(pointer ptr) : ptr_(ptr) {}
+ CountedIter() = default;
+
+ reference operator*() const;
+ pointer operator->() const;
+ auto operator<=>(const self&) const = default;
+
+ self& operator++() { globalCount++; ++ptr_; return *this; }
+ self operator++(int) {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ self& operator--();
+ self operator--(int);
+};
+
+struct CountedView : std::ranges::view_base {
+ int *ptr_;
+
+ CountedView(int *ptr) : ptr_(ptr) {}
+
+ auto begin() { return CountedIter(ptr_); }
+ auto begin() const { return CountedIter(ptr_); }
+ auto end() { return sentinel_wrapper<CountedIter>(CountedIter(ptr_ + 8)); }
+ auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(ptr_ + 8)); }
+};
+
+struct RASentRange : std::ranges::view_base {
+ using sent_t = sentinel_wrapper<random_access_iterator<int*>>;
+ using sent_const_t = sentinel_wrapper<random_access_iterator<const int*>>;
+
+ int *ptr_;
+
+ constexpr RASentRange(int *ptr) : ptr_(ptr) {}
+
+ constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{ptr_}; }
+ constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{ptr_}; }
+ constexpr sent_t end() { return sent_t{random_access_iterator<int*>{ptr_ + 8}}; }
+ constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{ptr_ + 8}}; }
+};
+
+template<class T>
+concept BeginInvocable = requires(T t) { t.begin(); };
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Common bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.begin().base().base() == buffer + 8);
+ assert(std::move(rev).begin().base().base() == buffer + 8);
+
+ ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+ // Const common bidirectional range.
+ {
+ const auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.begin().base().base() == buffer + 8);
+ assert(std::move(rev).begin().base().base() == buffer + 8);
+
+ ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
+ }
+ // Non-common, non-const (move only) bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer});
+ assert(std::move(rev).begin().base().base() == buffer + 8);
+
+ ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+ // Non-common, non-const bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer});
+ assert(rev.begin().base().base() == buffer + 8);
+ assert(std::move(rev).begin().base().base() == buffer + 8);
+
+ ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+ // Non-common random access range.
+ // Note: const overload invalid for non-common ranges, though it would not be imposible
+ // to implement for random access ranges.
+ {
+ auto rev = std::ranges::reverse_view(RASentRange{buffer});
+ assert(rev.begin().base().base() == buffer + 8);
+ assert(std::move(rev).begin().base().base() == buffer + 8);
+
+ ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<random_access_iterator<int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<random_access_iterator<int*>>);
+ }
+ {
+ static_assert( BeginInvocable< std::ranges::reverse_view<BidirSentRange<Copyable>>>);
+ static_assert(!BeginInvocable<const std::ranges::reverse_view<BidirSentRange<Copyable>>>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ {
+ // Make sure we cache begin.
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ CountedView view{buffer};
+ std::ranges::reverse_view rev(view);
+ assert(rev.begin().base().ptr_ == buffer + 8);
+ assert(globalCount == 8);
+ assert(rev.begin().base().ptr_ == buffer + 8);
+ assert(globalCount == 8);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..ff211ae2ea1ae
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/borrowing.compile.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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class T>
+// inline constexpr bool enable_borrowed_range<reverse_view<T>> = enable_borrowed_range<T>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_iterators.h"
+
+struct View : std::ranges::view_base {
+ friend int* begin(View&);
+ friend int* begin(View const&);
+ friend sentinel_wrapper<int*> end(View&);
+ friend sentinel_wrapper<int*> end(View const&);
+};
+
+struct BorrowableView : std::ranges::view_base {
+ friend int* begin(BorrowableView&);
+ friend int* begin(BorrowableView const&);
+ friend sentinel_wrapper<int*> end(BorrowableView&);
+ friend sentinel_wrapper<int*> end(BorrowableView const&);
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowableView> = true;
+
+static_assert(!std::ranges::enable_borrowed_range<std::ranges::reverse_view<View>>);
+static_assert( std::ranges::enable_borrowed_range<std::ranges::reverse_view<BorrowableView>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..082867d39b8e8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// template<class R>
+// reverse_view(R&&) -> reverse_view<views::all_t<R>>;
+
+#include <ranges>
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+
+struct View : std::ranges::view_base {
+ friend int* begin(View&);
+ friend int* begin(View const&);
+ friend sentinel_wrapper<int*> end(View&);
+ friend sentinel_wrapper<int*> end(View const&);
+};
+
+struct Range {
+ friend int* begin(Range&);
+ friend int* begin(Range const&);
+ friend sentinel_wrapper<int*> end(Range&);
+ friend sentinel_wrapper<int*> end(Range const&);
+};
+
+struct BorrowedRange {
+ friend int* begin(BorrowedRange&);
+ friend int* begin(BorrowedRange const&);
+ friend sentinel_wrapper<int*> end(BorrowedRange&);
+ friend sentinel_wrapper<int*> end(BorrowedRange const&);
+};
+
+template<>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedRange> = true;
+
+void testCTAD() {
+ View v;
+ Range r;
+ BorrowedRange br;
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(v)),
+ std::ranges::reverse_view<View>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(r)),
+ std::ranges::reverse_view<std::ranges::ref_view<Range>>
+ >);
+ // std::ranges::reverse_view(std::move(r)) invalid. RValue range must be borrowed.
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(br)),
+ std::ranges::reverse_view<std::ranges::ref_view<BorrowedRange>>
+ >);
+ static_assert(std::same_as<
+ decltype(std::ranges::reverse_view(std::move(br))),
+ std::ranges::reverse_view<std::ranges::subrange<
+ int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
+ >);
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..18974346a86b4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.default.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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// reverse_view() requires default_initializable<V> = default;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+enum CtorKind { DefaultCtor, PtrCtor };
+template<CtorKind CK>
+struct BidirRangeWith : std::ranges::view_base {
+ int *ptr_ = nullptr;
+
+ constexpr BidirRangeWith() requires (CK == DefaultCtor) = default;
+ constexpr BidirRangeWith(int *ptr);
+
+ constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{ptr_}; }
+ constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{ptr_}; }
+ constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{ptr_ + 8}; }
+ constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{ptr_ + 8}; }
+};
+
+constexpr bool test() {
+ {
+ static_assert( std::default_initializable<std::ranges::reverse_view<BidirRangeWith<DefaultCtor>>>);
+ static_assert(!std::default_initializable<std::ranges::reverse_view<BidirRangeWith<PtrCtor>>>);
+ }
+
+ {
+ std::ranges::reverse_view<BidirRangeWith<DefaultCtor>> rev;
+ assert(rev.base().ptr_ == nullptr);
+ }
+ {
+ const std::ranges::reverse_view<BidirRangeWith<DefaultCtor>> rev;
+ assert(rev.base().ptr_ == nullptr);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
+
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.view.pass.cpp
new file mode 100644
index 0000000000000..647fc3dc5e1d2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctor.view.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr explicit reverse_view(V r);
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ {
+ BidirRange r{buffer};
+ std::ranges::reverse_view<BidirRange> rev(r);
+ assert(rev.base().ptr_ == buffer);
+ }
+ {
+ const BidirRange r{buffer};
+ const std::ranges::reverse_view<BidirRange> rev(r);
+ assert(rev.base().ptr_ == buffer);
+ }
+ {
+ std::ranges::reverse_view<BidirSentRange<MoveOnly>> rev(BidirSentRange<MoveOnly>{buffer});
+ assert(std::move(rev).base().ptr_ == buffer);
+ }
+ {
+ const std::ranges::reverse_view<BidirSentRange<Copyable>> rev(BidirSentRange<Copyable>{buffer});
+ assert(rev.base().ptr_ == buffer);
+ }
+ {
+ // Make sure this ctor is marked as "explicit".
+ static_assert( std::is_constructible_v<std::ranges::reverse_view<BidirRange>, BidirRange>);
+ static_assert(!std::is_convertible_v<std::ranges::reverse_view<BidirRange>, BidirRange>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/end.pass.cpp
new file mode 100644
index 0000000000000..eb430d16bc100
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/end.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr reverse_iterator<iterator_t<V>> end();
+// constexpr auto end() const requires common_range<const V>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Common bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.end().base().base() == buffer);
+ assert(std::move(rev).end().base().base() == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.end()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+ // Const common bidirectional range.
+ {
+ const auto rev = std::ranges::reverse_view(BidirRange{buffer});
+ assert(rev.end().base().base() == buffer);
+ assert(std::move(rev).end().base().base() == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.end()), std::reverse_iterator<bidirectional_iterator<const int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator<bidirectional_iterator<const int*>>);
+ }
+ // Non-common, non-const (move only) bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer});
+ assert(std::move(rev).end().base().base() == buffer);
+
+ ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+ // Non-common, const bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer});
+ assert(rev.end().base().base() == buffer);
+ assert(std::move(rev).end().base().base() == buffer);
+
+ ASSERT_SAME_TYPE(decltype(rev.end()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator<bidirectional_iterator<int*>>);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/range_concept_conformance.compile.pass.cpp
new file mode 100644
index 0000000000000..e41c173e07c49
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/range_concept_conformance.compile.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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// Test that reverse_view conforms to range and view concepts.
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+static_assert( std::ranges::bidirectional_range<std::ranges::reverse_view<test_view<bidirectional_iterator>>>);
+static_assert( std::ranges::random_access_range<std::ranges::reverse_view<test_view<random_access_iterator>>>);
+static_assert( std::ranges::random_access_range<std::ranges::reverse_view<test_view<contiguous_iterator>>>);
+static_assert(!std::ranges::contiguous_range<std::ranges::reverse_view<test_view<contiguous_iterator>>>);
+
+static_assert(std::ranges::view<std::ranges::reverse_view<test_view<bidirectional_iterator>>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/size.pass.cpp
new file mode 100644
index 0000000000000..6a86e2c283562
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/size.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: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// constexpr auto size() requires sized_range<V>;
+// constexpr auto size() const requires sized_range<const V>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+// end - begin = 8, but size may return something else.
+template<CopyCategory CC>
+struct BidirSizedRange : std::ranges::view_base {
+ int *ptr_;
+ size_t size_;
+
+ constexpr BidirSizedRange(int *ptr, size_t size) : ptr_(ptr), size_(size) {}
+ constexpr BidirSizedRange(const BidirSizedRange &) requires (CC == Copyable) = default;
+ constexpr BidirSizedRange(BidirSizedRange &&) requires (CC == MoveOnly) = default;
+ constexpr BidirSizedRange& operator=(const BidirSizedRange &) requires (CC == Copyable) = default;
+ constexpr BidirSizedRange& operator=(BidirSizedRange &&) requires (CC == MoveOnly) = default;
+
+ constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{ptr_}; }
+ constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{ptr_}; }
+ constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{ptr_ + 8}; }
+ constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{ptr_ + 8}; }
+
+ constexpr size_t size() const { return size_; }
+};
+
+constexpr bool test() {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // Non-common, non-const bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSizedRange<Copyable>{buffer, 4});
+ assert(std::ranges::size(rev) == 4);
+ assert(rev.size() == 4);
+ assert(std::move(rev).size() == 4);
+
+ ASSERT_SAME_TYPE(decltype(rev.size()), size_t);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).size()), size_t);
+ }
+ // Non-common, const bidirectional range.
+ {
+ const auto rev = std::ranges::reverse_view(BidirSizedRange<Copyable>{buffer, 4});
+ assert(std::ranges::size(rev) == 4);
+ assert(rev.size() == 4);
+ assert(std::move(rev).size() == 4);
+
+ ASSERT_SAME_TYPE(decltype(rev.size()), size_t);
+ ASSERT_SAME_TYPE(decltype(std::move(rev).size()), size_t);
+ }
+ // Non-common, non-const (move only) bidirectional range.
+ {
+ auto rev = std::ranges::reverse_view(BidirSizedRange<MoveOnly>{buffer, 4});
+ assert(std::move(rev).size() == 4);
+
+ ASSERT_SAME_TYPE(decltype(std::move(rev).size()), size_t);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/types.h b/libcxx/test/std/ranges/range.adaptors/range.reverse/types.h
new file mode 100644
index 0000000000000..08454607f0c79
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/types.h
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_REVERSE_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_REVERSE_TYPES_H
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+struct BidirRange : std::ranges::view_base {
+ int *ptr_;
+
+ constexpr BidirRange(int *ptr) : ptr_(ptr) {}
+
+ constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{ptr_}; }
+ constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{ptr_}; }
+ constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{ptr_ + 8}; }
+ constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{ptr_ + 8}; }
+};
+
+enum CopyCategory { MoveOnly, Copyable };
+template<CopyCategory CC>
+struct BidirSentRange : std::ranges::view_base {
+ using sent_t = sentinel_wrapper<bidirectional_iterator<int*>>;
+ using sent_const_t = sentinel_wrapper<bidirectional_iterator<const int*>>;
+
+ int *ptr_;
+
+ constexpr BidirSentRange(int *ptr) : ptr_(ptr) {}
+ constexpr BidirSentRange(const BidirSentRange &) requires (CC == Copyable) = default;
+ constexpr BidirSentRange(BidirSentRange &&) requires (CC == MoveOnly) = default;
+ constexpr BidirSentRange& operator=(const BidirSentRange &) requires (CC == Copyable) = default;
+ constexpr BidirSentRange& operator=(BidirSentRange &&) requires (CC == MoveOnly) = default;
+
+ constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{ptr_}; }
+ constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{ptr_}; }
+ constexpr sent_t end() { return sent_t{bidirectional_iterator<int*>{ptr_ + 8}}; }
+ constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator<const int*>{ptr_ + 8}}; }
+};
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_REVERSE_TYPES_H
More information about the libcxx-commits
mailing list