diff options
author | Jakub Mazurkiewicz <mazkuba3@gmail.com> | 2023-12-13 20:00:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-13 19:00:37 +0000 |
commit | 0b46606ca5b52aa515c5359ed6f24fb18d825b50 (patch) | |
tree | 416abbc5982c564becf05115c9fbf8abfc580137 | |
parent | a4336f2ec1747ea234a07d683930683f67fbd655 (diff) | |
download | llvm-0b46606ca5b52aa515c5359ed6f24fb18d825b50.zip llvm-0b46606ca5b52aa515c5359ed6f24fb18d825b50.tar.gz llvm-0b46606ca5b52aa515c5359ed6f24fb18d825b50.tar.bz2 |
[libc++] Fix `take_view::__sentinel`'s `operator==` (#74655)
* Fix `take_view::__sentinel`'s `operator==`
* Rename `ranges/range.adaptors/range.take/sentinel/base.pass.cpp`
directory to
`ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp`
* Add ***full*** test coverage for `take_view::__sentinel`'s
`operator==`
* Drive-by: fix comment in `base.pass.cpp` test
* Close #55211
-rw-r--r-- | libcxx/include/__ranges/take_view.h | 5 | ||||
-rw-r--r-- | libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp (renamed from libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp) | 5 | ||||
-rw-r--r-- | libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp (renamed from libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp) | 18 | ||||
-rw-r--r-- | libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp | 150 | ||||
-rw-r--r-- | libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp | 55 | ||||
-rw-r--r-- | libcxx/test/support/test_comparisons.h | 8 |
6 files changed, 165 insertions, 76 deletions
diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h index 4204017..518375d 100644 --- a/libcxx/include/__ranges/take_view.h +++ b/libcxx/include/__ranges/take_view.h @@ -180,10 +180,9 @@ public: return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; } - template<bool _OtherConst = !_Const> + template <bool _OtherConst = !_Const> requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> - _LIBCPP_HIDE_FROM_ABI - friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) { + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_OtherConst>& __lhs, const __sentinel& __rhs) { return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; } }; diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp index c949eb7..15b2b547 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp @@ -8,10 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 -// sentinel() = default; -// constexpr explicit sentinel(sentinel_t<Base> end); -// constexpr sentinel(sentinel<!Const> s) -// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>; +// constexpr sentinel_t<Base> base() const; #include <ranges> #include <cassert> diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp index 9d1bdaa..8928371 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp @@ -34,14 +34,14 @@ constexpr bool test() { { // Test the conversion from "sentinel" to "sentinel-to-const". - using TakeView = std::ranges::take_view<MoveOnlyView>; - using Sentinel = std::ranges::sentinel_t<TakeView>; + using TakeView = std::ranges::take_view<MoveOnlyView>; + using Sentinel = std::ranges::sentinel_t<TakeView>; using ConstSentinel = std::ranges::sentinel_t<const TakeView>; static_assert(std::is_convertible_v<Sentinel, ConstSentinel>); - TakeView tv = TakeView(MoveOnlyView(buffer), 4); - Sentinel s = tv.end(); + TakeView tv = TakeView(MoveOnlyView(buffer), 4); + Sentinel s = tv.end(); ConstSentinel cs = s; - cs = s; // test assignment also + cs = s; // test assignment also assert(tv.begin() + 4 == s); assert(tv.begin() + 4 == cs); assert(std::as_const(tv).begin() + 4 == s); @@ -50,12 +50,12 @@ constexpr bool test() { { // Test the constructor from "base-sentinel" to "sentinel". - using TakeView = std::ranges::take_view<MoveOnlyView>; - using Sentinel = std::ranges::sentinel_t<TakeView>; + using TakeView = std::ranges::take_view<MoveOnlyView>; + using Sentinel = std::ranges::sentinel_t<TakeView>; sentinel_wrapper<int*> sw1 = MoveOnlyView(buffer).end(); - static_assert( std::is_constructible_v<Sentinel, sentinel_wrapper<int*>>); + static_assert(std::is_constructible_v<Sentinel, sentinel_wrapper<int*>>); static_assert(!std::is_convertible_v<sentinel_wrapper<int*>, Sentinel>); - auto s = Sentinel(sw1); + auto s = Sentinel(sw1); std::same_as<sentinel_wrapper<int*>> auto sw2 = s.base(); assert(base(sw2) == base(sw1)); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp new file mode 100644 index 0000000..e6f433e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// friend constexpr bool operator==(const CI<Const>& y, const sentinel& x); +// template<bool OtherConst = !Const> +// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> +// friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x); + +#include <cassert> +#include <cstddef> +#include <ranges> +#include <type_traits> +#include <utility> + +#include "test_comparisons.h" +#include "test_iterators.h" + +template <bool Const> +using MaybeConstIterator = cpp20_input_iterator<std::conditional_t<Const, const int*, int*>>; + +template <bool Const> +class CrossConstComparableSentinel { + using Base = std::conditional_t<Const, const int*, int*>; + Base base_; + +public: + CrossConstComparableSentinel() = default; + constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {} + + friend constexpr bool operator==(const MaybeConstIterator<Const>& it, const CrossConstComparableSentinel& se) { + return base(it) == se.base_; + } + + friend constexpr bool operator==(const MaybeConstIterator<!Const>& it, const CrossConstComparableSentinel& se) { + return base(it) == se.base_; + } +}; + +static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<false>>); +static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<true>>); +static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<false>>); +static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<true>>); + +struct CrossConstComparableView : std::ranges::view_base { + template <std::size_t N> + constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {} + + constexpr MaybeConstIterator<false> begin() { return MaybeConstIterator<false>{b_}; } + constexpr CrossConstComparableSentinel<false> end() { return CrossConstComparableSentinel<false>{e_}; } + + constexpr MaybeConstIterator<true> begin() const { return MaybeConstIterator<true>{b_}; } + constexpr CrossConstComparableSentinel<true> end() const { return CrossConstComparableSentinel<true>{e_}; } + +private: + int* b_; + int* e_; +}; + +static_assert(std::ranges::range<CrossConstComparableView>); +static_assert(std::ranges::range<const CrossConstComparableView>); + +struct NonCrossConstComparableView : std::ranges::view_base { + int* begin(); + sentinel_wrapper<int*> end(); + + long* begin() const; + sentinel_wrapper<long*> end() const; +}; + +static_assert(std::ranges::range<NonCrossConstComparableView>); +static_assert(std::ranges::range<const NonCrossConstComparableView>); + +template <class T, class U> +concept weakly_equality_comparable_with = requires(const T& t, const U& u) { + t == u; + t != u; + u == t; + u != t; +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + using CrossConstComparableTakeView = std::ranges::take_view<CrossConstComparableView>; + + { // Compare CI<Const> with sentinel<Const> + { // Const == true + AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>, + std::ranges::sentinel_t<const CrossConstComparableTakeView>>(); + const CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true)); + assert(testEquality(tv.begin(), tv.end(), false)); + } + + { // Const == false + AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>, + std::ranges::sentinel_t<CrossConstComparableTakeView>>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true)); + assert(testEquality(std::ranges::next(tv.begin(), 1), tv.end(), false)); + } + } + + { // Compare CI<Const> with sentinel<!Const> + { // Const == true + AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>, + std::ranges::sentinel_t<CrossConstComparableTakeView>>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 4), tv.end(), true)); + assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 2), tv.end(), false)); + } + + { // Const == false + AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>, + std::ranges::sentinel_t<const CrossConstComparableTakeView>>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), std::as_const(tv).end(), true)); + assert(testEquality(std::ranges::next(tv.begin(), 3), std::as_const(tv).end(), false)); + } + } + + { // Check invalid comparisons between CI<Const> and sentinel<!Const> + using TakeView = std::ranges::take_view<NonCrossConstComparableView>; + static_assert( + !weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>, std::ranges::sentinel_t<TakeView>>); + static_assert( + !weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<const TakeView>>); + + // Those should be valid + static_assert( + weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<TakeView>>); + static_assert(weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>, + std::ranges::sentinel_t<const TakeView>>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp deleted file mode 100644 index eb265a7..0000000 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 - -// sentinel() = default; -// constexpr explicit sentinel(sentinel_t<Base> end); -// constexpr sentinel(sentinel<!Const> s) -// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>; - -#include <ranges> -#include <cassert> - -#include "test_macros.h" -#include "test_iterators.h" -#include "../types.h" - -constexpr bool test() { - int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - - { - { - const std::ranges::take_view<MoveOnlyView> tv(MoveOnlyView{buffer}, 4); - assert(tv.end() == std::ranges::next(tv.begin(), 4)); - assert(std::ranges::next(tv.begin(), 4) == tv.end()); - } - - { - std::ranges::take_view<MoveOnlyView> tv(MoveOnlyView{buffer}, 4); - assert(tv.end() == std::ranges::next(tv.begin(), 4)); - assert(std::ranges::next(tv.begin(), 4) == tv.end()); - } - } - - { - std::ranges::take_view<MoveOnlyView> tvNonConst(MoveOnlyView{buffer}, 4); - const std::ranges::take_view<MoveOnlyView> tvConst(MoveOnlyView{buffer}, 4); - assert(tvNonConst.end() == std::ranges::next(tvConst.begin(), 4)); - assert(std::ranges::next(tvConst.begin(), 4) == tvNonConst.end()); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h index e006f69..db6977a 100644 --- a/libcxx/test/support/test_comparisons.h +++ b/libcxx/test/support/test_comparisons.h @@ -213,13 +213,11 @@ void AssertEqualityAreNoexcept() } template <class T, class U = T> -void AssertEqualityReturnBool() -{ - ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool); - ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool); +TEST_CONSTEXPR_CXX14 void AssertEqualityReturnBool() { + ASSERT_SAME_TYPE(decltype(std::declval<const T&>() == std::declval<const U&>()), bool); + ASSERT_SAME_TYPE(decltype(std::declval<const T&>() != std::declval<const U&>()), bool); } - template <class T, class U = T> void AssertEqualityConvertibleToBool() { |