diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -146,4 +146,4 @@ `[range.split] `_,split_view,[range.all],Zoe Carver,In Progress `[range.counted] `_,view::counted,[range.subrange],Zoe Carver,Not started `[range.common] `_,common_view,[range.all],Zoe Carver,✅ -`[range.reverse] `_,reverse_view,[range.all],Unassigned,Not started +`[range.reverse] `_,reverse_view,[range.all],Zoe Carver,✅ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -199,6 +199,8 @@ __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 --- /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 +#include + +#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 + requires bidirectional_range<_View> + class reverse_view : public view_interface> { + // 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>>, __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> 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> begin() requires common_range<_View> { + return _VSTD::make_reverse_iterator(ranges::end(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto begin() const requires common_range { + return _VSTD::make_reverse_iterator(ranges::end(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI + constexpr reverse_iterator> end() { + return _VSTD::make_reverse_iterator(ranges::begin(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto end() const requires common_range { + 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 { + return ranges::size(__base_); + } + }; + + template + reverse_view(_Range&&) -> reverse_view>; + + template + inline constexpr bool enable_borrowed_range> = 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 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -631,6 +631,7 @@ 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 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -154,6 +154,14 @@ requires (!common_range && copyable>) class common_view; + // [range.reverse], reverse view + template + requires bidirectional_range + class reverse_view; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + template inline constexpr bool enable_borrowed_range> = enable_borrowed_range; @@ -188,6 +196,8 @@ #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 --- /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 --- /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 { return base_; } +// constexpr V base() && { return std::move(base_); } + +#include +#include + +#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{buffer}); + assert(std::move(rev).base().ptr_ == buffer); + + ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange); + } + // Test const. + { + const auto rev = std::ranges::reverse_view(BidirSentRange{buffer}); + assert(rev.base().ptr_ == buffer); + assert(std::move(rev).base().ptr_ == buffer); + + ASSERT_SAME_TYPE(decltype(rev.base()), BidirSentRange); + ASSERT_SAME_TYPE(decltype(std::move(rev).base()), BidirSentRange); + } + } + + 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 --- /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> begin(); +// constexpr reverse_iterator> begin() requires common_range; +// constexpr auto begin() const requires common_range; + +#include +#include + +#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::ptrdiff_t difference_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(ptr_ + 8)); } + auto end() const { return sentinel_wrapper(CountedIter(ptr_ + 8)); } +}; + +struct RASentRange : std::ranges::view_base { + using sent_t = sentinel_wrapper>; + using sent_const_t = sentinel_wrapper>; + + int *ptr_; + + constexpr RASentRange(int *ptr) : ptr_(ptr) {} + + constexpr random_access_iterator begin() { return random_access_iterator{ptr_}; } + constexpr random_access_iterator begin() const { return random_access_iterator{ptr_}; } + constexpr sent_t end() { return sent_t{random_access_iterator{ptr_ + 8}}; } + constexpr sent_const_t end() const { return sent_const_t{random_access_iterator{ptr_ + 8}}; } +}; + +template +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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator>); + } + // 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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator>); + } + // Non-common, non-const (move only) bidirectional range. + { + auto rev = std::ranges::reverse_view(BidirSentRange{buffer}); + assert(std::move(rev).begin().base().base() == buffer + 8); + + ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator>); + } + // Non-common, non-const bidirectional range. + { + auto rev = std::ranges::reverse_view(BidirSentRange{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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator>); + } + // 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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator>); + } + { + static_assert( BeginInvocable< std::ranges::reverse_view>>); + static_assert(!BeginInvocable>>); + } + + 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 --- /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 +// inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + +#include +#include + +#include "test_iterators.h" + +struct View : std::ranges::view_base { + friend int* begin(View&); + friend int* begin(View const&); + friend sentinel_wrapper end(View&); + friend sentinel_wrapper end(View const&); +}; + +struct BorrowableView : std::ranges::view_base { + friend int* begin(BorrowableView&); + friend int* begin(BorrowableView const&); + friend sentinel_wrapper end(BorrowableView&); + friend sentinel_wrapper end(BorrowableView const&); +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(!std::ranges::enable_borrowed_range>); +static_assert( std::ranges::enable_borrowed_range>); 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 --- /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 +// reverse_view(R&&) -> reverse_view>; + +#include +#include +#include + +#include "test_iterators.h" + +struct View : std::ranges::view_base { + friend int* begin(View&); + friend int* begin(View const&); + friend sentinel_wrapper end(View&); + friend sentinel_wrapper end(View const&); +}; + +struct Range { + friend int* begin(Range&); + friend int* begin(Range const&); + friend sentinel_wrapper end(Range&); + friend sentinel_wrapper end(Range const&); +}; + +struct BorrowedRange { + friend int* begin(BorrowedRange&); + friend int* begin(BorrowedRange const&); + friend sentinel_wrapper end(BorrowedRange&); + friend sentinel_wrapper end(BorrowedRange const&); +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +void testCTAD() { + View v; + Range r; + BorrowedRange br; + static_assert(std::same_as< + decltype(std::ranges::reverse_view(v)), + std::ranges::reverse_view + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(r)), + std::ranges::reverse_view> + >); + // 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> + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(std::move(br))), + std::ranges::reverse_view, 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 --- /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 = default; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +enum CtorKind { DefaultCtor, PtrCtor }; +template +struct BidirRangeWith : std::ranges::view_base { + int *ptr_ = nullptr; + + constexpr BidirRangeWith() requires (CK == DefaultCtor) = default; + constexpr BidirRangeWith(int *ptr); + + constexpr bidirectional_iterator begin() { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator end() { return bidirectional_iterator{ptr_ + 8}; } + constexpr bidirectional_iterator end() const { return bidirectional_iterator{ptr_ + 8}; } +}; + +constexpr bool test() { + { + static_assert( std::default_initializable>>); + static_assert(!std::default_initializable>>); + } + + { + std::ranges::reverse_view> rev; + assert(rev.base().ptr_ == nullptr); + } + { + const std::ranges::reverse_view> 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 --- /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 +#include + +#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 rev(r); + assert(rev.base().ptr_ == buffer); + } + { + const BidirRange r{buffer}; + const std::ranges::reverse_view rev(r); + assert(rev.base().ptr_ == buffer); + } + { + std::ranges::reverse_view> rev(BidirSentRange{buffer}); + assert(std::move(rev).base().ptr_ == buffer); + } + { + const std::ranges::reverse_view> rev(BidirSentRange{buffer}); + assert(rev.base().ptr_ == buffer); + } + { + // Make sure this ctor is marked as "explicit". + static_assert( std::is_constructible_v, BidirRange>); + static_assert(!std::is_convertible_v, 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 --- /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> end(); +// constexpr auto end() const requires common_range; + +#include +#include + +#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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator>); + } + // 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>); + ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator>); + } + // Non-common, non-const (move only) bidirectional range. + { + auto rev = std::ranges::reverse_view(BidirSentRange{buffer}); + assert(std::move(rev).end().base().base() == buffer); + + ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator>); + } + // Non-common, const bidirectional range. + { + auto rev = std::ranges::reverse_view(BidirSentRange{buffer}); + assert(rev.end().base().base() == buffer); + assert(std::move(rev).end().base().base() == buffer); + + ASSERT_SAME_TYPE(decltype(rev.end()), std::reverse_iterator>); + ASSERT_SAME_TYPE(decltype(std::move(rev).end()), std::reverse_iterator>); + } + + 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 --- /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 + +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +static_assert( std::ranges::bidirectional_range>>); +static_assert( std::ranges::random_access_range>>); +static_assert( std::ranges::random_access_range>>); +static_assert(!std::ranges::contiguous_range>>); + +static_assert(std::ranges::view>>); 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 --- /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; +// constexpr auto size() const requires sized_range; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +// end - begin = 8, but size may return something else. +template +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 begin() { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator end() { return bidirectional_iterator{ptr_ + 8}; } + constexpr bidirectional_iterator end() const { return bidirectional_iterator{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{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{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{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 --- /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 begin() { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator end() { return bidirectional_iterator{ptr_ + 8}; } + constexpr bidirectional_iterator end() const { return bidirectional_iterator{ptr_ + 8}; } +}; + +enum CopyCategory { MoveOnly, Copyable }; +template +struct BidirSentRange : std::ranges::view_base { + using sent_t = sentinel_wrapper>; + using sent_const_t = sentinel_wrapper>; + + 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 begin() { return bidirectional_iterator{ptr_}; } + constexpr bidirectional_iterator begin() const { return bidirectional_iterator{ptr_}; } + constexpr sent_t end() { return sent_t{bidirectional_iterator{ptr_ + 8}}; } + constexpr sent_const_t end() const { return sent_const_t{bidirectional_iterator{ptr_ + 8}}; } +}; + +#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_REVERSE_TYPES_H