[libcxx][ranges] Add ranges::take_view.

Differential Revision: https://reviews.llvm.org/D106507
This commit is contained in:
zoecarver 2021-05-26 08:59:14 -07:00
parent f623dc9a8c
commit 0f4b41e038
20 changed files with 993 additions and 3 deletions

View File

@ -139,7 +139,7 @@ Section,Description,Dependencies,Assignee,Complete
`[range.filter] <http://wg21.link/range.filter>`_,filter_view,[range.all],Louis Dionne,Not started
`[range.transform] <http://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,✅
`[range.iota] <http://wg21.link/range.iota>`_,iota_view,[range.all],Louis Dionne,Not started
`[range.take] <http://wg21.link/range.take>`_,take_view,[range.all],Zoe Carver,In Progress
`[range.take] <http://wg21.link/range.take>`_,take_view,[range.all],Zoe Carver,
`[range.join] <http://wg21.link/range.join>`_,join_view,[range.all],Christopher Di Bella,Not started
`[range.empty] <http://wg21.link/range.empty>`_,`empty_view <https://llvm.org/D103208>`_,[view.interface],Zoe Carver,✅
`[range.single] <http://wg21.link/range.single>`_,single_view,[view.interface],Zoe Carver,In Progress

1 Section Description Dependencies Assignee Complete
139
140
141
142
143
144
145

View File

@ -197,6 +197,7 @@ set(files
__ranges/enable_view.h
__ranges/non_propagating_cache.h
__ranges/ref_view.h
__ranges/take_view.h
__ranges/size.h
__ranges/subrange.h
__ranges/transform_view.h

View File

@ -0,0 +1,184 @@
// -*- 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_TAKE_VIEW_H
#define _LIBCPP___RANGES_TAKE_VIEW_H
#include <__algorithm/min.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/counted_iterator.h>
#include <__iterator/default_sentinel.h>
#include <__iterator/iterator_traits.h>
#include <__ranges/access.h>
#include <__ranges/all.h>
#include <__ranges/concepts.h>
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/size.h>
#include <__ranges/view_interface.h>
#include <__utility/move.h>
#include <concepts>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_RANGES)
namespace ranges {
template<view _View>
class take_view : public view_interface<take_view<_View>> {
[[no_unique_address]] _View __base_ = _View();
range_difference_t<_View> __count_ = 0;
template<bool> class __sentinel;
public:
_LIBCPP_HIDE_FROM_ABI
take_view() requires default_initializable<_View> = default;
_LIBCPP_HIDE_FROM_ABI
constexpr take_view(_View __base, range_difference_t<_View> __count)
: __base_(_VSTD::move(__base)), __count_(__count) {}
_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 auto begin() requires (!__simple_view<_View>) {
if constexpr (sized_range<_View>) {
if constexpr (random_access_range<_View>) {
return ranges::begin(__base_);
} else {
using _DifferenceT = range_difference_t<_View>;
auto __size = size();
return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size));
}
} else {
return counted_iterator(ranges::begin(__base_), __count_);
}
}
_LIBCPP_HIDE_FROM_ABI
constexpr auto begin() const requires range<const _View> {
if constexpr (sized_range<const _View>) {
if constexpr (random_access_range<const _View>) {
return ranges::begin(__base_);
} else {
using _DifferenceT = range_difference_t<const _View>;
auto __size = size();
return counted_iterator(ranges::begin(__base_), static_cast<_DifferenceT>(__size));
}
} else {
return counted_iterator(ranges::begin(__base_), __count_);
}
}
_LIBCPP_HIDE_FROM_ABI
constexpr auto end() requires (!__simple_view<_View>) {
if constexpr (sized_range<_View>) {
if constexpr (random_access_range<_View>) {
return ranges::begin(__base_) + size();
} else {
return default_sentinel;
}
} else {
return __sentinel<false>{ranges::end(__base_)};
}
}
_LIBCPP_HIDE_FROM_ABI
constexpr auto end() const requires range<const _View> {
if constexpr (sized_range<const _View>) {
if constexpr (random_access_range<const _View>) {
return ranges::begin(__base_) + size();
} else {
return default_sentinel;
}
} else {
return __sentinel<true>{ranges::end(__base_)};
}
}
_LIBCPP_HIDE_FROM_ABI
constexpr auto size() requires sized_range<_View> {
auto __n = ranges::size(__base_);
// TODO: use ranges::min here.
return _VSTD::min(__n, static_cast<decltype(__n)>(__count_));
}
_LIBCPP_HIDE_FROM_ABI
constexpr auto size() const requires sized_range<const _View> {
auto __n = ranges::size(__base_);
// TODO: use ranges::min here.
return _VSTD::min(__n, static_cast<decltype(__n)>(__count_));
}
};
template<view _View>
template<bool _Const>
class take_view<_View>::__sentinel {
using _Base = __maybe_const<_Const, _View>;
template<bool _OtherConst>
using _Iter = counted_iterator<iterator_t<__maybe_const<_OtherConst, _View>>>;
[[no_unique_address]] sentinel_t<_Base> __end_ = sentinel_t<_Base>();
template<bool>
friend class take_view<_View>::__sentinel;
public:
_LIBCPP_HIDE_FROM_ABI
__sentinel() = default;
_LIBCPP_HIDE_FROM_ABI
constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(_VSTD::move(__end)) {}
_LIBCPP_HIDE_FROM_ABI
constexpr __sentinel(__sentinel<!_Const> __s)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(_VSTD::move(__s.__end_)) {}
_LIBCPP_HIDE_FROM_ABI
constexpr sentinel_t<_Base> base() const { return __end_; }
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) {
return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
}
template<bool _OtherConst = !_Const>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) {
return __lhs.count() == 0 || __lhs.base() == __rhs.__end_;
}
};
template<class _Range>
take_view(_Range&&, range_difference_t<_Range>) -> take_view<views::all_t<_Range>>;
template<class _Tp>
inline constexpr bool enable_borrowed_range<take_view<_Tp>> = enable_borrowed_range<_Tp>;
} // namespace ranges
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___RANGES_TAKE_VIEW_H

View File

@ -628,6 +628,7 @@ module std [system] {
module ref_view { private header "__ranges/ref_view.h" }
module size { private header "__ranges/size.h" }
module subrange { private header "__ranges/subrange.h" }
module take_view { private header "__ranges/take_view.h" }
module transform_view { private header "__ranges/transform_view.h" }
module view_interface { private header "__ranges/view_interface.h" }
}

View File

@ -156,6 +156,12 @@ namespace std::ranges {
template<class T>
inline constexpr bool enable_borrowed_range<common_view<T>> = enable_borrowed_range<T>;
// [range.take], take view
template<view> class take_view;
template<class T>
inline constexpr bool enable_borrowed_range<take_view<T>> = enable_borrowed_range<T>;
}
*/
@ -173,6 +179,7 @@ namespace std::ranges {
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
#include <__ranges/ref_view.h>
#include <__ranges/take_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__ranges/transform_view.h>

View File

@ -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/take_view.h'}}
#include <__ranges/take_view.h>

View File

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// constexpr V base() const& requires copy_constructible<V>;
// constexpr V base() &&;
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "types.h"
constexpr bool hasLValueQualifiedBase(auto&& view) {
return requires { view.base(); };
}
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
std::ranges::take_view<CopyableView> tv(CopyableView{buffer}, 0);
assert(tv.base().ptr_ == buffer);
assert(std::move(tv).base().ptr_ == buffer);
ASSERT_SAME_TYPE(decltype(tv.base()), CopyableView);
ASSERT_SAME_TYPE(decltype(std::move(tv).base()), CopyableView);
static_assert(hasLValueQualifiedBase(tv));
}
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 1);
assert(std::move(tv).base().ptr_ == buffer);
ASSERT_SAME_TYPE(decltype(std::move(tv).base()), ContiguousView);
static_assert(!hasLValueQualifiedBase(tv));
}
{
const std::ranges::take_view<CopyableView> tv(CopyableView{buffer}, 2);
assert(tv.base().ptr_ == buffer);
assert(std::move(tv).base().ptr_ == buffer);
ASSERT_SAME_TYPE(decltype(tv.base()), CopyableView);
ASSERT_SAME_TYPE(decltype(std::move(tv).base()), CopyableView);
static_assert(hasLValueQualifiedBase(tv));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -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 auto begin() requires (!simple-view<V>);
// constexpr auto begin() const requires range<const V>;
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
#include "types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// sized_range && random_access_iterator
{
std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 4);
assert(tv.begin() == begin(SizedRandomAccessView(buffer)));
ASSERT_SAME_TYPE(decltype(tv.begin()), RandomAccessIter);
}
{
const std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 4);
assert(tv.begin() == begin(SizedRandomAccessView(buffer)));
ASSERT_SAME_TYPE(decltype(tv.begin()), RandomAccessIter);
}
// sized_range && !random_access_iterator
{
std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 4);
assert(tv.begin() == std::counted_iterator<ForwardIter>(ForwardIter(buffer), 4));
ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator<ForwardIter>);
}
{
const std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 4);
assert(tv.begin() == std::counted_iterator<ForwardIter>(ForwardIter(buffer), 4));
ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator<ForwardIter>);
}
// !sized_range
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.begin() == std::counted_iterator<int*>(buffer, 4));
ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator<int*>);
}
{
const std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.begin() == std::counted_iterator<int*>(buffer, 4));
ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator<int*>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -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<take_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::take_view<View>>);
static_assert( std::ranges::enable_borrowed_range<std::ranges::take_view<BorrowableView>>);

View File

@ -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>
// take_view(R&&, range_difference_t<R>) -> take_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::take_view(v, 0)),
std::ranges::take_view<View>
>);
static_assert(std::same_as<
decltype(std::ranges::take_view(r, 0)),
std::ranges::take_view<std::ranges::ref_view<Range>>
>);
// std::ranges::take_view(std::move(r), 0) invalid. RValue range must be borrowed.
static_assert(std::same_as<
decltype(std::ranges::take_view(br, 0)),
std::ranges::take_view<std::ranges::ref_view<BorrowedRange>>
>);
static_assert(std::same_as<
decltype(std::ranges::take_view(std::move(br), 0)),
std::ranges::take_view<std::ranges::subrange<
int *, sentinel_wrapper<int *>, std::ranges::subrange_kind::unsized>>
>);
}

View File

@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// take_view() requires default_initializable<V> = default;
// constexpr take_view(V base, range_difference_t<V> count);
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
#include "types.h"
int globalBuffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
template<bool IsDefaultCtorable>
struct DefaultConstructible : std::ranges::view_base {
DefaultConstructible() requires IsDefaultCtorable = default;
DefaultConstructible(int*);
int* begin();
sentinel_wrapper<int*> end();
};
struct SizedRandomAccessViewToGlobal : std::ranges::view_base {
RandomAccessIter begin() { return RandomAccessIter(globalBuffer); }
RandomAccessIter begin() const { return RandomAccessIter(globalBuffer); }
sentinel_wrapper<RandomAccessIter> end() {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(globalBuffer + 8)};
}
sentinel_wrapper<RandomAccessIter> end() const {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(globalBuffer + 8)};
}
};
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
std::ranges::take_view<CopyableView> tv(CopyableView{buffer}, 0);
assert(tv.base().ptr_ == buffer);
assert(tv.begin() == tv.end()); // Checking we have correct size.
}
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 1);
assert(std::move(tv).base().ptr_ == buffer);
assert(std::ranges::next(tv.begin(), 1) == tv.end()); // Checking we have correct size.
}
{
const std::ranges::take_view<CopyableView> tv(CopyableView{buffer}, 2);
assert(tv.base().ptr_ == buffer);
assert(std::ranges::next(tv.begin(), 2) == tv.end()); // Checking we have correct size.
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
// Tests for the default ctor.
static_assert( std::default_initializable<DefaultConstructible<true>>);
static_assert(!std::default_initializable<DefaultConstructible<false>>);
std::ranges::take_view<SizedRandomAccessViewToGlobal> tv;
assert(*tv.base().begin() == 1);
assert(tv.size() == 0);
return 0;
}

View File

@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
// constexpr auto end() requires (!simple-view<V>)
// constexpr auto end() const requires range<const V>
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
#include "types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// sized_range && random_access_iterator
{
std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 0);
assert(tv.end() == std::ranges::next(tv.begin(), 0));
ASSERT_SAME_TYPE(decltype(tv.end()), RandomAccessIter);
}
{
const std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 1);
assert(tv.end() == std::ranges::next(tv.begin(), 1));
ASSERT_SAME_TYPE(decltype(tv.end()), RandomAccessIter);
}
// sized_range && !random_access_iterator
{
std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 2);
assert(tv.end() == std::ranges::next(tv.begin(), 2));
ASSERT_SAME_TYPE(decltype(tv.end()), std::default_sentinel_t);
}
{
const std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 3);
assert(tv.end() == std::ranges::next(tv.begin(), 3));
ASSERT_SAME_TYPE(decltype(tv.end()), std::default_sentinel_t);
}
// !sized_range
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.end() == std::ranges::next(tv.begin(), 4));
// The <sentinel> type.
static_assert(!std::same_as<decltype(tv.end()), std::default_sentinel_t>);
static_assert(!std::same_as<decltype(tv.end()), int*>);
}
{
const std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 5);
assert(tv.end() == std::ranges::next(tv.begin(), 5));
}
// Just to cover the case where count == 8.
{
std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 8);
assert(tv.end() == std::ranges::next(tv.begin(), 8));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
// Range concept conformance tests for take_view.
#include <ranges>
#include <cassert>
#include <concepts>
#include "test_iterators.h"
#include "test_range.h"
static_assert(std::ranges::input_range<std::ranges::take_view<test_view<cpp20_input_iterator>>>);
static_assert(std::ranges::forward_range<std::ranges::take_view<test_view<forward_iterator>>>);
static_assert(std::ranges::bidirectional_range<std::ranges::take_view<test_view<bidirectional_iterator>>>);
static_assert(std::ranges::random_access_range<std::ranges::take_view<test_view<random_access_iterator>>>);
static_assert(std::ranges::contiguous_range<std::ranges::take_view<test_view<contiguous_iterator>>>);

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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
// sentinel() = default;
// constexpr explicit sentinel(sentinel_t<Base> end);
// constexpr sentinel(sentinel<!Const> s)
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "../types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
auto sw = sentinel_wrapper<int *>(buffer + 8); // Note: not 4, but that's OK.
{
const std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.end().base().base() == sw.base());
ASSERT_SAME_TYPE(decltype(tv.end().base()), sentinel_wrapper<int *>);
}
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.end().base().base() == sw.base());
ASSERT_SAME_TYPE(decltype(tv.end().base()), sentinel_wrapper<int *>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// 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
// sentinel() = default;
// constexpr explicit sentinel(sentinel_t<Base> end);
// constexpr sentinel(sentinel<!Const> s)
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "../types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
// Test the default ctor.
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(decltype(tv.end()){} == std::ranges::next(tv.begin(), 4));
}
{
std::ranges::take_view<ContiguousView> nonConst(ContiguousView{buffer}, 5);
const std::ranges::take_view<ContiguousView> tvConst(ContiguousView{buffer}, 5);
auto sent1 = nonConst.end();
// Convert to const. Note, we cannot go the other way.
std::remove_cv_t<decltype(tvConst.end())> sent2 = sent1;
assert(sent1 == std::ranges::next(tvConst.begin(), 5));
assert(sent2 == std::ranges::next(tvConst.begin(), 5));
}
{
std::ranges::take_view<CopyableView> tv(CopyableView{buffer}, 6);
auto sw = sentinel_wrapper<int *>(buffer + 6);
using Sent = decltype(tv.end());
Sent sent = Sent(sw);
assert(sent.base().base() == sw.base());
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// 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
// sentinel() = default;
// constexpr explicit sentinel(sentinel_t<Base> end);
// constexpr sentinel(sentinel<!Const> s)
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "../types.h"
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
{
const std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.end() == std::ranges::next(tv.begin(), 4));
assert(std::ranges::next(tv.begin(), 4) == tv.end());
}
{
std::ranges::take_view<ContiguousView> tv(ContiguousView{buffer}, 4);
assert(tv.end() == std::ranges::next(tv.begin(), 4));
assert(std::ranges::next(tv.begin(), 4) == tv.end());
}
}
{
std::ranges::take_view<ContiguousView> tvNonConst(ContiguousView{buffer}, 4);
const std::ranges::take_view<ContiguousView> tvConst(ContiguousView{buffer}, 4);
assert(tvNonConst.end() == std::ranges::next(tvConst.begin(), 4));
assert(std::ranges::next(tvConst.begin(), 4) == tvNonConst.end());
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// 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 "test_iterators.h"
#include "test_range.h"
#include "types.h"
template<class T>
concept SizeEnabled = requires(const std::ranges::take_view<T>& tv) {
tv.size();
};
constexpr bool test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
static_assert( SizeEnabled<SizedRandomAccessView>);
static_assert(!SizeEnabled<CopyableView>);
}
{
std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 0);
assert(tv.size() == 0);
}
{
const std::ranges::take_view<SizedRandomAccessView> tv(SizedRandomAccessView{buffer}, 2);
assert(tv.size() == 2);
}
{
std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 4);
assert(tv.size() == 4);
}
{
const std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 6);
assert(tv.size() == 6);
}
{
std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 8);
assert(tv.size() == 8);
}
{
const std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 8);
assert(tv.size() == 8);
}
{
std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 10);
assert(tv.size() == 8);
}
{
const std::ranges::take_view<SizedForwardView> tv(SizedForwardView{buffer}, 10);
assert(tv.size() == 8);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,75 @@
#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_TYPES_H
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_TYPES_H
#include <ranges>
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
struct ContiguousView : std::ranges::view_base {
int *ptr_;
constexpr ContiguousView(int* ptr) : ptr_(ptr) {}
ContiguousView(ContiguousView&&) = default;
ContiguousView& operator=(ContiguousView&&) = default;
constexpr int* begin() {return ptr_;}
constexpr int* begin() const {return ptr_;}
constexpr sentinel_wrapper<int*> end() {return sentinel_wrapper<int*>{ptr_ + 8};}
constexpr sentinel_wrapper<int*> end() const {return sentinel_wrapper<int*>{ptr_ + 8};}
};
struct CopyableView : std::ranges::view_base {
int *ptr_;
constexpr CopyableView(int* ptr) : ptr_(ptr) {}
constexpr int* begin() {return ptr_;}
constexpr int* begin() const {return ptr_;}
constexpr sentinel_wrapper<int*> end() {return sentinel_wrapper<int*>{ptr_ + 8};}
constexpr sentinel_wrapper<int*> end() const {return sentinel_wrapper<int*>{ptr_ + 8};}
};
using ForwardIter = forward_iterator<int*>;
struct SizedForwardView : std::ranges::view_base {
int *ptr_;
constexpr SizedForwardView(int* ptr) : ptr_(ptr) {}
constexpr friend ForwardIter begin(SizedForwardView& view) { return ForwardIter(view.ptr_); }
constexpr friend ForwardIter begin(SizedForwardView const& view) { return ForwardIter(view.ptr_); }
constexpr friend sentinel_wrapper<ForwardIter> end(SizedForwardView& view) {
return sentinel_wrapper<ForwardIter>{ForwardIter(view.ptr_ + 8)};
}
constexpr friend sentinel_wrapper<ForwardIter> end(SizedForwardView const& view) {
return sentinel_wrapper<ForwardIter>{ForwardIter(view.ptr_ + 8)};
}
};
// Required to make SizedForwardView a sized view.
constexpr auto operator-(sentinel_wrapper<ForwardIter> sent, ForwardIter iter) {
return sent.base().base() - iter.base();
}
constexpr auto operator-(ForwardIter iter, sentinel_wrapper<ForwardIter> sent) {
return iter.base() - sent.base().base();
}
using RandomAccessIter = random_access_iterator<int*>;
struct SizedRandomAccessView : std::ranges::view_base {
int *ptr_;
constexpr SizedRandomAccessView(int* ptr) : ptr_(ptr) {}
constexpr friend RandomAccessIter begin(SizedRandomAccessView& view) { return RandomAccessIter(view.ptr_); }
constexpr friend RandomAccessIter begin(SizedRandomAccessView const& view) { return RandomAccessIter(view.ptr_); }
constexpr friend sentinel_wrapper<RandomAccessIter> end(SizedRandomAccessView& view) {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(view.ptr_ + 8)};
}
constexpr friend sentinel_wrapper<RandomAccessIter> end(SizedRandomAccessView const& view) {
return sentinel_wrapper<RandomAccessIter>{RandomAccessIter(view.ptr_ + 8)};
}
};
// Required to make SizedRandomAccessView a sized view.
constexpr auto operator-(sentinel_wrapper<RandomAccessIter> sent, RandomAccessIter iter) {
return sent.base().base() - iter.base();
}
constexpr auto operator-(RandomAccessIter iter, sentinel_wrapper<RandomAccessIter> sent) {
return iter.base() - sent.base().base();
}
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_TYPES_H

View File

@ -14,6 +14,7 @@
// CTAD tests.
#include <ranges>
#include <concepts>
#include "test_macros.h"
#include "types.h"

View File

@ -21,7 +21,6 @@ struct sentinel {
bool operator==(std::input_or_output_iterator auto const&) const;
};
// clang-format off
template <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_range {
@ -54,6 +53,13 @@ struct test_non_const_common_range {
I<int*> end();
};
// clang-format on
template <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_view : std::ranges::view_base {
I<int*> begin();
I<int const*> begin() const;
sentinel end();
sentinel end() const;
};
#endif // LIBCXX_TEST_SUPPORT_TEST_RANGE_H