From 4d20cfcf4eb08217ed37c4d4c38dc395d7a66d26 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Thu, 27 Jul 2023 14:54:59 -0700 Subject: [PATCH] [libc++] Simplify single-iterator __bit_iterator algorithm specializations The single-iterator algorithms have an implementation for `false` and `true`, which are almost identical. Instead of writing two functions, this refactors the code to take the value searched for as a template parameter. This avoids a lot of code duplication and makes it easier to reason about the algorithm and their difference. Reviewed By: #libc, Mordante Spies: Mordante, libcxx-commits Differential Revision: https://reviews.llvm.org/D156033 --- libcxx/include/__bit_reference | 177 ++++++++------------------------- libcxx/include/bitset | 2 +- 2 files changed, 42 insertions(+), 137 deletions(-) diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index a6bb6d42505aed..912c5727d464be 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -179,47 +179,18 @@ private: __bit_const_reference& operator=(const __bit_const_reference&) = delete; }; -// find - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst> -__find_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) -{ - typedef __bit_iterator<_Cp, _IsConst> _It; - typedef typename _It::__storage_type __storage_type; - const int __bits_per_word = _It::__bits_per_word; - // do first partial word - if (__first.__ctz_ != 0) - { - __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); - __storage_type __dn = _VSTD::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __storage_type __b = *__first.__seg_ & __m; - if (__b) - return _It(__first.__seg_, static_cast(_VSTD::__libcpp_ctz(__b))); - if (__n == __dn) - return __first + __n; - __n -= __dn; - ++__first.__seg_; - } - // do middle whole words - for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - if (*__first.__seg_) - return _It(__first.__seg_, static_cast(_VSTD::__libcpp_ctz(*__first.__seg_))); - // do last partial word - if (__n > 0) - { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b = *__first.__seg_ & __m; - if (__b) - return _It(__first.__seg_, static_cast(_VSTD::__libcpp_ctz(__b))); - } - return _It(__first.__seg_, static_cast(__n)); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __invert_if(_Tp __v) { + if (_Invert) + return ~__v; + return __v; } -template +// find + +template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst> -__find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) +__find_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { typedef __bit_iterator<_Cp, _IsConst> _It; typedef typename _It::__storage_type __storage_type; @@ -230,7 +201,7 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = _VSTD::min(__clz_f, __n); __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __storage_type __b = ~*__first.__seg_ & __m; + __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(_VSTD::__libcpp_ctz(__b))); if (__n == __dn) @@ -239,9 +210,8 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type ++__first.__seg_; } // do middle whole words - for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - { - __storage_type __b = ~*__first.__seg_; + 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(_VSTD::__libcpp_ctz(__b))); } @@ -249,7 +219,7 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type if (__n > 0) { __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __storage_type __b = ~*__first.__seg_ & __m; + __storage_type __b = std::__invert_if(*__first.__seg_) & __m; if (__b) return _It(__first.__seg_, static_cast(_VSTD::__libcpp_ctz(__b))); } @@ -262,15 +232,15 @@ __bit_iterator<_Cp, _IsConst> find(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value) { if (static_cast(__value)) - return _VSTD::__find_bool_true(__first, static_cast(__last - __first)); - return _VSTD::__find_bool_false(__first, static_cast(__last - __first)); + return _VSTD::__find_bool(__first, static_cast(__last - __first)); + return _VSTD::__find_bool(__first, static_cast(__last - __first)); } // count -template +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __bit_iterator<_Cp, _IsConst>::difference_type -__count_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) +__count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { typedef __bit_iterator<_Cp, _IsConst> _It; typedef typename _It::__storage_type __storage_type; @@ -283,49 +253,18 @@ __count_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = _VSTD::min(__clz_f, __n); __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = _VSTD::__libcpp_popcount(*__first.__seg_ & __m); + __r = _VSTD::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); __n -= __dn; ++__first.__seg_; } // do middle whole words for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += _VSTD::__libcpp_popcount(*__first.__seg_); + __r += _VSTD::__libcpp_popcount(std::__invert_if(*__first.__seg_)); // do last partial word if (__n > 0) { __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += _VSTD::__libcpp_popcount(*__first.__seg_ & __m); - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI typename __bit_iterator<_Cp, _IsConst>::difference_type -__count_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) -{ - typedef __bit_iterator<_Cp, _IsConst> _It; - typedef typename _It::__storage_type __storage_type; - typedef typename _It::difference_type difference_type; - const int __bits_per_word = _It::__bits_per_word; - difference_type __r = 0; - // do first partial word - if (__first.__ctz_ != 0) - { - __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); - __storage_type __dn = _VSTD::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - __r = _VSTD::__libcpp_popcount(~*__first.__seg_ & __m); - __n -= __dn; - ++__first.__seg_; - } - // do middle whole words - for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) - __r += _VSTD::__libcpp_popcount(~*__first.__seg_); - // do last partial word - if (__n > 0) - { - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - __r += _VSTD::__libcpp_popcount(~*__first.__seg_ & __m); + __r += _VSTD::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); } return __r; } @@ -336,45 +275,15 @@ typename __bit_iterator<_Cp, _IsConst>::difference_type count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value) { if (static_cast(__value)) - return _VSTD::__count_bool_true(__first, static_cast(__last - __first)); - return _VSTD::__count_bool_false(__first, static_cast(__last - __first)); + return _VSTD::__count_bool(__first, static_cast(__last - __first)); + return _VSTD::__count_bool(__first, static_cast(__last - __first)); } // fill_n -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void -__fill_n_false(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n) -{ - typedef __bit_iterator<_Cp, false> _It; - typedef typename _It::__storage_type __storage_type; - const int __bits_per_word = _It::__bits_per_word; - // do first partial word - if (__first.__ctz_ != 0) - { - __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); - __storage_type __dn = _VSTD::min(__clz_f, __n); - __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - *__first.__seg_ &= ~__m; - __n -= __dn; - ++__first.__seg_; - } - // do middle whole words - __storage_type __nw = __n / __bits_per_word; - std::fill_n(std::__to_address(__first.__seg_), __nw, 0); - __n -= __nw * __bits_per_word; - // do last partial word - if (__n > 0) - { - __first.__seg_ += __nw; - __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - *__first.__seg_ &= ~__m; - } -} - -template +template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void -__fill_n_true(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n) +__fill_n(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n) { typedef __bit_iterator<_Cp, false> _It; typedef typename _It::__storage_type __storage_type; @@ -385,21 +294,26 @@ __fill_n_true(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n) __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); __storage_type __dn = _VSTD::min(__clz_f, __n); __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); - *__first.__seg_ |= __m; + if (_FillValue) + *__first.__seg_ |= __m; + else + *__first.__seg_ &= ~__m; __n -= __dn; ++__first.__seg_; } // do middle whole words __storage_type __nw = __n / __bits_per_word; - // __storage_type is always an unsigned type, so -1 sets all bits - std::fill_n(std::__to_address(__first.__seg_), __nw, static_cast<__storage_type>(-1)); + std::fill_n(std::__to_address(__first.__seg_), __nw, _FillValue ? static_cast<__storage_type>(-1) : 0); __n -= __nw * __bits_per_word; // do last partial word if (__n > 0) { __first.__seg_ += __nw; __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); - *__first.__seg_ |= __m; + if (_FillValue) + *__first.__seg_ |= __m; + else + *__first.__seg_ &= ~__m; } } @@ -411,9 +325,9 @@ fill_n(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n, bool __v if (__n > 0) { if (__value) - _VSTD::__fill_n_true(__first, __n); + _VSTD::__fill_n(__first, __n); else - _VSTD::__fill_n_false(__first, __n); + _VSTD::__fill_n(__first, __n); } } @@ -1276,13 +1190,9 @@ private: friend class __bit_const_reference<_Cp>; friend class __bit_iterator<_Cp, true>; template friend struct __bit_array; - template + template _LIBCPP_CONSTEXPR_SINCE_CXX20 - friend void __fill_n_false(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n); - - template - _LIBCPP_CONSTEXPR_SINCE_CXX20 - friend void __fill_n_true(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n); + friend void __fill_n(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n); template _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -1343,17 +1253,12 @@ private: friend bool equal(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); - template - _LIBCPP_CONSTEXPR_SINCE_CXX20 - friend __bit_iterator<_Dp, _IC> __find_bool_true(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); - template + template _LIBCPP_CONSTEXPR_SINCE_CXX20 - friend __bit_iterator<_Dp, _IC> __find_bool_false(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); - template friend typename __bit_iterator<_Dp, _IC>::difference_type + friend __bit_iterator<_Dp, _IC> __find_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); + template friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 - __count_bool_true(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); - template friend typename __bit_iterator<_Dp, _IC>::difference_type - __count_bool_false(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); + __count_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); }; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/bitset b/libcxx/include/bitset index c63ee22b1dfe6c..4da0a4f29559e9 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -1012,7 +1012,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t bitset<_Size>::count() const _NOEXCEPT { - return static_cast(_VSTD::__count_bool_true(base::__make_iter(0), _Size)); + return static_cast(_VSTD::__count_bool(base::__make_iter(0), _Size)); } template