[libcxx-commits] [libcxx] cf09b7d - [libc++][ranges] LWG3715: `view_interface::empty` is overconstrained (#85004)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 20 01:47:44 PDT 2024


Author: Xiaoyang Liu
Date: 2024-03-20T09:47:40+01:00
New Revision: cf09b7dec463178fbdefc72dc262d209d865c1c9

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

LOG: [libc++][ranges] LWG3715: `view_interface::empty` is overconstrained (#85004)

## Abstract

This pull request implements LWG3715: `view_interface::empty` is
overconstrained. Here is an example similar to those described in the
report, which compiles with `-stdlib=libstdc++` but failed to compile
with `-stdlib=libc++`:

```cpp
// https://godbolt.org/z/EWEoTzah3
std::istringstream input("1 2 3 4 5");
auto i = std::views::istream<int>(input);
auto r = std::views::counted(i.begin(), 4) | std::views::take(2);
assert(!r.empty());
```

## Reference

- [Draft C++ Standard:
[view.interface.general]](https://eel.is/c++draft/view.interface.general)
- [LWG3715](https://wg21.link/LWG3715)

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx23Issues.csv
    libcxx/include/__ranges/view_interface.h
    libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 659770cd58d19c..a103192350069b 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -181,7 +181,7 @@
 "`3711 <https://wg21.link/LWG3711>`__","Missing preconditions for slide_view constructor","July 2022","","","|ranges|"
 "`3712 <https://wg21.link/LWG3712>`__","``chunk_view`` and ``slide_view`` should not be ``default_initializable``","July 2022","","","|ranges|"
 "`3713 <https://wg21.link/LWG3713>`__","Sorted with respect to comparator (only)","July 2022","",""
-"`3715 <https://wg21.link/LWG3715>`__","``view_interface::empty`` is overconstrained","July 2022","","","|ranges|"
+"`3715 <https://wg21.link/LWG3715>`__","``view_interface::empty`` is overconstrained","July 2022","|Complete|","19.0","|ranges|"
 "`3719 <https://wg21.link/LWG3719>`__","Directory iterators should be usable with default sentinel","July 2022","|Complete|","17.0","|ranges|"
 "`3721 <https://wg21.link/LWG3721>`__","Allow an ``arg-id`` with a value of zero for ``width`` in ``std-format-spec``","July 2022","|Complete|","16.0","|format|"
 "`3724 <https://wg21.link/LWG3724>`__","``decay-copy`` should be constrained","July 2022","|Complete|","14.0"

diff  --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index 84dd1c316de379..3bcfbaf3a2f9ed 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -21,6 +21,7 @@
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
 #include <__ranges/empty.h>
+#include <__ranges/size.h>
 #include <__type_traits/is_class.h>
 #include <__type_traits/make_unsigned.h>
 #include <__type_traits/remove_cv.h>
@@ -51,16 +52,24 @@ class view_interface {
 public:
   template <class _D2 = _Derived>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty()
-    requires forward_range<_D2>
+    requires sized_range<_D2> || forward_range<_D2>
   {
-    return ranges::begin(__derived()) == ranges::end(__derived());
+    if constexpr (sized_range<_D2>) {
+      return ranges::size(__derived()) == 0;
+    } else {
+      return ranges::begin(__derived()) == ranges::end(__derived());
+    }
   }
 
   template <class _D2 = _Derived>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const
-    requires forward_range<const _D2>
+    requires sized_range<const _D2> || forward_range<const _D2>
   {
-    return ranges::begin(__derived()) == ranges::end(__derived());
+    if constexpr (sized_range<const _D2>) {
+      return ranges::size(__derived()) == 0;
+    } else {
+      return ranges::begin(__derived()) == ranges::end(__derived());
+    }
   }
 
   template <class _D2 = _Derived>

diff  --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index 2fc2fa8579996a..3f7c174d3fe48a 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -39,6 +39,14 @@ struct InputRange : std::ranges::view_interface<InputRange> {
   constexpr InputIter end() const { return InputIter(buff + 8); }
 };
 
+struct SizedInputRange : std::ranges::view_interface<SizedInputRange> {
+  int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+  constexpr InputIter begin() const { return InputIter(buff); }
+  constexpr sentinel_wrapper<InputIter> end() const { return sentinel_wrapper(InputIter(buff + 8)); }
+  constexpr std::size_t size() const { return 8; }
+};
+static_assert(std::ranges::sized_range<SizedInputRange>);
+
 struct NotSizedSentinel {
   using value_type = int;
   using 
diff erence_type = std::ptr
diff _t;
@@ -155,11 +163,24 @@ concept BoolOpInvocable = requires (T const& obj) { bool(obj); };
 
 constexpr bool testEmpty() {
   static_assert(!EmptyInvocable<InputRange>);
+  // LWG 3715: `view_interface::empty` is overconstrained
+  static_assert(EmptyInvocable<SizedInputRange>);
   static_assert( EmptyInvocable<ForwardRange>);
 
   static_assert(!BoolOpInvocable<InputRange>);
+  static_assert(BoolOpInvocable<SizedInputRange>);
   static_assert( BoolOpInvocable<ForwardRange>);
 
+  SizedInputRange sizedInputRange;
+  assert(!sizedInputRange.empty());
+  assert(!static_cast<SizedInputRange const&>(sizedInputRange).empty());
+
+  assert(sizedInputRange);
+  assert(static_cast<SizedInputRange const&>(sizedInputRange));
+
+  assert(!std::ranges::empty(sizedInputRange));
+  assert(!std::ranges::empty(static_cast<SizedInputRange const&>(sizedInputRange)));
+
   ForwardRange forwardRange;
   assert(!forwardRange.empty());
   assert(!static_cast<ForwardRange const&>(forwardRange).empty());


        


More information about the libcxx-commits mailing list