Skip to content

Commit 4d20cfc

Browse files
committed
[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
1 parent a800485 commit 4d20cfc

File tree

2 files changed

+42
-137
lines changed

2 files changed

+42
-137
lines changed

libcxx/include/__bit_reference

Lines changed: 41 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -179,47 +179,18 @@ private:
179179
__bit_const_reference& operator=(const __bit_const_reference&) = delete;
180180
};
181181

182-
// find
183-
184-
template <class _Cp, bool _IsConst>
185-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst>
186-
__find_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
187-
{
188-
typedef __bit_iterator<_Cp, _IsConst> _It;
189-
typedef typename _It::__storage_type __storage_type;
190-
const int __bits_per_word = _It::__bits_per_word;
191-
// do first partial word
192-
if (__first.__ctz_ != 0)
193-
{
194-
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
195-
__storage_type __dn = _VSTD::min(__clz_f, __n);
196-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
197-
__storage_type __b = *__first.__seg_ & __m;
198-
if (__b)
199-
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(__b)));
200-
if (__n == __dn)
201-
return __first + __n;
202-
__n -= __dn;
203-
++__first.__seg_;
204-
}
205-
// do middle whole words
206-
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
207-
if (*__first.__seg_)
208-
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(*__first.__seg_)));
209-
// do last partial word
210-
if (__n > 0)
211-
{
212-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
213-
__storage_type __b = *__first.__seg_ & __m;
214-
if (__b)
215-
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(__b)));
216-
}
217-
return _It(__first.__seg_, static_cast<unsigned>(__n));
182+
template <bool _Invert, class _Tp>
183+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __invert_if(_Tp __v) {
184+
if (_Invert)
185+
return ~__v;
186+
return __v;
218187
}
219188

220-
template <class _Cp, bool _IsConst>
189+
// find
190+
191+
template <bool _ToFind, class _Cp, bool _IsConst>
221192
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst>
222-
__find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
193+
__find_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
223194
{
224195
typedef __bit_iterator<_Cp, _IsConst> _It;
225196
typedef typename _It::__storage_type __storage_type;
@@ -230,7 +201,7 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type
230201
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
231202
__storage_type __dn = _VSTD::min(__clz_f, __n);
232203
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
233-
__storage_type __b = ~*__first.__seg_ & __m;
204+
__storage_type __b = std::__invert_if<!_ToFind>(*__first.__seg_) & __m;
234205
if (__b)
235206
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(__b)));
236207
if (__n == __dn)
@@ -239,17 +210,16 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type
239210
++__first.__seg_;
240211
}
241212
// do middle whole words
242-
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
243-
{
244-
__storage_type __b = ~*__first.__seg_;
213+
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) {
214+
__storage_type __b = std::__invert_if<!_ToFind>(*__first.__seg_);
245215
if (__b)
246216
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(__b)));
247217
}
248218
// do last partial word
249219
if (__n > 0)
250220
{
251221
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
252-
__storage_type __b = ~*__first.__seg_ & __m;
222+
__storage_type __b = std::__invert_if<!_ToFind>(*__first.__seg_) & __m;
253223
if (__b)
254224
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__libcpp_ctz(__b)));
255225
}
@@ -262,15 +232,15 @@ __bit_iterator<_Cp, _IsConst>
262232
find(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value)
263233
{
264234
if (static_cast<bool>(__value))
265-
return _VSTD::__find_bool_true(__first, static_cast<typename _Cp::size_type>(__last - __first));
266-
return _VSTD::__find_bool_false(__first, static_cast<typename _Cp::size_type>(__last - __first));
235+
return _VSTD::__find_bool<true>(__first, static_cast<typename _Cp::size_type>(__last - __first));
236+
return _VSTD::__find_bool<false>(__first, static_cast<typename _Cp::size_type>(__last - __first));
267237
}
268238

269239
// count
270240

271-
template <class _Cp, bool _IsConst>
241+
template <bool _ToCount, class _Cp, bool _IsConst>
272242
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __bit_iterator<_Cp, _IsConst>::difference_type
273-
__count_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
243+
__count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
274244
{
275245
typedef __bit_iterator<_Cp, _IsConst> _It;
276246
typedef typename _It::__storage_type __storage_type;
@@ -283,49 +253,18 @@ __count_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type
283253
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
284254
__storage_type __dn = _VSTD::min(__clz_f, __n);
285255
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
286-
__r = _VSTD::__libcpp_popcount(*__first.__seg_ & __m);
256+
__r = _VSTD::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
287257
__n -= __dn;
288258
++__first.__seg_;
289259
}
290260
// do middle whole words
291261
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
292-
__r += _VSTD::__libcpp_popcount(*__first.__seg_);
262+
__r += _VSTD::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_));
293263
// do last partial word
294264
if (__n > 0)
295265
{
296266
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
297-
__r += _VSTD::__libcpp_popcount(*__first.__seg_ & __m);
298-
}
299-
return __r;
300-
}
301-
302-
template <class _Cp, bool _IsConst>
303-
_LIBCPP_HIDE_FROM_ABI typename __bit_iterator<_Cp, _IsConst>::difference_type
304-
__count_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
305-
{
306-
typedef __bit_iterator<_Cp, _IsConst> _It;
307-
typedef typename _It::__storage_type __storage_type;
308-
typedef typename _It::difference_type difference_type;
309-
const int __bits_per_word = _It::__bits_per_word;
310-
difference_type __r = 0;
311-
// do first partial word
312-
if (__first.__ctz_ != 0)
313-
{
314-
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
315-
__storage_type __dn = _VSTD::min(__clz_f, __n);
316-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
317-
__r = _VSTD::__libcpp_popcount(~*__first.__seg_ & __m);
318-
__n -= __dn;
319-
++__first.__seg_;
320-
}
321-
// do middle whole words
322-
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
323-
__r += _VSTD::__libcpp_popcount(~*__first.__seg_);
324-
// do last partial word
325-
if (__n > 0)
326-
{
327-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
328-
__r += _VSTD::__libcpp_popcount(~*__first.__seg_ & __m);
267+
__r += _VSTD::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
329268
}
330269
return __r;
331270
}
@@ -336,45 +275,15 @@ typename __bit_iterator<_Cp, _IsConst>::difference_type
336275
count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value)
337276
{
338277
if (static_cast<bool>(__value))
339-
return _VSTD::__count_bool_true(__first, static_cast<typename _Cp::size_type>(__last - __first));
340-
return _VSTD::__count_bool_false(__first, static_cast<typename _Cp::size_type>(__last - __first));
278+
return _VSTD::__count_bool<true>(__first, static_cast<typename _Cp::size_type>(__last - __first));
279+
return _VSTD::__count_bool<false>(__first, static_cast<typename _Cp::size_type>(__last - __first));
341280
}
342281

343282
// fill_n
344283

345-
template <class _Cp>
346-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
347-
__fill_n_false(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
348-
{
349-
typedef __bit_iterator<_Cp, false> _It;
350-
typedef typename _It::__storage_type __storage_type;
351-
const int __bits_per_word = _It::__bits_per_word;
352-
// do first partial word
353-
if (__first.__ctz_ != 0)
354-
{
355-
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
356-
__storage_type __dn = _VSTD::min(__clz_f, __n);
357-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
358-
*__first.__seg_ &= ~__m;
359-
__n -= __dn;
360-
++__first.__seg_;
361-
}
362-
// do middle whole words
363-
__storage_type __nw = __n / __bits_per_word;
364-
std::fill_n(std::__to_address(__first.__seg_), __nw, 0);
365-
__n -= __nw * __bits_per_word;
366-
// do last partial word
367-
if (__n > 0)
368-
{
369-
__first.__seg_ += __nw;
370-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
371-
*__first.__seg_ &= ~__m;
372-
}
373-
}
374-
375-
template <class _Cp>
284+
template <bool _FillValue, class _Cp>
376285
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
377-
__fill_n_true(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
286+
__fill_n(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
378287
{
379288
typedef __bit_iterator<_Cp, false> _It;
380289
typedef typename _It::__storage_type __storage_type;
@@ -385,21 +294,26 @@ __fill_n_true(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
385294
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
386295
__storage_type __dn = _VSTD::min(__clz_f, __n);
387296
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
388-
*__first.__seg_ |= __m;
297+
if (_FillValue)
298+
*__first.__seg_ |= __m;
299+
else
300+
*__first.__seg_ &= ~__m;
389301
__n -= __dn;
390302
++__first.__seg_;
391303
}
392304
// do middle whole words
393305
__storage_type __nw = __n / __bits_per_word;
394-
// __storage_type is always an unsigned type, so -1 sets all bits
395-
std::fill_n(std::__to_address(__first.__seg_), __nw, static_cast<__storage_type>(-1));
306+
std::fill_n(std::__to_address(__first.__seg_), __nw, _FillValue ? static_cast<__storage_type>(-1) : 0);
396307
__n -= __nw * __bits_per_word;
397308
// do last partial word
398309
if (__n > 0)
399310
{
400311
__first.__seg_ += __nw;
401312
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
402-
*__first.__seg_ |= __m;
313+
if (_FillValue)
314+
*__first.__seg_ |= __m;
315+
else
316+
*__first.__seg_ &= ~__m;
403317
}
404318
}
405319

@@ -411,9 +325,9 @@ fill_n(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n, bool __v
411325
if (__n > 0)
412326
{
413327
if (__value)
414-
_VSTD::__fill_n_true(__first, __n);
328+
_VSTD::__fill_n<true>(__first, __n);
415329
else
416-
_VSTD::__fill_n_false(__first, __n);
330+
_VSTD::__fill_n<false>(__first, __n);
417331
}
418332
}
419333

@@ -1276,13 +1190,9 @@ private:
12761190
friend class __bit_const_reference<_Cp>;
12771191
friend class __bit_iterator<_Cp, true>;
12781192
template <class _Dp> friend struct __bit_array;
1279-
template <class _Dp>
1193+
template <bool _FillValue, class _Dp>
12801194
_LIBCPP_CONSTEXPR_SINCE_CXX20
1281-
friend void __fill_n_false(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n);
1282-
1283-
template <class _Dp>
1284-
_LIBCPP_CONSTEXPR_SINCE_CXX20
1285-
friend void __fill_n_true(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n);
1195+
friend void __fill_n(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n);
12861196

12871197
template <class _Dp, bool _IC>
12881198
_LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -1343,17 +1253,12 @@ private:
13431253
friend bool equal(__bit_iterator<_Dp, _IC1>,
13441254
__bit_iterator<_Dp, _IC1>,
13451255
__bit_iterator<_Dp, _IC2>);
1346-
template <class _Dp, bool _IC>
1347-
_LIBCPP_CONSTEXPR_SINCE_CXX20
1348-
friend __bit_iterator<_Dp, _IC> __find_bool_true(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
1349-
template <class _Dp, bool _IC>
1256+
template <bool _ToFind, class _Dp, bool _IC>
13501257
_LIBCPP_CONSTEXPR_SINCE_CXX20
1351-
friend __bit_iterator<_Dp, _IC> __find_bool_false(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
1352-
template <class _Dp, bool _IC> friend typename __bit_iterator<_Dp, _IC>::difference_type
1258+
friend __bit_iterator<_Dp, _IC> __find_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
1259+
template <bool _ToCount, class _Dp, bool _IC> friend typename __bit_iterator<_Dp, _IC>::difference_type
13531260
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23
1354-
__count_bool_true(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
1355-
template <class _Dp, bool _IC> friend typename __bit_iterator<_Dp, _IC>::difference_type
1356-
__count_bool_false(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
1261+
__count_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);
13571262
};
13581263

13591264
_LIBCPP_END_NAMESPACE_STD

libcxx/include/bitset

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23
10121012
size_t
10131013
bitset<_Size>::count() const _NOEXCEPT
10141014
{
1015-
return static_cast<size_t>(_VSTD::__count_bool_true(base::__make_iter(0), _Size));
1015+
return static_cast<size_t>(_VSTD::__count_bool<true>(base::__make_iter(0), _Size));
10161016
}
10171017

10181018
template <size_t _Size>

0 commit comments

Comments
 (0)