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 @@ -97,7 +97,7 @@ | `ranges::ssize `_ | `ranges::empty `_ | `ranges::data `_ -| ranges::cdata",[iterator.concepts],Christopher Di Bella and Zoe Carver,In progress +| `ranges::cdata `_",[iterator.concepts],Christopher Di Bella and Zoe Carver,In progress `[range.range] `_,"| `ranges::range `_ | `ranges::borrowed_range `_ | `ranges::enable_borrowed_range `_ @@ -114,12 +114,12 @@ `[range.view] `_,"| `ranges::enable_view `_ | `ranges::view_base `_ | `ranges::view `_",[range.range],Louis Dionne,✅ -`[range.refinements] `_,"| ranges::output_range +`[range.refinements] `_,"| `ranges::output_range `_ | `ranges::input_range `_ | `ranges::forward_range: `D100275 `_ | `ranges::bidirectional_range `_ | `ranges::random_access_range `_ -| ranges::contiguous_range +| `ranges::contiguous_range `_ | `ranges::common_range `_",[range.range],Christopher Di Bella,✅ `[range.refinements]`_,`ranges::viewable_range `_,[range.range],Louis Dionne,✅ `[range.utility.helpers] `_,"| *simple-view* diff --git a/libcxx/include/__ranges/data.h b/libcxx/include/__ranges/data.h --- a/libcxx/include/__ranges/data.h +++ b/libcxx/include/__ranges/data.h @@ -71,6 +71,34 @@ } // namespace __cpo } // namespace ranges +// [range.prim.cdata] + +namespace ranges { +namespace __cdata { + struct __fn { + template + requires is_lvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::data(static_cast&>(__t)))) + -> decltype( ranges::data(static_cast&>(__t))) + { return ranges::data(static_cast&>(__t)); } + + template + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::data(static_cast(__t)))) + -> decltype( ranges::data(static_cast(__t))) + { return ranges::data(static_cast(__t)); } + }; +} + +inline namespace __cpo { + inline constexpr auto cdata = __cdata::__fn{}; +} // namespace __cpo +} // namespace ranges + #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp --- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp @@ -61,7 +61,7 @@ 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)); diff --git a/libcxx/test/std/ranges/range.access/data.pass.cpp b/libcxx/test/std/ranges/range.access/data.pass.cpp --- a/libcxx/test/std/ranges/range.access/data.pass.cpp +++ b/libcxx/test/std/ranges/range.access/data.pass.cpp @@ -20,6 +20,7 @@ #include "test_iterators.h" using RangeDataT = decltype(std::ranges::data); +using RangeCDataT = decltype(std::ranges::cdata); static int globalBuff[2]; @@ -32,6 +33,13 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); + struct DataMember { int x; constexpr const int *data() const { return &x; } @@ -40,15 +48,21 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); 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 { @@ -59,6 +73,10 @@ static_assert(!std::is_invocable_v); ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), short*); static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*); + static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), short*); + static_assert(!std::is_invocable_v); } { struct NC { @@ -72,6 +90,10 @@ static_assert(!std::is_invocable_v); ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), char*); static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); + static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval())), char*); + static_assert(!std::is_invocable_v); } return true; } @@ -80,12 +102,14 @@ void *data() const; }; static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct Empty { }; struct EmptyDataMember { Empty data() const; }; static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct PtrConvertibleDataMember { struct Ptr { @@ -94,6 +118,7 @@ Ptr data() const; }; static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct NonConstDataMember { int x; @@ -115,15 +140,19 @@ 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); EnabledBorrowingDataMember c; assert(std::ranges::data(std::move(c)) == &globalBuff[0]); + static_assert(!std::is_invocable_v); DataMemberAndBegin d; assert(std::ranges::data(d) == &d.x); + assert(std::ranges::cdata(d) == &d.x); return true; } @@ -139,6 +168,10 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginMemberRandomAccess { int buff[8]; @@ -149,6 +182,10 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginFriendContiguousIterator { int buff[8]; @@ -161,6 +198,10 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert( std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginFriendRandomAccess { friend random_access_iterator begin(const BeginFriendRandomAccess iter); @@ -169,6 +210,10 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginMemberRvalue { int buff[8]; @@ -179,6 +224,10 @@ static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginMemberBorrowingEnabled { constexpr contiguous_iterator begin() { return contiguous_iterator{&globalBuff[1]}; } @@ -189,19 +238,27 @@ static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); 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); return true; } @@ -211,6 +268,8 @@ template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*&>); struct RandomButNotContiguous { random_access_iterator begin() const; @@ -218,6 +277,8 @@ }; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); int main(int, char**) { static_assert(testReturnTypes());