diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h --- a/libcxx/include/__compare/strong_order.h +++ b/libcxx/include/__compare/strong_order.h @@ -86,11 +86,11 @@ bool __u_is_nan = _VSTD::isnan(__u); bool __t_is_negative = _VSTD::signbit(__t); bool __u_is_negative = _VSTD::signbit(__u); - using _IntType = std::conditional_t< - sizeof(__t) == sizeof(int32_t), int32_t, std::conditional_t< + using _IntType = conditional_t< + sizeof(__t) == sizeof(int32_t), int32_t, conditional_t< sizeof(__t) == sizeof(int64_t), int64_t, void> >; - if constexpr (std::is_same_v<_IntType, void>) { + if constexpr (is_same_v<_IntType, void>) { static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type"); } else if (__t_is_nan && __u_is_nan) { // Order by sign bit, then by "payload bits" (we'll just use bit_cast). diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h --- a/libcxx/include/__compare/weak_order.h +++ b/libcxx/include/__compare/weak_order.h @@ -42,13 +42,13 @@ _LIBCPP_HIDE_FROM_ABI static constexpr weak_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) noexcept { - std::partial_ordering __po = (__t <=> __u); - if (__po == std::partial_ordering::less) { - return std::weak_ordering::less; - } else if (__po == std::partial_ordering::equivalent) { - return std::weak_ordering::equivalent; - } else if (__po == std::partial_ordering::greater) { - return std::weak_ordering::greater; + partial_ordering __po = (__t <=> __u); + if (__po == partial_ordering::less) { + return weak_ordering::less; + } else if (__po == partial_ordering::equivalent) { + return weak_ordering::equivalent; + } else if (__po == partial_ordering::greater) { + return weak_ordering::greater; } else { // Otherwise, at least one of them is a NaN. bool __t_is_nan = _VSTD::isnan(__t); diff --git a/libcxx/include/__ranges/counted.h b/libcxx/include/__ranges/counted.h --- a/libcxx/include/__ranges/counted.h +++ b/libcxx/include/__ranges/counted.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___RANGES_COUNTED_H #define _LIBCPP___RANGES_COUNTED_H +#include <__concepts/convertible_to.h> #include <__config> #include <__iterator/concepts.h> #include <__iterator/counted_iterator.h> @@ -16,10 +17,7 @@ #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> -#include <__ranges/concepts.h> #include <__ranges/subrange.h> -#include <__utility/decay_copy.h> -#include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/move.h> #include @@ -36,50 +34,44 @@ namespace ranges::views { namespace __counted { + template concept __explicitly_convertible = requires { _To(_From{}); }; struct __fn { - template - requires contiguous_iterator> && - __explicitly_convertible<_Diff, iter_difference_t<_Iter>> + template _LIBCPP_HIDE_FROM_ABI - constexpr auto operator()(_Iter&& __it, _Diff __c) const - noexcept(noexcept( - span(_VSTD::to_address(__it), static_cast>(__c)) - )) - { - return span(_VSTD::to_address(__it), static_cast>(__c)); - } - - template - requires random_access_iterator> && - __explicitly_convertible<_Diff, iter_difference_t<_Iter>> + static constexpr auto __go(_It __it, iter_difference_t<_It> __count) + noexcept(noexcept(span(_VSTD::to_address(__it), static_cast(__count)))) + // Deliberately omit return-type SFINAE, because to_address is not SFINAE-friendly + { return span(_VSTD::to_address(__it), static_cast(__count)); } + + template _LIBCPP_HIDE_FROM_ABI - constexpr auto operator()(_Iter&& __it, _Diff __c) const - noexcept( - noexcept(__it + static_cast>(__c)) && - noexcept(ranges::subrange(_VSTD::forward<_Iter>(__it), _VSTD::__decay_copy(__it))) - ) - { - auto __last = __it + static_cast>(__c); - return ranges::subrange(_VSTD::forward<_Iter>(__it), _VSTD::move(__last)); - } - - template - requires __explicitly_convertible<_Diff, iter_difference_t<_Iter>> + static constexpr auto __go(_It __it, iter_difference_t<_It> __count) + noexcept(noexcept(subrange(__it, __it + __count))) + -> decltype( subrange(__it, __it + __count)) + { return subrange(__it, __it + __count); } + + template _LIBCPP_HIDE_FROM_ABI - constexpr auto operator()(_Iter&& __it, _Diff __c) const - noexcept(noexcept( - ranges::subrange(counted_iterator(_VSTD::forward<_Iter>(__it), __c), default_sentinel) - )) - { - return ranges::subrange(counted_iterator(_VSTD::forward<_Iter>(__it), __c), default_sentinel); - } + static constexpr auto __go(_It&& __it, iter_difference_t<_It> __count) + noexcept(noexcept(subrange(counted_iterator(_VSTD::forward<_It>(__it), __count), default_sentinel))) + -> decltype( subrange(counted_iterator(_VSTD::forward<_It>(__it), __count), default_sentinel)) + { return subrange(counted_iterator(_VSTD::forward<_It>(__it), __count), default_sentinel); } + + template> _Diff> + requires input_or_output_iterator> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_It&& __it, _Diff&& __count) const + noexcept(noexcept(__go(_VSTD::forward<_It>(__it), _VSTD::forward<_Diff>(__count)))) + -> decltype( __go(_VSTD::forward<_It>(__it), _VSTD::forward<_Diff>(__count))) + { return __go(_VSTD::forward<_It>(__it), _VSTD::forward<_Diff>(__count)); } }; -} + +} // namespace __counted inline namespace __cpo { inline constexpr auto counted = __counted::__fn{}; diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -91,14 +91,14 @@ _LIBCPP_HIDE_FROM_ABI constexpr subrange(__convertible_to_non_slicing<_Iter> auto __iter, _Sent __sent) requires _MustProvideSizeAtConstruction - : __begin_(_VSTD::move(__iter)), __end_(std::move(__sent)) + : __begin_(_VSTD::move(__iter)), __end_(_VSTD::move(__sent)) { } _LIBCPP_HIDE_FROM_ABI constexpr subrange(__convertible_to_non_slicing<_Iter> auto __iter, _Sent __sent, make_unsigned_t> __n) requires (_Kind == subrange_kind::sized) - : __begin_(_VSTD::move(__iter)), __end_(std::move(__sent)), __size_(__n) + : __begin_(_VSTD::move(__iter)), __end_(_VSTD::move(__sent)), __size_(__n) { if constexpr (sized_sentinel_for<_Sent, _Iter>) _LIBCPP_ASSERT((__end_ - __begin_) == static_cast>(__n), diff --git a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp @@ -20,183 +20,205 @@ #include "test_macros.h" #include "test_iterators.h" -struct Unrelated {}; - -struct ConvertibleToSize { - constexpr operator std::ptrdiff_t() const { return 8; } +struct Convertible { + operator int() const; }; -struct ImplicitlyConvertible { - operator short(); - explicit operator std::ptrdiff_t() = delete; +struct OnlyExplicitlyConvertible { + explicit operator int() const; }; -template -concept CountedInvocable = requires(Iter& i, T t) { std::views::counted(i, t); }; +template +concept CountedInvocable = requires (Ts&&... ts) { + std::views::counted(std::forward(ts)...); +}; constexpr bool test() { int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; { - static_assert( CountedInvocable, ConvertibleToSize>); - static_assert(!CountedInvocable, ImplicitlyConvertible>); - static_assert(!CountedInvocable, Unrelated>); + static_assert(std::addressof(std::views::counted) == std::addressof(std::ranges::views::counted)); + + auto copy = std::views::counted; + static_assert(std::semiregular); + + static_assert( CountedInvocable); + static_assert( CountedInvocable); + static_assert(!CountedInvocable); + static_assert(!CountedInvocable); + static_assert(!CountedInvocable); + static_assert(!CountedInvocable); + static_assert(!CountedInvocable<>); + } + + { + auto c1 = std::views::counted(buffer, 3); + auto c2 = std::views::counted(std::as_const(buffer), 3); + + ASSERT_SAME_TYPE(decltype(c1), std::span); + ASSERT_SAME_TYPE(decltype(c2), std::span); + + assert(c1.data() == buffer && c1.size() == 3); + assert(c2.data() == buffer && c2.size() == 3); + } + + { + auto it = contiguous_iterator(buffer); + auto cit = contiguous_iterator(buffer); + + auto c1 = std::views::counted(it, 3); + auto c2 = std::views::counted(std::as_const(it), 3); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(contiguous_iterator(buffer), 3); + auto c5 = std::views::counted(cit, 3); + auto c6 = std::views::counted(std::as_const(cit), 3); + auto c7 = std::views::counted(std::move(cit), 3); + auto c8 = std::views::counted(contiguous_iterator(buffer), 3); + + ASSERT_SAME_TYPE(decltype(c1), std::span); + ASSERT_SAME_TYPE(decltype(c2), std::span); + ASSERT_SAME_TYPE(decltype(c3), std::span); + ASSERT_SAME_TYPE(decltype(c4), std::span); + ASSERT_SAME_TYPE(decltype(c5), std::span); + ASSERT_SAME_TYPE(decltype(c6), std::span); + ASSERT_SAME_TYPE(decltype(c7), std::span); + ASSERT_SAME_TYPE(decltype(c8), std::span); + + assert(c1.data() == buffer && c1.size() == 3); + assert(c2.data() == buffer && c2.size() == 3); + assert(c3.data() == buffer && c3.size() == 3); + assert(c4.data() == buffer && c4.size() == 3); + assert(c5.data() == buffer && c5.size() == 3); + assert(c6.data() == buffer && c6.size() == 3); + assert(c7.data() == buffer && c7.size() == 3); + assert(c8.data() == buffer && c8.size() == 3); + } - static_assert(std::semiregular>); + { + auto it = random_access_iterator(buffer); + auto cit = random_access_iterator(buffer); + + auto c1 = std::views::counted(it, 3); + auto c2 = std::views::counted(std::as_const(it), 3); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(random_access_iterator(buffer), 3); + auto c5 = std::views::counted(cit, 3); + auto c6 = std::views::counted(std::as_const(cit), 3); + auto c7 = std::views::counted(std::move(cit), 3); + auto c8 = std::views::counted(random_access_iterator(buffer), 3); + + ASSERT_SAME_TYPE(decltype(c1), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c2), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c3), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c4), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c5), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c6), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c7), std::ranges::subrange>); + ASSERT_SAME_TYPE(decltype(c8), std::ranges::subrange>); + + assert(c1.begin() == it && c1.end() == it + 3); + assert(c2.begin() == it && c2.end() == it + 3); + assert(c3.begin() == it && c3.end() == it + 3); + assert(c4.begin() == it && c4.end() == it + 3); + assert(c5.begin() == cit && c5.end() == cit + 3); + assert(c6.begin() == cit && c6.end() == cit + 3); + assert(c7.begin() == cit && c7.end() == cit + 3); + assert(c8.begin() == cit && c8.end() == cit + 3); } { - { - contiguous_iterator iter(buffer); - std::span s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.data() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span); - } - { - const contiguous_iterator iter(buffer); - std::span s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.data() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span); - } - { - contiguous_iterator iter(buffer); - std::span s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.data() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span); - } - { - const contiguous_iterator iter(buffer); - std::span s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.data() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span); - } + auto it = bidirectional_iterator(buffer); + auto cit = bidirectional_iterator(buffer); + + auto c1 = std::views::counted(it, 3); + auto c2 = std::views::counted(std::as_const(it), 3); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(bidirectional_iterator(buffer), 3); + auto c5 = std::views::counted(cit, 3); + auto c6 = std::views::counted(std::as_const(cit), 3); + auto c7 = std::views::counted(std::move(cit), 3); + auto c8 = std::views::counted(bidirectional_iterator(buffer), 3); + + using Expected = std::ranges::subrange, std::default_sentinel_t>; + using ConstExpected = std::ranges::subrange, std::default_sentinel_t>; + + ASSERT_SAME_TYPE(decltype(c1), Expected); + ASSERT_SAME_TYPE(decltype(c2), Expected); + ASSERT_SAME_TYPE(decltype(c3), Expected); + ASSERT_SAME_TYPE(decltype(c4), Expected); + ASSERT_SAME_TYPE(decltype(c5), ConstExpected); + ASSERT_SAME_TYPE(decltype(c6), ConstExpected); + ASSERT_SAME_TYPE(decltype(c7), ConstExpected); + ASSERT_SAME_TYPE(decltype(c8), ConstExpected); + + assert(c1.begin().base() == it && c1.size() == 3); + assert(c2.begin().base() == it && c2.size() == 3); + assert(c3.begin().base() == it && c3.size() == 3); + assert(c4.begin().base() == it && c4.size() == 3); + assert(c5.begin().base() == cit && c5.size() == 3); + assert(c6.begin().base() == cit && c6.size() == 3); + assert(c7.begin().base() == cit && c7.size() == 3); + assert(c8.begin().base() == cit && c8.size() == 3); } { - { - random_access_iterator iter(buffer); - std::ranges::subrange> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == iter); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange>); - } - { - const random_access_iterator iter(buffer); - std::ranges::subrange> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == iter); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange>); - } - { - random_access_iterator iter(buffer); - std::ranges::subrange> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == iter); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange>); - } - { - const random_access_iterator iter(buffer); - std::ranges::subrange> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == iter); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange>); - } + auto it = output_iterator(buffer); + + auto c1 = std::views::counted(it, 3); + auto c2 = std::views::counted(std::as_const(it), 3); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(output_iterator(buffer), 3); + + using Expected = std::ranges::subrange, std::default_sentinel_t>; + + ASSERT_SAME_TYPE(decltype(c1), Expected); + ASSERT_SAME_TYPE(decltype(c2), Expected); + ASSERT_SAME_TYPE(decltype(c3), Expected); + ASSERT_SAME_TYPE(decltype(c4), Expected); + + assert(base(c1.begin().base()) == buffer && c1.size() == 3); + assert(base(c2.begin().base()) == buffer && c2.size() == 3); + assert(base(c3.begin().base()) == buffer && c3.size() == 3); + assert(base(c4.begin().base()) == buffer && c4.size() == 3); } { - { - bidirectional_iterator iter(buffer); - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == std::counted_iterator(iter, 8)); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } - { - const bidirectional_iterator iter(buffer); - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == std::counted_iterator(iter, 8)); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } - { - output_iterator iter(buffer); - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == std::counted_iterator(iter, 8)); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } - { - const output_iterator iter(buffer); - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(iter, 8); - assert(s.size() == 8); - assert(s.begin() == std::counted_iterator(iter, 8)); - - ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } - { - cpp20_input_iterator iter(buffer); - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(std::move(iter), 8); - assert(s.size() == 8); - assert(s.begin().base().base() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(std::move(iter), 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } - { - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t> s = std::views::counted(cpp20_input_iterator(buffer), 8); - assert(s.size() == 8); - assert(s.begin().base().base() == buffer); - - ASSERT_SAME_TYPE(decltype(std::views::counted(cpp20_input_iterator(buffer), 8)), - std::ranges::subrange< - std::counted_iterator>, - std::default_sentinel_t>); - } + auto it = cpp17_input_iterator(buffer); + + auto c1 = std::views::counted(it, 3); + auto c2 = std::views::counted(std::as_const(it), 3); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(cpp17_input_iterator(buffer), 3); + + using Expected = std::ranges::subrange, std::default_sentinel_t>; + + ASSERT_SAME_TYPE(decltype(c1), Expected); + ASSERT_SAME_TYPE(decltype(c2), Expected); + ASSERT_SAME_TYPE(decltype(c3), Expected); + ASSERT_SAME_TYPE(decltype(c4), Expected); + + assert(base(c1.begin().base()) == buffer && c1.size() == 3); + assert(base(c2.begin().base()) == buffer && c2.size() == 3); + assert(base(c3.begin().base()) == buffer && c3.size() == 3); + assert(base(c4.begin().base()) == buffer && c4.size() == 3); } { - static_assert(std::same_as); + auto it = cpp20_input_iterator(buffer); + + static_assert(!std::copyable>); + static_assert(!CountedInvocable&, int>); + static_assert(!CountedInvocable&, int>); + auto c3 = std::views::counted(std::move(it), 3); + auto c4 = std::views::counted(cpp20_input_iterator(buffer), 3); + + using Expected = std::ranges::subrange, std::default_sentinel_t>; + + ASSERT_SAME_TYPE(decltype(c3), Expected); + ASSERT_SAME_TYPE(decltype(c4), Expected); + + assert(base(c3.begin().base()) == buffer && c3.size() == 3); + assert(base(c4.begin().base()) == buffer && c4.size() == 3); } return true; diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -657,6 +657,8 @@ constexpr I base() && { return std::move(base_); } + friend constexpr I base(const cpp20_input_iterator& i) { return i.base_; } + template void operator,(T const &) = delete;