Index: libcxx/include/iterator =================================================================== --- libcxx/include/iterator +++ libcxx/include/iterator @@ -399,6 +399,11 @@ // 24.8, container access: template constexpr auto size(const C& c) -> decltype(c.size()); // C++17 template constexpr size_t size(const T (&array)[N]) noexcept; // C++17 + +template constexpr auto ssize(const C& c) + -> common_type_t>; // C++20 +template constexpr ptrdiff_t ssize(const T (&array)[N]) noexcept; // C++20 + template constexpr auto empty(const C& c) -> decltype(c.empty()); // C++17 template constexpr bool empty(const T (&array)[N]) noexcept; // C++17 template constexpr bool empty(initializer_list il) noexcept; // C++17 @@ -1858,6 +1863,19 @@ inline _LIBCPP_INLINE_VISIBILITY constexpr size_t size(const _Tp (&)[_Sz]) noexcept { return _Sz; } +#if _LIBCPP_STD_VER > 17 +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr auto ssize(const _Cont& __c) +_NOEXCEPT_(noexcept(static_cast>>(__c.size()))) +-> common_type_t> +{ return static_cast>>(__c.size()); } + +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr ptrdiff_t ssize(const _Tp (&)[_Sz]) noexcept { return _Sz; } +#endif + template _LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_INLINE_VISIBILITY constexpr auto empty(const _Cont& __c) Index: libcxx/test/std/iterators/iterator.container/size.pass.cpp =================================================================== --- libcxx/test/std/iterators/iterator.container/size.pass.cpp +++ libcxx/test/std/iterators/iterator.container/size.pass.cpp @@ -27,32 +27,30 @@ template -void test_const_container( const C& c ) +void test_container( C& c) { // Can't say noexcept here because the container might not be assert ( std::size(c) == c.size()); } -template -void test_const_container( const std::initializer_list& c) +template +void test_const_container( const C& c ) { -// ASSERT_NOEXCEPT(std::size(c)); -// For some reason, there isn't a std::size() for initializer lists +// Can't say noexcept here because the container might not be assert ( std::size(c) == c.size()); } -template -void test_container( C& c) +template +void test_const_container( const std::initializer_list& c) { -// Can't say noexcept here because the container might not be + LIBCPP_ASSERT_NOEXCEPT(std::size(c)); // our std::size is conditionally noexcept assert ( std::size(c) == c.size()); } template void test_container( std::initializer_list& c ) { -// ASSERT_NOEXCEPT(std::size(c)); -// For some reason, there isn't a std::size() for initializer lists + LIBCPP_ASSERT_NOEXCEPT(std::size(c)); // our std::size is conditionally noexcept assert ( std::size(c) == c.size()); } Index: libcxx/test/std/iterators/iterator.container/ssize.pass.cpp =================================================================== --- libcxx/test/std/iterators/iterator.container/ssize.pass.cpp +++ libcxx/test/std/iterators/iterator.container/ssize.pass.cpp @@ -25,30 +25,31 @@ struct short_container { - uint16_t size() const { return 60000; } + uint16_t size() const { return 60000; } // not noexcept }; + + template -void test_const_container(const C& c) +void test_container(C& c) { // Can't say noexcept here because the container might not be static_assert( std::is_signed_v, ""); assert ( std::ssize(c) == static_cast(c.size())); } -template -void test_const_container(const std::initializer_list& c) +template +void test_const_container(const C& c) { -// ASSERT_NOEXCEPT(std::size(c)); +// Can't say noexcept here because the container might not be static_assert( std::is_signed_v, ""); -// For some reason, there isn't a std::size() for initializer lists, so it uses the generic one assert ( std::ssize(c) == static_cast(c.size())); } -template -void test_container(C& c) +template +void test_const_container(const std::initializer_list& c) { -// Can't say noexcept here because the container might not be + LIBCPP_ASSERT_NOEXCEPT(std::ssize(c)); // our std::ssize is conditionally noexcept static_assert( std::is_signed_v, ""); assert ( std::ssize(c) == static_cast(c.size())); } @@ -56,8 +57,7 @@ template void test_container(std::initializer_list& c) { -// ASSERT_NOEXCEPT(std::size(c)); -// For some reason, there isn't a std::size() for initializer lists, so it uses the generic one + LIBCPP_ASSERT_NOEXCEPT(std::ssize(c)); // our std::ssize is conditionally noexcept static_assert( std::is_signed_v, ""); assert ( std::ssize(c) == static_cast(c.size())); } @@ -66,6 +66,7 @@ void test_const_array(const T (&array)[Sz]) { ASSERT_NOEXCEPT(std::ssize(array)); + static_assert( std::is_signed_v, ""); assert ( std::ssize(array) == Sz ); } @@ -113,6 +114,7 @@ static_assert( std::numeric_limits< decltype(std::ssize(sc))>::max() > 60000, ""); static_assert( std::numeric_limits>::max() < 60000, ""); assert (std::ssize(sc) == 60000); + LIBCPP_ASSERT_NOT_NOEXCEPT(std::ssize(sc)); return 0; }