From fefda1641549cf585fdc12558187e7052cd0db58 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Fri, 10 Jan 2025 15:19:08 -0500 Subject: [PATCH 1/4] Fix ambiguous call in {ranges, std}::find --- libcxx/include/__algorithm/find.h | 10 +-- libcxx/include/__bit/countr.h | 90 ++++++++++++++++--- .../alg.nonmodifying/alg.find/find.pass.cpp | 30 +++++++ .../alg.find/ranges.find.pass.cpp | 30 +++++++ 4 files changed, 143 insertions(+), 17 deletions(-) diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 24b8b2f96443c..23c38b7d6e80b 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,10 +106,10 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); if (__n == __dn) return __first + __n; __n -= __dn; @@ -119,14 +119,14 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) { __storage_type __b = std::__invert_if(*__first.__seg_); if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } // do last partial word if (__n > 0) { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) - return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); } return _It(__first.__seg_, static_cast(__n)); } diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 2f7571133bd03..1035710600d23 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -15,6 +15,8 @@ #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,20 +40,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -template -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT { -#if __has_builtin(__builtin_ctzg) - return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); -#else // __has_builtin(__builtin_ctzg) - if (__t == 0) - return numeric_limits<_Tp>::digits; - if (sizeof(_Tp) <= sizeof(unsigned int)) +#if _LIBCPP_STD_VER >= 17 +// Implementation using constexpr if for C++ standards >= 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_ctz(static_cast(__t)); - else if (sizeof(_Tp) <= sizeof(unsigned long long)) + } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); - else { + } else { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -60,7 +61,72 @@ template } return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // __has_builtin(__builtin_ctzg) +} + +#else +// Equivalent SFINAE-based implementation for older C++ standards < 17 + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) +template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && + sizeof(_Tp) <= sizeof(unsigned long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, + __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && + sizeof(_Tp) <= sizeof(unsigned long long), + int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + return std::__libcpp_ctz(static_cast(__t)); +} + +# if _LIBCPP_STD_VER == 11 + +// Recursive constexpr implementation for C++11 due to limited constexpr support +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +} + +# else + +// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) +// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) +template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +} + +# endif // _LIBCPP_STD_VER == 11 + +#endif // _LIBCPP_STD_VER >= 17 + +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { +#if __has_builtin(__builtin_ctzg) + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index dd89f2c5ae944..a870f169e0a6b 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -16,6 +16,7 @@ // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4245 /wd4305 /wd4310 /wd4389 /wd4805 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 +// XFAIL: FROZEN-CXX03-HEADERS-FIXME // @@ -31,6 +32,7 @@ #include #include +#include "sized_allocator.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" @@ -209,6 +211,33 @@ struct TestIntegerPromotions { } }; +TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } +} + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integer_types(), TestTypes()); types::for_each(types::integer_types(), TestTypes()); @@ -227,6 +256,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); + test_bititer_with_custom_sized_types(); { // Test vector::iterator optimization std::vector vec(256 + 8); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 46accc5e36f0a..7c73e8ac73aeb 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -34,6 +34,7 @@ #include #include "almost_satisfies_types.h" +#include "sized_allocator.h" #include "test_iterators.h" struct NotEqualityComparable {}; @@ -123,6 +124,33 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; +constexpr void test_bititer_with_custom_sized_types() { + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } +} + constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { @@ -217,6 +245,8 @@ constexpr bool test() { } } + test_bititer_with_custom_sized_types(); + return true; } From a250c1bc9b15407fdc4e17b130212ed32d98ea6d Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Wed, 15 Jan 2025 19:11:16 -0500 Subject: [PATCH 2/4] Refactor --- libcxx/include/__algorithm/find.h | 2 +- libcxx/include/__bit/countr.h | 55 ++++++++----------- libcxx/include/__bit_reference | 15 +++++ libcxx/include/__fwd/bit_reference.h | 9 ++- .../alg.nonmodifying/alg.find/find.pass.cpp | 8 +-- .../alg.find/ranges.find.pass.cpp | 6 +- 6 files changed, 51 insertions(+), 44 deletions(-) diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index 23c38b7d6e80b..a7d9374b3a1c8 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -106,7 +106,7 @@ __find_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_ty if (__first.__ctz_ != 0) { __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = std::min(__clz_f, __n); - __storage_type __m = std::__middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn); + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(std::__countr_zero(__b))); diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 1035710600d23..e80be8a39520c 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -40,12 +40,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -#if _LIBCPP_STD_VER >= 17 -// Implementation using constexpr if for C++ standards >= 17 +#ifndef _LIBCPP_CXX03_LANG +// constexpr implementation for C++11 and later -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) -template ::value, int> = 0> -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl(_Tp __t) _NOEXCEPT { + static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types"); if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { @@ -53,6 +54,12 @@ template ::value, int> = 0> } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { +# if _LIBCPP_STD_VER == 11 + // A recursive constexpr implementation for C++11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +# else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -60,53 +67,36 @@ template ::value, int> = 0> __t >>= __ulldigits; } return __ret + std::__libcpp_ctz(static_cast(__t)); +# endif } } #else -// Equivalent SFINAE-based implementation for older C++ standards < 17 +// implementation for C++03 -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case) template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && sizeof(_Tp) <= sizeof(unsigned long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { return std::__libcpp_ctz(static_cast(__t)); } -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && sizeof(_Tp) <= sizeof(unsigned long long), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { return std::__libcpp_ctz(static_cast(__t)); } -# if _LIBCPP_STD_VER == 11 - -// Recursive constexpr implementation for C++11 due to limited constexpr support -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) -template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { - unsigned long long __ull = static_cast(__t); - const unsigned int __ulldigits = numeric_limits::digits; - return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -} - -# else - -// Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98) -// Precondition: __t != 0 (This is guaranteed by the caller __countr_zero) template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp __t) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -116,16 +106,15 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _ return __ret + std::__libcpp_ctz(static_cast(__t)); } -# endif // _LIBCPP_STD_VER == 11 - -#endif // _LIBCPP_STD_VER >= 17 +#endif // _LIBCPP_CXX03_LANG -template ::value, int> = 0> +template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { + static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); #if __has_builtin(__builtin_ctzg) return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else - return __t != 0 ? __countr_zero_impl(__t) : numeric_limits<_Tp>::digits; + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; #endif } diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 079d1de9dd523..dc959ce5f8e6a 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -18,6 +18,7 @@ #include <__algorithm/min.h> #include <__assert> #include <__bit/countr.h> +#include <__bit/invert_if.h> #include <__compare/ordering.h> #include <__config> #include <__cstddef/ptrdiff_t.h> @@ -67,6 +68,20 @@ struct __size_difference_type_traits<_Cp, __void_t +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { + static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); + return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { + static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); + return static_cast<_StorageType>( + static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz)); +} + // This function is designed to operate correctly even for smaller integral types like `uint8_t`, `uint16_t`, // or `unsigned short`. Casting back to _StorageType is crucial to prevent undefined behavior that can arise // from integral promotions. diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h index d65f043e89ad6..73f3bc07736dd 100644 --- a/libcxx/include/__fwd/bit_reference.h +++ b/libcxx/include/__fwd/bit_reference.h @@ -10,9 +10,6 @@ #define _LIBCPP___FWD_BIT_REFERENCE_H #include <__config> -#include <__memory/pointer_traits.h> -#include <__type_traits/enable_if.h> -#include <__type_traits/is_unsigned.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -30,6 +27,12 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __fill_masked_range(_StoragePointer __word, unsigned __ctz, unsigned __clz, bool __fill_val); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index a870f169e0a6b..12f2530c467fc 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -211,7 +211,7 @@ struct TestIntegerPromotions { } }; -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { +TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -220,7 +220,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -232,7 +232,7 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } @@ -256,7 +256,7 @@ TEST_CONSTEXPR_CXX20 bool test() { #endif types::for_each(types::integral_types(), TestIntegerPromotions()); - test_bititer_with_custom_sized_types(); + test_bit_iterator_with_custom_sized_types(); { // Test vector::iterator optimization std::vector vec(256 + 8); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 7c73e8ac73aeb..dba040d2c0448 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -124,7 +124,7 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; -constexpr void test_bititer_with_custom_sized_types() { +constexpr void test_bit_iterator_with_custom_sized_types() { { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -133,7 +133,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(199, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } @@ -145,7 +145,7 @@ constexpr void test_bititer_with_custom_sized_types() { } { using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); + std::vector in(257, false, Alloc(1)); in[in.size() - 2] = true; assert(std::ranges::find(in, true) == in.end() - 2); } From 4ec181e069a8a62cbed89ed38ff4d2f03576dda2 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Tue, 11 Feb 2025 18:44:23 -0500 Subject: [PATCH 3/4] Unify __countr_zero_impl for C++03 and later --- libcxx/include/__bit/countr.h | 61 ++++--------------- libcxx/include/__bit_reference | 10 ++- .../alg.nonmodifying/alg.find/find.pass.cpp | 45 +++++++------- .../alg.find/ranges.find.pass.cpp | 54 ++++++++-------- 4 files changed, 70 insertions(+), 100 deletions(-) diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index e80be8a39520c..ae0ee4fbeed38 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -12,10 +12,10 @@ #ifndef _LIBCPP___BIT_COUNTR_H #define _LIBCPP___BIT_COUNTR_H +#include <__assert> #include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> -#include <__type_traits/enable_if.h> #include <__type_traits/is_unsigned.h> #include @@ -40,26 +40,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD return __builtin_ctzll(__x); } -#ifndef _LIBCPP_CXX03_LANG -// constexpr implementation for C++11 and later - +// A constexpr implementation for C++11 and later (using clang extensions for constexpr support) // Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) template -[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl(_Tp __t) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__t != 0, "__countr_zero_impl called with zero value"); static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types"); - if constexpr (sizeof(_Tp) <= sizeof(unsigned int)) { + // Use constexpr if as a C++17 extension for clang + if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); - } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long)) { + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { return std::__libcpp_ctz(static_cast(__t)); - } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) { return std::__libcpp_ctz(static_cast(__t)); } else { -# if _LIBCPP_STD_VER == 11 - // A recursive constexpr implementation for C++11 +#if _LIBCPP_STD_VER == 11 + // A constexpr implementation for C++11 using variable declaration as a C++14 extension for clang unsigned long long __ull = static_cast(__t); const unsigned int __ulldigits = numeric_limits::digits; return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); -# else +#else int __ret = 0; const unsigned int __ulldigits = numeric_limits::digits; while (static_cast(__t) == 0uLL) { @@ -67,47 +67,10 @@ template __t >>= __ulldigits; } return __ret + std::__libcpp_ctz(static_cast(__t)); -# endif - } -} - -#else -// implementation for C++03 - -template < class _Tp, __enable_if_t::value && sizeof(_Tp) <= sizeof(unsigned int), int> = 0> -_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { - return std::__libcpp_ctz(static_cast(__t)); -} - -template < class _Tp, - __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned int)) && - sizeof(_Tp) <= sizeof(unsigned long), - int> = 0 > -_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { - return std::__libcpp_ctz(static_cast(__t)); -} - -template < class _Tp, - __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long)) && - sizeof(_Tp) <= sizeof(unsigned long long), - int> = 0 > -_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { - return std::__libcpp_ctz(static_cast(__t)); -} - -template < class _Tp, __enable_if_t::value && (sizeof(_Tp) > sizeof(unsigned long long)), int> = 0 > -_LIBCPP_HIDE_FROM_ABI int __countr_zero_impl(_Tp __t) { - int __ret = 0; - const unsigned int __ulldigits = numeric_limits::digits; - while (static_cast(__t) == 0uLL) { - __ret += __ulldigits; - __t >>= __ulldigits; +#endif } - return __ret + std::__libcpp_ctz(static_cast(__t)); } -#endif // _LIBCPP_CXX03_LANG - template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index dc959ce5f8e6a..3930cff69c7bb 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -18,7 +18,6 @@ #include <__algorithm/min.h> #include <__assert> #include <__bit/countr.h> -#include <__bit/invert_if.h> #include <__compare/ordering.h> #include <__config> #include <__cstddef/ptrdiff_t.h> @@ -68,12 +67,21 @@ struct __size_difference_type_traits<_Cp, __void_t _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); } +// Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz), a specified number of +// trailing zeros (__ctz), and sets all bits in between to one template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index 12f2530c467fc..e0ca23c04ce5f 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -211,7 +211,29 @@ struct TestIntegerPromotions { } }; -TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { +TEST_CONSTEXPR_CXX20 bool test() { + types::for_each(types::integer_types(), TestTypes()); + types::for_each(types::integer_types(), TestTypes()); + types::for_each(types::integer_types(), TestTypes()); +#if TEST_STD_VER >= 20 + Test, TriviallyComparable>().operator()*>(); + Test, TriviallyComparable>().operator()*>(); +#endif + + // TODO: Remove the `_LIBCPP_ENABLE_EXPERIMENTAL` check once we have the FTM guarded or views::join isn't + // experimental anymore +#if TEST_STD_VER >= 20 && (!defined(_LIBCPP_VERSION) || defined(_LIBCPP_ENABLE_EXPERIMENTAL)) + { + std::vector> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + auto view = vec | std::views::join; + assert(std::find(view.begin(), view.end(), 4) == std::next(view.begin(), 3)); + } +#endif + + types::for_each(types::integral_types(), TestIntegerPromotions()); + + // Verify that the std::vector::iterator optimization works properly for allocators with custom size types + // See https://github.com/llvm/llvm-project/issues/122528 { using Alloc = sized_allocator; std::vector in(100, false, Alloc(1)); @@ -236,27 +258,6 @@ TEST_CONSTEXPR_CXX20 void test_bit_iterator_with_custom_sized_types() { in[in.size() - 2] = true; assert(std::find(in.begin(), in.end(), true) == in.end() - 2); } -} - -TEST_CONSTEXPR_CXX20 bool test() { - types::for_each(types::integer_types(), TestTypes()); - types::for_each(types::integer_types(), TestTypes()); - types::for_each(types::integer_types(), TestTypes()); -#if TEST_STD_VER >= 20 - Test, TriviallyComparable>().operator()*>(); - Test, TriviallyComparable>().operator()*>(); -#endif - -#if TEST_STD_VER >= 20 - { - std::vector> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - auto view = vec | std::views::join; - assert(std::find(view.begin(), view.end(), 4) == std::next(view.begin(), 3)); - } -#endif - - types::for_each(types::integral_types(), TestIntegerPromotions()); - test_bit_iterator_with_custom_sized_types(); { // Test vector::iterator optimization std::vector vec(256 + 8); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index dba040d2c0448..908e0d6654963 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -124,33 +124,6 @@ class TriviallyComparable { bool operator==(const TriviallyComparable&) const = default; }; -constexpr void test_bit_iterator_with_custom_sized_types() { - { - using Alloc = sized_allocator; - std::vector in(100, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(199, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(257, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } -} - constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { @@ -245,7 +218,32 @@ constexpr bool test() { } } - test_bititer_with_custom_sized_types(); + // Verify that the std::vector::iterator optimization works properly for allocators with custom size types + // See https://github.com/llvm/llvm-project/issues/122528 + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(199, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(257, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } return true; } From bcd553dd94459630200e1c62c9104e9035a888e6 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Sun, 23 Feb 2025 12:03:35 -0500 Subject: [PATCH 4/4] Remove unnecessary static_casts --- libcxx/include/__bit/countr.h | 4 +- libcxx/include/__bit_reference | 25 ++++--- .../alg.nonmodifying/alg.find/find.pass.cpp | 65 ++++++++++--------- .../alg.find/ranges.find.pass.cpp | 61 +++++++++-------- .../bitset.members/left_shift_eq.pass.cpp | 28 ++++---- 5 files changed, 96 insertions(+), 87 deletions(-) diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index ae0ee4fbeed38..46c43921fc60d 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -46,7 +46,6 @@ template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__t != 0, "__countr_zero_impl called with zero value"); static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types"); - // Use constexpr if as a C++17 extension for clang if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { return std::__libcpp_ctz(static_cast(__t)); } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { @@ -55,7 +54,6 @@ template return std::__libcpp_ctz(static_cast(__t)); } else { #if _LIBCPP_STD_VER == 11 - // A constexpr implementation for C++11 using variable declaration as a C++14 extension for clang unsigned long long __ull = static_cast(__t); const unsigned int __ulldigits = numeric_limits::digits; return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); @@ -74,7 +72,7 @@ template template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); -#if __has_builtin(__builtin_ctzg) +#if __has_builtin(__builtin_ctzg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19. return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); #else return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 3930cff69c7bb..aca300f851593 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -68,31 +68,29 @@ struct __size_difference_type_traits<_Cp, __void_t _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz) { static_assert(is_unsigned<_StorageType>::value, "__trailing_mask only works with unsigned types"); - return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz); + return static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz; } // Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz), a specified number of -// trailing zeros (__ctz), and sets all bits in between to one +// trailing zeros (__ctz), and sets all bits in between to one. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) { static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types"); - return static_cast<_StorageType>( - static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & - std::__trailing_mask<_StorageType>(__clz)); + return (static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) & + std::__trailing_mask<_StorageType>(__clz); } // This function is designed to operate correctly even for smaller integral types like `uint8_t`, `uint16_t`, -// or `unsigned short`. Casting back to _StorageType is crucial to prevent undefined behavior that can arise -// from integral promotions. +// or `unsigned short`. // See https://github.com/llvm/llvm-project/pull/122410. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void @@ -102,12 +100,11 @@ __fill_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz, bool using _StorageType = typename pointer_traits<_StoragePointer>::element_type; _LIBCPP_ASSERT_VALID_INPUT_RANGE( __ctz + __clz < sizeof(_StorageType) * CHAR_BIT, "__fill_masked_range called with invalid range"); - _StorageType __m = static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz) & - static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz); + _StorageType __m = std::__middle_mask<_StorageType>(__clz, __ctz); if (__fill_val) *__word |= __m; else - *__word &= static_cast<_StorageType>(~__m); + *__word &= ~__m; } template ::value> diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index e0ca23c04ce5f..3aaeb9c2f345f 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -220,9 +220,7 @@ TEST_CONSTEXPR_CXX20 bool test() { Test, TriviallyComparable>().operator()*>(); #endif - // TODO: Remove the `_LIBCPP_ENABLE_EXPERIMENTAL` check once we have the FTM guarded or views::join isn't - // experimental anymore -#if TEST_STD_VER >= 20 && (!defined(_LIBCPP_VERSION) || defined(_LIBCPP_ENABLE_EXPERIMENTAL)) +#if TEST_STD_VER >= 20 { std::vector> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; auto view = vec | std::views::join; @@ -232,34 +230,8 @@ TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integral_types(), TestIntegerPromotions()); - // Verify that the std::vector::iterator optimization works properly for allocators with custom size types - // See https://github.com/llvm/llvm-project/issues/122528 - { - using Alloc = sized_allocator; - std::vector in(100, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::find(in.begin(), in.end(), true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(199, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::find(in.begin(), in.end(), true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::find(in.begin(), in.end(), true) == in.end() - 2); - } { - using Alloc = sized_allocator; - std::vector in(257, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::find(in.begin(), in.end(), true) == in.end() - 2); - } - - { // Test vector::iterator optimization + // Test vector::iterator optimization std::vector vec(256 + 8); for (ptrdiff_t i = 8; i <= 256; i *= 2) { for (size_t offset = 0; offset < 8; offset += 2) { @@ -269,6 +241,39 @@ TEST_CONSTEXPR_CXX20 bool test() { assert(std::find(vec.begin() + offset, vec.end(), false) == vec.begin() + offset + i); } } + + // Verify that the std::vector::iterator optimization works properly for allocators with custom size types + // Fix https://github.com/llvm/llvm-project/issues/122528 + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(199, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(205, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(257, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::find(in.begin(), in.end(), true) == in.end() - 2); + } } return true; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 908e0d6654963..d7e6be9928a2d 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -203,7 +203,8 @@ constexpr bool test() { } } - { // Test vector::iterator optimization + { + // Test vector::iterator optimization std::vector vec(256 + 8); for (ptrdiff_t i = 8; i <= 256; i *= 2) { for (size_t offset = 0; offset < 8; offset += 2) { @@ -216,33 +217,39 @@ constexpr bool test() { std::ranges::begin(vec) + offset + i); } } - } - // Verify that the std::vector::iterator optimization works properly for allocators with custom size types - // See https://github.com/llvm/llvm-project/issues/122528 - { - using Alloc = sized_allocator; - std::vector in(100, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(199, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(200, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); - } - { - using Alloc = sized_allocator; - std::vector in(257, false, Alloc(1)); - in[in.size() - 2] = true; - assert(std::ranges::find(in, true) == in.end() - 2); + // Verify that the std::vector::iterator optimization works properly for allocators with custom size types + // See https://github.com/llvm/llvm-project/issues/122528 + { + using Alloc = sized_allocator; + std::vector in(100, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(199, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(200, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(205, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } + { + using Alloc = sized_allocator; + std::vector in(257, false, Alloc(1)); + in[in.size() - 2] = true; + assert(std::ranges::find(in, true) == in.end() - 2); + } } return true; diff --git a/libcxx/test/std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp index 521a4ff13abba..265ecb23b2985 100644 --- a/libcxx/test/std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp +++ b/libcxx/test/std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=15000000 + // bitset& operator<<=(size_t pos); // constexpr since C++23 #include @@ -18,20 +20,20 @@ template TEST_CONSTEXPR_CXX23 bool test_left_shift() { - std::vector > const cases = get_test_cases(); - for (std::size_t c = 0; c != cases.size(); ++c) { - for (std::size_t s = 0; s <= N+1; ++s) { - std::bitset v1 = cases[c]; - std::bitset v2 = v1; - v1 <<= s; - for (std::size_t i = 0; i < v1.size(); ++i) - if (i < s) - assert(v1[i] == 0); - else - assert(v1[i] == v2[i-s]); - } + std::vector > const cases = get_test_cases(); + for (std::size_t c = 0; c != cases.size(); ++c) { + for (std::size_t s = 0; s <= N + 1; ++s) { + std::bitset v1 = cases[c]; + std::bitset v2 = v1; + v1 <<= s; + for (std::size_t i = 0; i < v1.size(); ++i) + if (i < s) + assert(v1[i] == 0); + else + assert(v1[i] == v2[i - s]); } - return true; + } + return true; } int main(int, char**) {