[libcxx-commits] [libcxx] 483f7f5 - [libc++] [ranges] Implement ranges::cdata.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 12 19:07:26 PST 2022


Author: Arthur O'Dwyer
Date: 2022-01-12T22:07:13-05:00
New Revision: 483f7f55365209dc39df9fa31b2cce0f03e9b4ec

URL: https://github.com/llvm/llvm-project/commit/483f7f55365209dc39df9fa31b2cce0f03e9b4ec
DIFF: https://github.com/llvm/llvm-project/commit/483f7f55365209dc39df9fa31b2cce0f03e9b4ec.diff

LOG: [libc++] [ranges] Implement ranges::cdata.

Differential Revision: https://reviews.llvm.org/D117044

Added: 
    

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/__ranges/data.h
    libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
    libcxx/test/std/ranges/range.access/data.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index be82f3fa6d4c1..4ed4f6879a6ee 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -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>`_
@@ -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*

diff  --git a/libcxx/include/__ranges/data.h b/libcxx/include/__ranges/data.h
index 20d84912d2786..69dfd479c0110 100644
--- a/libcxx/include/__ranges/data.h
+++ b/libcxx/include/__ranges/data.h
@@ -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

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
index 86ddfdeacd921..4cd461631838d 100644
--- 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::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));

diff  --git a/libcxx/test/std/ranges/range.access/data.pass.cpp b/libcxx/test/std/ranges/range.access/data.pass.cpp
index 8f2446287a30a..d7d87e2eb0415 100644
--- 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<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; }
@@ -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 {
@@ -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 {
@@ -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;
 }
@@ -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 {
@@ -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;
@@ -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;
 }
@@ -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];
@@ -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];
@@ -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);
@@ -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];
@@ -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]}; }
@@ -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;
 }
@@ -211,6 +268,8 @@ 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;
@@ -218,6 +277,8 @@ struct RandomButNotContiguous {
 };
 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());


        


More information about the libcxx-commits mailing list