[libcxx-commits] [libcxx] [libc++][ranges] LWG4001: `iota_view` should provide `empty` (PR #79687)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 15 10:35:51 PDT 2024
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/79687
>From fe76be259414c0cd8dfa448cec293b9db40409a9 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Thu, 11 Jan 2024 10:04:20 +0200
Subject: [PATCH 1/5] [libc++][ranges] LWG4001: `iota_view` should provide
`empty`
Implements: https://wg21.link/LWG4001
- https://eel.is/c++draft/range.iota.view
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/include/__ranges/iota_view.h | 2 +
.../range.iota.view/empty.pass.cpp | 136 ++++++++++++++++++
3 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 58e995809777c..1901c144c9319 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -38,7 +38,7 @@
"`3974 <https://wg21.link/LWG3974>`__","``mdspan::operator[]`` should not copy ``OtherIndexTypes``","Kona November 2023","","",""
"`3987 <https://wg21.link/LWG3987>`__","Including ``<flat_foo>`` doesn't provide ``std::begin``/``end``","Kona November 2023","","","|flat_containers|"
"`3990 <https://wg21.link/LWG3990>`__","Program-defined specializations of ``std::tuple`` and ``std::variant`` can't be properly supported","Kona November 2023","","",""
-"`4001 <https://wg21.link/LWG4001>`__","``iota_view`` should provide ``empty``","Kona November 2023","","","|ranges|"
+"`4001 <https://wg21.link/LWG4001>`__","``iota_view`` should provide ``empty``","Kona November 2023","|Complete|","19.0","|ranges|"
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"","","","","",""
diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h
index 9e6f724241ccf..c3b72d52d4c29 100644
--- a/libcxx/include/__ranges/iota_view.h
+++ b/libcxx/include/__ranges/iota_view.h
@@ -345,6 +345,8 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
return __iterator{__bound_sentinel_};
}
+ _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __value_ == __bound_sentinel_; }
+
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
requires(same_as<_Start, _BoundSentinel> && __advanceable<_Start>) ||
(integral<_Start> && integral<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start>
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
new file mode 100644
index 0000000000000..e7adffaf63b4c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// constexpr bool empty() const;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+#include "types.h"
+
+template <typename R>
+concept HasFreeEmpty = requires(R r) { std::ranges::empty(r); };
+
+template <typename R>
+concept HasMemberEmpty = requires(R r) {
+ { r.empty() } -> std::same_as<bool>;
+};
+
+constexpr void test_empty_iota() {
+ std::vector<int> ev;
+
+ // Both parameters are non-const
+ {
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(iv.empty());
+ }
+ // Left paramter is const
+ {
+ auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(iv.empty());
+ }
+ // Right paramter is const
+ {
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(iv.empty());
+ }
+ // Both parameters are const
+ {
+ auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(std::as_const(ev)));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(iv.empty());
+ }
+
+ std::vector<char> v{'b', 'a', 'b', 'a', 'z', 'm', 't'};
+ auto fv = v | std::views::filter([](auto val) { return val == '0'; });
+
+ {
+ auto iv = std::views::iota(std::ranges::begin(fv), std::ranges::end(fv));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(iv.empty());
+ }
+}
+
+constexpr void test_nonempty_iota() {
+ // Default ctr
+ {
+ std::ranges::iota_view<Int42<DefaultTo42>> iv;
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(!iv.empty());
+ }
+ // Value pass
+ {
+ std::ranges::iota_view<SomeInt> iv(SomeInt(94));
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(!iv.empty());
+ }
+
+ {
+ std::vector<char> v;
+ auto it = std::back_inserter(v);
+ auto iv = std::views::iota(it);
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(!iv.empty());
+ }
+ {
+ std::vector<char> v{'b', 'a', 'b', 'a', 'z', 'm', 't'};
+ auto it = std::back_inserter(v);
+ auto iv = std::views::iota(it);
+
+ static_assert(HasFreeEmpty<decltype(iv)>);
+ static_assert(HasMemberEmpty<decltype(iv)>);
+
+ assert(!iv.empty());
+ }
+}
+
+constexpr bool test() {
+ test_empty_iota();
+ test_nonempty_iota();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
>From bdb67fc0686449de41a68b148f345e7e4ca87d43 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Sun, 28 Jan 2024 00:57:51 +0200
Subject: [PATCH 2/5] Update
libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
Co-authored-by: Will Hawkins <whh8b at obs.cr>
---
.../std/ranges/range.factories/range.iota.view/empty.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
index e7adffaf63b4c..28af27297cbd8 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
@@ -38,7 +38,7 @@ constexpr void test_empty_iota() {
assert(iv.empty());
}
- // Left paramter is const
+ // Left parameter is const
{
auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
>From b76e34ce5573059f3385f85fbeae9396aad9f221 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Sun, 28 Jan 2024 00:58:04 +0200
Subject: [PATCH 3/5] Update
libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
Co-authored-by: Will Hawkins <whh8b at obs.cr>
---
.../std/ranges/range.factories/range.iota.view/empty.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
index 28af27297cbd8..589e7e73beda4 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
@@ -47,7 +47,7 @@ constexpr void test_empty_iota() {
assert(iv.empty());
}
- // Right paramter is const
+ // Right parameter is const
{
auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
>From 02c4e7184ef60ce8511697d0ea152be65c80a3e9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 2 Apr 2024 16:37:29 +0300
Subject: [PATCH 4/5] Addressed comments
---
.../range.iota.view/empty.pass.cpp | 95 +++++++++++--------
1 file changed, 58 insertions(+), 37 deletions(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
index 589e7e73beda4..8abb57957c6f4 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
@@ -19,61 +19,94 @@
#include "types.h"
template <typename R>
-concept HasFreeEmpty = requires(R r) { std::ranges::empty(r); };
-
-template <typename R>
-concept HasMemberEmpty = requires(R r) {
+concept HasEmpty = requires(R r) {
+ std::ranges::empty(r);
{ r.empty() } -> std::same_as<bool>;
};
-constexpr void test_empty_iota() {
+constexpr void test_empty_iota_sfinae() {
std::vector<int> ev;
// Both parameters are non-const
{
auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
- assert(iv.empty());
+ static_assert(HasEmpty<decltype(iv)>);
}
// Left parameter is const
{
auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
- assert(iv.empty());
+ static_assert(HasEmpty<decltype(iv)>);
}
// Right parameter is const
{
auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
- assert(iv.empty());
+ static_assert(HasEmpty<decltype(iv)>);
}
// Both parameters are const
{
auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(std::as_const(ev)));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
+ static_assert(HasEmpty<decltype(iv)>);
+ }
+}
- assert(iv.empty());
+constexpr void test_nonempty_iota_sfinae() {
+ // Default ctr
+ {
+ std::ranges::iota_view<Int42<DefaultTo42>> iv;
+
+ static_assert(HasEmpty<decltype(iv)>);
+ }
+ // Value pass
+ {
+ std::ranges::iota_view<SomeInt> iv(SomeInt(94));
+
+ static_assert(HasEmpty<decltype(iv)>);
+ }
+
+ {
+ std::vector<char> v;
+ auto it = std::back_inserter(v);
+ auto iv = std::views::iota(it);
+
+ static_assert(HasEmpty<decltype(iv)>);
+ }
+ {
+ std::vector<char> v{'b', 'a', 'b', 'a', 'z', 'm', 't'};
+ auto it = std::back_inserter(v);
+ auto iv = std::views::iota(it);
+
+ static_assert(HasEmpty<decltype(iv)>);
}
+}
+
+constexpr void test_empty_iota() {
+ std::vector<int> ev;
- std::vector<char> v{'b', 'a', 'b', 'a', 'z', 'm', 't'};
- auto fv = v | std::views::filter([](auto val) { return val == '0'; });
+ // Both parameters are non-const
+ {
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
+
+ assert(iv.empty());
+ }
+ // Left parameter is const
+ {
+ auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
+ assert(iv.empty());
+ }
+ // Right parameter is const
{
- auto iv = std::views::iota(std::ranges::begin(fv), std::ranges::end(fv));
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
+ assert(iv.empty());
+ }
+ // Both parameters are const
+ {
+ auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(std::as_const(ev)));
assert(iv.empty());
}
@@ -84,18 +117,12 @@ constexpr void test_nonempty_iota() {
{
std::ranges::iota_view<Int42<DefaultTo42>> iv;
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
assert(!iv.empty());
}
// Value pass
{
std::ranges::iota_view<SomeInt> iv(SomeInt(94));
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
assert(!iv.empty());
}
@@ -104,9 +131,6 @@ constexpr void test_nonempty_iota() {
auto it = std::back_inserter(v);
auto iv = std::views::iota(it);
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
assert(!iv.empty());
}
{
@@ -114,9 +138,6 @@ constexpr void test_nonempty_iota() {
auto it = std::back_inserter(v);
auto iv = std::views::iota(it);
- static_assert(HasFreeEmpty<decltype(iv)>);
- static_assert(HasMemberEmpty<decltype(iv)>);
-
assert(!iv.empty());
}
}
>From 8b1131f1da1a9111fad983427458253499d4325e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 15 Jul 2024 20:35:32 +0300
Subject: [PATCH 5/5] Addressed review comments
---
.../range.iota.view/empty.pass.cpp | 54 +++----------------
1 file changed, 7 insertions(+), 47 deletions(-)
diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
index 8abb57957c6f4..a8a34e152643a 100644
--- a/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
+++ b/libcxx/test/std/ranges/range.factories/range.iota.view/empty.pass.cpp
@@ -19,7 +19,7 @@
#include "types.h"
template <typename R>
-concept HasEmpty = requires(R r) {
+concept HasEmpty = requires(const R r) {
std::ranges::empty(r);
{ r.empty() } -> std::same_as<bool>;
};
@@ -27,30 +27,10 @@ concept HasEmpty = requires(R r) {
constexpr void test_empty_iota_sfinae() {
std::vector<int> ev;
- // Both parameters are non-const
- {
- auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
-
- static_assert(HasEmpty<decltype(iv)>);
- }
- // Left parameter is const
- {
- auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
-
- static_assert(HasEmpty<decltype(iv)>);
- }
- // Right parameter is const
- {
- auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
-
- static_assert(HasEmpty<decltype(iv)>);
- }
- // Both parameters are const
- {
- auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(std::as_const(ev)));
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
- static_assert(HasEmpty<decltype(iv)>);
- }
+ static_assert(HasEmpty<decltype(iv)>);
+ static_assert(HasEmpty<decltype(std::as_const(iv))>);
}
constexpr void test_nonempty_iota_sfinae() {
@@ -86,30 +66,10 @@ constexpr void test_nonempty_iota_sfinae() {
constexpr void test_empty_iota() {
std::vector<int> ev;
- // Both parameters are non-const
- {
- auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
+ auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(ev));
- assert(iv.empty());
- }
- // Left parameter is const
- {
- auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(ev));
-
- assert(iv.empty());
- }
- // Right parameter is const
- {
- auto iv = std::views::iota(std::ranges::begin(ev), std::ranges::end(std::as_const(ev)));
-
- assert(iv.empty());
- }
- // Both parameters are const
- {
- auto iv = std::views::iota(std::ranges::begin(std::as_const(ev)), std::ranges::end(std::as_const(ev)));
-
- assert(iv.empty());
- }
+ assert(iv.empty());
+ assert(std::as_const(iv).empty());
}
constexpr void test_nonempty_iota() {
More information about the libcxx-commits
mailing list