Skip to content

Commit

Permalink
[libc++] [ranges] Implement ranges::cdata.
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D117044
  • Loading branch information
Arthur O'Dwyer committed Jan 13, 2022
1 parent 55fcbf0 commit 483f7f5
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
6 changes: 3 additions & 3 deletions libcxx/docs/Status/RangesPaper.csv
Expand Up @@ -97,7 +97,7 @@ Section,Description,Dependencies,Assignee,Complete
| `ranges::ssize <https://llvm.org/D101189>`_
| `ranges::empty <https://llvm.org/D101193>`_
| `ranges::data <https://llvm.org/D101476>`_
| ranges::cdata",[iterator.concepts],Christopher Di Bella and Zoe Carver,In progress
| `ranges::cdata <https://llvm.org/D117044>`_",[iterator.concepts],Christopher Di Bella and Zoe Carver,In progress
`[range.range] <http://wg21.link/range.range>`_,"| `ranges::range <https://llvm.org/D100269>`_
| `ranges::borrowed_range <https://llvm.org/D102426>`_
| `ranges::enable_borrowed_range <https://llvm.org/D90999>`_
Expand All @@ -114,12 +114,12 @@ Section,Description,Dependencies,Assignee,Complete
`[range.view] <http://wg21.link/range.view>`_,"| `ranges::enable_view <https://llvm.org/D101547>`_
| `ranges::view_base <https://llvm.org/D101547>`_
| `ranges::view <https://llvm.org/D101547>`_",[range.range],Louis Dionne,✅
`[range.refinements] <http://wg21.link/range.refinements>`_,"| ranges::output_range
`[range.refinements] <http://wg21.link/range.refinements>`_,"| `ranges::output_range <https://llvm.org/D106704>`_
| `ranges::input_range <https://llvm.org/D100271>`_
| `ranges::forward_range: `D100275 <https://llvm.org/D100275>`_
| `ranges::bidirectional_range <https://llvm.org/D100278>`_
| `ranges::random_access_range <https://llvm.org/D101316>`_
| ranges::contiguous_range
| `ranges::contiguous_range <https://llvm.org/D104262>`_
| `ranges::common_range <https://llvm.org/D100269>`_",[range.range],Christopher Di Bella,✅
`[range.refinements]`_,`ranges::viewable_range <https://llvm.org/D105816>`_,[range.range],Louis Dionne,✅
`[range.utility.helpers] <http://wg21.link/range.utility.helpers>`_,"| *simple-view*
Expand Down
28 changes: 28 additions & 0 deletions libcxx/include/__ranges/data.h
Expand Up @@ -71,6 +71,34 @@ inline namespace __cpo {
} // namespace __cpo
} // namespace ranges

// [range.prim.cdata]

namespace ranges {
namespace __cdata {
struct __fn {
template <class _Tp>
requires is_lvalue_reference_v<_Tp&&>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
constexpr auto operator()(_Tp&& __t) const
noexcept(noexcept(ranges::data(static_cast<const remove_reference_t<_Tp>&>(__t))))
-> decltype( ranges::data(static_cast<const remove_reference_t<_Tp>&>(__t)))
{ return ranges::data(static_cast<const remove_reference_t<_Tp>&>(__t)); }

template <class _Tp>
requires is_rvalue_reference_v<_Tp&&>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
constexpr auto operator()(_Tp&& __t) const
noexcept(noexcept(ranges::data(static_cast<const _Tp&&>(__t))))
-> decltype( ranges::data(static_cast<const _Tp&&>(__t)))
{ return ranges::data(static_cast<const _Tp&&>(__t)); }
};
}

inline namespace __cpo {
inline constexpr auto cdata = __cdata::__fn{};
} // namespace __cpo
} // namespace ranges

#endif // !defined(_LIBCPP_HAS_NO_RANGES)

_LIBCPP_END_NAMESPACE_STD
Expand Down
Expand Up @@ -61,7 +61,7 @@ static_assert(test(std::weak_order, 1, 2));
static_assert(test(std::ranges::begin, a));
static_assert(test(std::ranges::end, a));
static_assert(test(std::ranges::cbegin, a));
//static_assert(test(std::ranges::cdata, a));
static_assert(test(std::ranges::cdata, a));
static_assert(test(std::ranges::cend, a));
//static_assert(test(std::ranges::crbegin, a));
//static_assert(test(std::ranges::crend, a));
Expand Down
61 changes: 61 additions & 0 deletions libcxx/test/std/ranges/range.access/data.pass.cpp
Expand Up @@ -20,6 +20,7 @@
#include "test_iterators.h"

using RangeDataT = decltype(std::ranges::data);
using RangeCDataT = decltype(std::ranges::cdata);

static int globalBuff[2];

Expand All @@ -32,6 +33,13 @@ static_assert(!std::is_invocable_v<RangeDataT, int [1]>);
static_assert(!std::is_invocable_v<RangeDataT, int (&&)[1]>);
static_assert( std::is_invocable_v<RangeDataT, int (&)[1]>);

static_assert(!std::is_invocable_v<RangeCDataT, Incomplete[]>);
static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2]>);
static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2][2]>);
static_assert(!std::is_invocable_v<RangeCDataT, int [1]>);
static_assert(!std::is_invocable_v<RangeCDataT, int (&&)[1]>);
static_assert( std::is_invocable_v<RangeCDataT, int (&)[1]>);

struct DataMember {
int x;
constexpr const int *data() const { return &x; }
Expand All @@ -40,15 +48,21 @@ static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
static_assert( std::is_invocable_v<RangeDataT, DataMember const&>);
static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>);
static_assert( std::is_invocable_v<RangeCDataT, DataMember &>);
static_assert(!std::is_invocable_v<RangeCDataT, DataMember &&>);
static_assert( std::is_invocable_v<RangeCDataT, DataMember const&>);
static_assert(!std::is_invocable_v<RangeCDataT, DataMember const&&>);

constexpr bool testReturnTypes() {
{
int *x[2];
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), int* const*);
}
{
int x[2][2];
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), const int(*)[2]);
}
{
struct D {
Expand All @@ -59,6 +73,10 @@ constexpr bool testReturnTypes() {
static_assert(!std::is_invocable_v<RangeDataT, D&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*);
static_assert(!std::is_invocable_v<RangeDataT, const D&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<D&>())), short*);
static_assert(!std::is_invocable_v<RangeCDataT, D&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const D&>())), short*);
static_assert(!std::is_invocable_v<RangeCDataT, const D&&>);
}
{
struct NC {
Expand All @@ -72,6 +90,10 @@ constexpr bool testReturnTypes() {
static_assert(!std::is_invocable_v<RangeDataT, NC&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*);
static_assert(!std::is_invocable_v<RangeDataT, const NC&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<NC&>())), char*);
static_assert(!std::is_invocable_v<RangeCDataT, NC&&>);
ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const NC&>())), char*);
static_assert(!std::is_invocable_v<RangeCDataT, const NC&&>);
}
return true;
}
Expand All @@ -80,12 +102,14 @@ struct VoidDataMember {
void *data() const;
};
static_assert(!std::is_invocable_v<RangeDataT, VoidDataMember const&>);
static_assert(!std::is_invocable_v<RangeCDataT, VoidDataMember const&>);

struct Empty { };
struct EmptyDataMember {
Empty data() const;
};
static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
static_assert(!std::is_invocable_v<RangeCDataT, EmptyDataMember const&>);

struct PtrConvertibleDataMember {
struct Ptr {
Expand All @@ -94,6 +118,7 @@ struct PtrConvertibleDataMember {
Ptr data() const;
};
static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
static_assert(!std::is_invocable_v<RangeCDataT, PtrConvertibleDataMember const&>);

struct NonConstDataMember {
int x;
Expand All @@ -115,15 +140,19 @@ struct DataMemberAndBegin {
constexpr bool testDataMember() {
DataMember a;
assert(std::ranges::data(a) == &a.x);
assert(std::ranges::cdata(a) == &a.x);

NonConstDataMember b;
assert(std::ranges::data(b) == &b.x);
static_assert(!std::is_invocable_v<RangeCDataT, decltype((b))>);

EnabledBorrowingDataMember c;
assert(std::ranges::data(std::move(c)) == &globalBuff[0]);
static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>);

DataMemberAndBegin d;
assert(std::ranges::data(d) == &d.x);
assert(std::ranges::cdata(d) == &d.x);

return true;
}
Expand All @@ -139,6 +168,10 @@ static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>)
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>);
static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>);

struct BeginMemberRandomAccess {
int buff[8];
Expand All @@ -149,6 +182,10 @@ static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&>);
static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&>);
static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&&>);

struct BeginFriendContiguousIterator {
int buff[8];
Expand All @@ -161,6 +198,10 @@ static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>)
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>);
static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>);

struct BeginFriendRandomAccess {
friend random_access_iterator<const int*> begin(const BeginFriendRandomAccess iter);
Expand All @@ -169,6 +210,10 @@ static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&>);
static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&&>);
static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&>);
static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&&>);

struct BeginMemberRvalue {
int buff[8];
Expand All @@ -179,6 +224,10 @@ static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&&>);

struct BeginMemberBorrowingEnabled {
constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
Expand All @@ -189,19 +238,27 @@ static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &>);
static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&>);
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&>);
static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&&>);

constexpr bool testViaRangesBegin() {
int arr[2];
assert(std::ranges::data(arr) == arr + 0);
assert(std::ranges::cdata(arr) == arr + 0);

BeginMemberContiguousIterator a;
assert(std::ranges::data(a) == a.buff);
assert(std::ranges::cdata(a) == a.buff);

const BeginFriendContiguousIterator b {};
assert(std::ranges::data(b) == b.buff);
assert(std::ranges::cdata(b) == b.buff);

BeginMemberBorrowingEnabled c;
assert(std::ranges::data(std::move(c)) == &globalBuff[1]);
static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>);

return true;
}
Expand All @@ -211,13 +268,17 @@ struct Incomplete;
template<class T> struct Holder { T t; };
static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*&>);
static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*>);
static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*&>);

struct RandomButNotContiguous {
random_access_iterator<int*> begin() const;
random_access_iterator<int*> end() const;
};
static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>);
static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous&>);
static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous>);
static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous&>);

int main(int, char**) {
static_assert(testReturnTypes());
Expand Down

0 comments on commit 483f7f5

Please sign in to comment.