Skip to content

Commit 9d982c6

Browse files
committed
[libcxx][ranges] Add ranges::reverse_view.
Differential Revision: https://reviews.llvm.org/D107096
1 parent 706bd12 commit 9d982c6

File tree

16 files changed

+822
-1
lines changed

16 files changed

+822
-1
lines changed

libcxx/docs/Status/RangesPaper.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,4 @@ Section,Description,Dependencies,Assignee,Complete
146146
`[range.split] <http://wg21.link/range.split>`_,split_view,[range.all],Zoe Carver,In Progress
147147
`[range.counted] <http://wg21.link/range.counted>`_,view::counted,[range.subrange],Zoe Carver,Not started
148148
`[range.common] <http://wg21.link/range.common>`_,common_view,[range.all],Zoe Carver,✅
149-
`[range.reverse] <http://wg21.link/range.reverse>`_,reverse_view,[range.all],Unassigned,Not started
149+
`[range.reverse] <http://wg21.link/range.reverse>`_,reverse_view,[range.all],Zoe Carver,✅

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ set(files
199199
__ranges/enable_view.h
200200
__ranges/non_propagating_cache.h
201201
__ranges/ref_view.h
202+
__ranges/reverse_view.h
203+
__ranges/take_view.h
202204
__ranges/single_view.h
203205
__ranges/size.h
204206
__ranges/subrange.h
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
#ifndef _LIBCPP___RANGES_REVERSE_VIEW_H
10+
#define _LIBCPP___RANGES_REVERSE_VIEW_H
11+
12+
#include <__config>
13+
#include <__iterator/concepts.h>
14+
#include <__iterator/next.h>
15+
#include <__iterator/reverse_iterator.h>
16+
#include <__ranges/access.h>
17+
#include <__ranges/all.h>
18+
#include <__ranges/concepts.h>
19+
#include <__ranges/enable_borrowed_range.h>
20+
#include <__ranges/non_propagating_cache.h>
21+
#include <__ranges/size.h>
22+
#include <__ranges/view_interface.h>
23+
#include <concepts>
24+
#include <type_traits>
25+
26+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27+
#pragma GCC system_header
28+
#endif
29+
30+
_LIBCPP_BEGIN_NAMESPACE_STD
31+
32+
#if !defined(_LIBCPP_HAS_NO_RANGES)
33+
34+
namespace ranges {
35+
template<view _View>
36+
requires bidirectional_range<_View>
37+
class reverse_view : public view_interface<reverse_view<_View>> {
38+
// We cache begin() whenever ranges::next is not guaranteed O(1) to provide an
39+
// amortized O(1) begin() method.
40+
static constexpr bool _UseCache = !random_access_range<_View> && !common_range<_View>;
41+
using _Cache = _If<_UseCache, __non_propagating_cache<reverse_iterator<iterator_t<_View>>>, __empty_cache>;
42+
[[no_unique_address]] _Cache __cached_begin_ = _Cache();
43+
[[no_unique_address]] _View __base_ = _View();
44+
45+
public:
46+
_LIBCPP_HIDE_FROM_ABI
47+
reverse_view() requires default_initializable<_View> = default;
48+
49+
_LIBCPP_HIDE_FROM_ABI
50+
constexpr explicit reverse_view(_View __view) : __base_(_VSTD::move(__view)) {}
51+
52+
_LIBCPP_HIDE_FROM_ABI
53+
constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
54+
55+
_LIBCPP_HIDE_FROM_ABI
56+
constexpr _View base() && { return _VSTD::move(__base_); }
57+
58+
_LIBCPP_HIDE_FROM_ABI
59+
constexpr reverse_iterator<iterator_t<_View>> begin() {
60+
if constexpr (_UseCache)
61+
if (__cached_begin_.__has_value())
62+
return *__cached_begin_;
63+
64+
auto __tmp = _VSTD::make_reverse_iterator(ranges::next(ranges::begin(__base_), ranges::end(__base_)));
65+
if constexpr (_UseCache)
66+
__cached_begin_.__set(__tmp);
67+
return __tmp;
68+
}
69+
70+
_LIBCPP_HIDE_FROM_ABI
71+
constexpr reverse_iterator<iterator_t<_View>> begin() requires common_range<_View> {
72+
return _VSTD::make_reverse_iterator(ranges::end(__base_));
73+
}
74+
75+
_LIBCPP_HIDE_FROM_ABI
76+
constexpr auto begin() const requires common_range<const _View> {
77+
return _VSTD::make_reverse_iterator(ranges::end(__base_));
78+
}
79+
80+
_LIBCPP_HIDE_FROM_ABI
81+
constexpr reverse_iterator<iterator_t<_View>> end() {
82+
return _VSTD::make_reverse_iterator(ranges::begin(__base_));
83+
}
84+
85+
_LIBCPP_HIDE_FROM_ABI
86+
constexpr auto end() const requires common_range<const _View> {
87+
return _VSTD::make_reverse_iterator(ranges::begin(__base_));
88+
}
89+
90+
_LIBCPP_HIDE_FROM_ABI
91+
constexpr auto size() requires sized_range<_View> {
92+
return ranges::size(__base_);
93+
}
94+
95+
_LIBCPP_HIDE_FROM_ABI
96+
constexpr auto size() const requires sized_range<const _View> {
97+
return ranges::size(__base_);
98+
}
99+
};
100+
101+
template<class _Range>
102+
reverse_view(_Range&&) -> reverse_view<views::all_t<_Range>>;
103+
104+
template<class _Tp>
105+
inline constexpr bool enable_borrowed_range<reverse_view<_Tp>> = enable_borrowed_range<_Tp>;
106+
} // namespace ranges
107+
108+
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
109+
110+
_LIBCPP_END_NAMESPACE_STD
111+
112+
#endif // _LIBCPP___RANGES_REVERSE_VIEW_H

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ module std [system] {
631631
module enable_view { private header "__ranges/enable_view.h" }
632632
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
633633
module ref_view { private header "__ranges/ref_view.h" }
634+
module reverse_view { private header "__ranges/reverse_view.h" }
634635
module size { private header "__ranges/size.h" }
635636
module single_view { private header "__ranges/single_view.h" }
636637
module subrange { private header "__ranges/subrange.h" }

libcxx/include/ranges

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ namespace std::ranges {
154154
requires (!common_range<V> && copyable<iterator_t<V>>)
155155
class common_view;
156156
157+
// [range.reverse], reverse view
158+
template<view V>
159+
requires bidirectional_range<V>
160+
class reverse_view;
161+
162+
template<class T>
163+
inline constexpr bool enable_borrowed_range<reverse_view<T>> = enable_borrowed_range<T>;
164+
157165
template<class T>
158166
inline constexpr bool enable_borrowed_range<common_view<T>> = enable_borrowed_range<T>;
159167
@@ -188,6 +196,8 @@ namespace std::ranges {
188196
#include <__ranges/enable_borrowed_range.h>
189197
#include <__ranges/enable_view.h>
190198
#include <__ranges/ref_view.h>
199+
#include <__ranges/reverse_view.h>
200+
#include <__ranges/take_view.h>
191201
#include <__ranges/single_view.h>
192202
#include <__ranges/size.h>
193203
#include <__ranges/subrange.h>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// REQUIRES: modules-build
11+
12+
// WARNING: This test was generated by 'generate_private_header_tests.py'
13+
// and should not be edited manually.
14+
15+
// expected-error@*:* {{use of private header from outside its module: '__ranges/reverse_view.h'}}
16+
#include <__ranges/reverse_view.h>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
// UNSUPPORTED: libcpp-no-concepts
11+
// UNSUPPORTED: gcc-10
12+
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
13+
14+
// constexpr V base() const& requires copy_constructible<V> { return base_; }
15+
// constexpr V base() && { return std::move(base_); }
16+
17+
#include <ranges>
18+
#include <cassert>
19+
20+
#include "test_macros.h"
21+
#include "types.h"
22+
23+
constexpr bool test() {
24+
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
25+
26+
// Test common ranges.
27+
{
28+
// Test non-const.
29+
{
30+
auto rev = std::ranges::reverse_view(BidirRange{buffer});
31+
assert(rev.base().ptr_ == buffer);
32+
assert(std::move(rev).base().ptr_ == buffer);
33+
34+
ASSERT_SAME_TYPE(decltype(rev.base()), BidirRange);
35+
ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirRange);
36+
}
37+
// Test const.
38+
{
39+
const auto rev = std::ranges::reverse_view(BidirRange{buffer});
40+
assert(rev.base().ptr_ == buffer);
41+
assert(std::move(rev).base().ptr_ == buffer);
42+
43+
ASSERT_SAME_TYPE(decltype(rev.base()), BidirRange);
44+
ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirRange);
45+
}
46+
}
47+
// Test non-common ranges.
48+
{
49+
// Test non-const (also move only).
50+
{
51+
auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer});
52+
assert(std::move(rev).base().ptr_ == buffer);
53+
54+
ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange<MoveOnly>);
55+
}
56+
// Test const.
57+
{
58+
const auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer});
59+
assert(rev.base().ptr_ == buffer);
60+
assert(std::move(rev).base().ptr_ == buffer);
61+
62+
ASSERT_SAME_TYPE(decltype(rev.base()), BidirSentRange<Copyable>);
63+
ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange<Copyable>);
64+
}
65+
}
66+
67+
return true;
68+
}
69+
70+
int main(int, char**) {
71+
test();
72+
static_assert(test());
73+
74+
return 0;
75+
}

0 commit comments

Comments
 (0)