Skip to content

Commit 8dbf8de

Browse files
committed
Optimize ranges::equal for vector<bool>::iterator
1 parent 6e3631d commit 8dbf8de

File tree

6 files changed

+413
-221
lines changed

6 files changed

+413
-221
lines changed

libcxx/include/__algorithm/equal.h

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@
1111
#define _LIBCPP___ALGORITHM_EQUAL_H
1212

1313
#include <__algorithm/comp.h>
14+
#include <__algorithm/min.h>
1415
#include <__algorithm/unwrap_iter.h>
1516
#include <__config>
1617
#include <__functional/identity.h>
18+
#include <__functional/ranges_operations.h>
19+
#include <__fwd/bit_reference.h>
1720
#include <__iterator/distance.h>
1821
#include <__iterator/iterator_traits.h>
22+
#include <__memory/pointer_traits.h>
1923
#include <__string/constexpr_c_functions.h>
2024
#include <__type_traits/desugars_to.h>
2125
#include <__type_traits/enable_if.h>
2226
#include <__type_traits/invoke.h>
2327
#include <__type_traits/is_equality_comparable.h>
28+
#include <__type_traits/is_same.h>
2429
#include <__type_traits/is_volatile.h>
2530
#include <__utility/move.h>
2631

@@ -33,6 +38,132 @@ _LIBCPP_PUSH_MACROS
3338

3439
_LIBCPP_BEGIN_NAMESPACE_STD
3540

41+
template <class _Cp, bool _IC1, bool _IC2>
42+
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned(
43+
__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) {
44+
using _It = __bit_iterator<_Cp, _IC1>;
45+
using difference_type = typename _It::difference_type;
46+
using __storage_type = typename _It::__storage_type;
47+
48+
const int __bits_per_word = _It::__bits_per_word;
49+
difference_type __n = __last1 - __first1;
50+
if (__n > 0) {
51+
// do first word
52+
if (__first1.__ctz_ != 0) {
53+
unsigned __clz_f = __bits_per_word - __first1.__ctz_;
54+
difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
55+
__n -= __dn;
56+
__storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
57+
__storage_type __b = *__first1.__seg_ & __m;
58+
unsigned __clz_r = __bits_per_word - __first2.__ctz_;
59+
__storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
60+
__m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn));
61+
if (__first2.__ctz_ > __first1.__ctz_) {
62+
if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_)))
63+
return false;
64+
} else {
65+
if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_)))
66+
return false;
67+
}
68+
__first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word;
69+
__first2.__ctz_ = static_cast<unsigned>((__ddn + __first2.__ctz_) % __bits_per_word);
70+
__dn -= __ddn;
71+
if (__dn > 0) {
72+
__m = ~__storage_type(0) >> (__bits_per_word - __dn);
73+
if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn)))
74+
return false;
75+
__first2.__ctz_ = static_cast<unsigned>(__dn);
76+
}
77+
++__first1.__seg_;
78+
// __first1.__ctz_ = 0;
79+
}
80+
// __first1.__ctz_ == 0;
81+
// do middle words
82+
unsigned __clz_r = __bits_per_word - __first2.__ctz_;
83+
__storage_type __m = ~__storage_type(0) << __first2.__ctz_;
84+
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) {
85+
__storage_type __b = *__first1.__seg_;
86+
if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_))
87+
return false;
88+
++__first2.__seg_;
89+
if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r))
90+
return false;
91+
}
92+
// do last word
93+
if (__n > 0) {
94+
__m = ~__storage_type(0) >> (__bits_per_word - __n);
95+
__storage_type __b = *__first1.__seg_ & __m;
96+
__storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r));
97+
__m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn));
98+
if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_))
99+
return false;
100+
__first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word;
101+
__first2.__ctz_ = static_cast<unsigned>((__dn + __first2.__ctz_) % __bits_per_word);
102+
__n -= __dn;
103+
if (__n > 0) {
104+
__m = ~__storage_type(0) >> (__bits_per_word - __n);
105+
if ((*__first2.__seg_ & __m) != (__b >> __dn))
106+
return false;
107+
}
108+
}
109+
}
110+
return true;
111+
}
112+
113+
template <class _Cp, bool _IC1, bool _IC2>
114+
[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned(
115+
__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) {
116+
using _It = __bit_iterator<_Cp, _IC1>;
117+
using difference_type = typename _It::difference_type;
118+
using __storage_type = typename _It::__storage_type;
119+
120+
const int __bits_per_word = _It::__bits_per_word;
121+
difference_type __n = __last1 - __first1;
122+
if (__n > 0) {
123+
// do first word
124+
if (__first1.__ctz_ != 0) {
125+
unsigned __clz = __bits_per_word - __first1.__ctz_;
126+
difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
127+
__n -= __dn;
128+
__storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn));
129+
if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m))
130+
return false;
131+
++__first2.__seg_;
132+
++__first1.__seg_;
133+
// __first1.__ctz_ = 0;
134+
// __first2.__ctz_ = 0;
135+
}
136+
// __first1.__ctz_ == 0;
137+
// __first2.__ctz_ == 0;
138+
// do middle words
139+
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_)
140+
if (*__first2.__seg_ != *__first1.__seg_)
141+
return false;
142+
// do last word
143+
if (__n > 0) {
144+
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
145+
if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m))
146+
return false;
147+
}
148+
}
149+
return true;
150+
}
151+
152+
template <class _Cp,
153+
bool _IC1,
154+
bool _IC2,
155+
class _BinaryPredicate,
156+
__enable_if_t<std::is_same<_BinaryPredicate, __equal_to>::value, int> = 0>
157+
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl(
158+
__bit_iterator<_Cp, _IC1> __first1,
159+
__bit_iterator<_Cp, _IC1> __last1,
160+
__bit_iterator<_Cp, _IC2> __first2,
161+
_BinaryPredicate) {
162+
if (__first1.__ctz_ == __first2.__ctz_)
163+
return std::__equal_aligned(__first1, __last1, __first2);
164+
return std::__equal_unaligned(__first1, __last1, __first2);
165+
}
166+
36167
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
37168
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl(
38169
_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) {
@@ -94,6 +225,26 @@ __equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&,
94225
return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1));
95226
}
96227

228+
template <class _Cp,
229+
bool _IC1,
230+
bool _IC2,
231+
class _Pred,
232+
class _Proj1,
233+
class _Proj2,
234+
__enable_if_t<(is_same<_Pred, ranges::equal_to>::value || is_same<_Pred, __equal_to>::value) &&
235+
__is_identity<_Proj1>::value && __is_identity<_Proj2>::value,
236+
int> = 0>
237+
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl(
238+
__bit_iterator<_Cp, _IC1> __first1,
239+
__bit_iterator<_Cp, _IC1> __last1,
240+
__bit_iterator<_Cp, _IC2> __first2,
241+
__bit_iterator<_Cp, _IC2>,
242+
_Pred&,
243+
_Proj1&,
244+
_Proj2&) {
245+
return std::__equal_iter_impl(__first1, __last1, __first2, __equal_to());
246+
}
247+
97248
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
98249
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
99250
equal(_InputIterator1 __first1,

libcxx/include/__bit_reference

Lines changed: 11 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#ifndef _LIBCPP___BIT_REFERENCE
1111
#define _LIBCPP___BIT_REFERENCE
1212

13+
#include <__algorithm/comp.h>
1314
#include <__algorithm/copy_n.h>
15+
#include <__algorithm/equal.h>
1416
#include <__algorithm/min.h>
1517
#include <__bit/countr.h>
1618
#include <__compare/ordering.h>
@@ -21,7 +23,9 @@
2123
#include <__memory/construct_at.h>
2224
#include <__memory/pointer_traits.h>
2325
#include <__type_traits/conditional.h>
26+
#include <__type_traits/enable_if.h>
2427
#include <__type_traits/is_constant_evaluated.h>
28+
#include <__type_traits/is_same.h>
2529
#include <__utility/swap.h>
2630

2731
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -655,127 +659,6 @@ rotate(__bit_iterator<_Cp, false> __first, __bit_iterator<_Cp, false> __middle,
655659
return __r;
656660
}
657661

658-
// equal
659-
660-
template <class _Cp, bool _IC1, bool _IC2>
661-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned(
662-
__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) {
663-
using _It = __bit_iterator<_Cp, _IC1>;
664-
using difference_type = typename _It::difference_type;
665-
using __storage_type = typename _It::__storage_type;
666-
667-
const int __bits_per_word = _It::__bits_per_word;
668-
difference_type __n = __last1 - __first1;
669-
if (__n > 0) {
670-
// do first word
671-
if (__first1.__ctz_ != 0) {
672-
unsigned __clz_f = __bits_per_word - __first1.__ctz_;
673-
difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
674-
__n -= __dn;
675-
__storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
676-
__storage_type __b = *__first1.__seg_ & __m;
677-
unsigned __clz_r = __bits_per_word - __first2.__ctz_;
678-
__storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
679-
__m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn));
680-
if (__first2.__ctz_ > __first1.__ctz_) {
681-
if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_)))
682-
return false;
683-
} else {
684-
if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_)))
685-
return false;
686-
}
687-
__first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word;
688-
__first2.__ctz_ = static_cast<unsigned>((__ddn + __first2.__ctz_) % __bits_per_word);
689-
__dn -= __ddn;
690-
if (__dn > 0) {
691-
__m = ~__storage_type(0) >> (__bits_per_word - __dn);
692-
if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn)))
693-
return false;
694-
__first2.__ctz_ = static_cast<unsigned>(__dn);
695-
}
696-
++__first1.__seg_;
697-
// __first1.__ctz_ = 0;
698-
}
699-
// __first1.__ctz_ == 0;
700-
// do middle words
701-
unsigned __clz_r = __bits_per_word - __first2.__ctz_;
702-
__storage_type __m = ~__storage_type(0) << __first2.__ctz_;
703-
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) {
704-
__storage_type __b = *__first1.__seg_;
705-
if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_))
706-
return false;
707-
++__first2.__seg_;
708-
if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r))
709-
return false;
710-
}
711-
// do last word
712-
if (__n > 0) {
713-
__m = ~__storage_type(0) >> (__bits_per_word - __n);
714-
__storage_type __b = *__first1.__seg_ & __m;
715-
__storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r));
716-
__m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn));
717-
if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_))
718-
return false;
719-
__first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word;
720-
__first2.__ctz_ = static_cast<unsigned>((__dn + __first2.__ctz_) % __bits_per_word);
721-
__n -= __dn;
722-
if (__n > 0) {
723-
__m = ~__storage_type(0) >> (__bits_per_word - __n);
724-
if ((*__first2.__seg_ & __m) != (__b >> __dn))
725-
return false;
726-
}
727-
}
728-
}
729-
return true;
730-
}
731-
732-
template <class _Cp, bool _IC1, bool _IC2>
733-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned(
734-
__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) {
735-
using _It = __bit_iterator<_Cp, _IC1>;
736-
using difference_type = typename _It::difference_type;
737-
using __storage_type = typename _It::__storage_type;
738-
739-
const int __bits_per_word = _It::__bits_per_word;
740-
difference_type __n = __last1 - __first1;
741-
if (__n > 0) {
742-
// do first word
743-
if (__first1.__ctz_ != 0) {
744-
unsigned __clz = __bits_per_word - __first1.__ctz_;
745-
difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
746-
__n -= __dn;
747-
__storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn));
748-
if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m))
749-
return false;
750-
++__first2.__seg_;
751-
++__first1.__seg_;
752-
// __first1.__ctz_ = 0;
753-
// __first2.__ctz_ = 0;
754-
}
755-
// __first1.__ctz_ == 0;
756-
// __first2.__ctz_ == 0;
757-
// do middle words
758-
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_)
759-
if (*__first2.__seg_ != *__first1.__seg_)
760-
return false;
761-
// do last word
762-
if (__n > 0) {
763-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
764-
if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m))
765-
return false;
766-
}
767-
}
768-
return true;
769-
}
770-
771-
template <class _Cp, bool _IC1, bool _IC2>
772-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
773-
equal(__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) {
774-
if (__first1.__ctz_ == __first2.__ctz_)
775-
return std::__equal_aligned(__first1, __last1, __first2);
776-
return std::__equal_unaligned(__first1, __last1, __first2);
777-
}
778-
779662
template <class _Cp, bool _IsConst, typename _Cp::__storage_type>
780663
class __bit_iterator {
781664
public:
@@ -1004,9 +887,13 @@ private:
1004887
template <class _Dp, bool _IC1, bool _IC2>
1005888
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
1006889
__equal_unaligned(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>);
1007-
template <class _Dp, bool _IC1, bool _IC2>
1008-
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
1009-
equal(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>);
890+
template <class _Dp,
891+
bool _IC1,
892+
bool _IC2,
893+
class _BinaryPredicate,
894+
__enable_if_t<std::is_same<_BinaryPredicate, __equal_to>::value, int> >
895+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_iter_impl(
896+
__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>, _BinaryPredicate);
1010897
template <bool _ToFind, class _Dp, bool _IC>
1011898
_LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC>
1012899
__find_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type);

libcxx/include/bitset

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ template <size_t N> struct hash<std::bitset<N>>;
130130
# include <__cxx03/bitset>
131131
#else
132132
# include <__algorithm/count.h>
133+
# include <__algorithm/equal.h>
133134
# include <__algorithm/fill.h>
134135
# include <__algorithm/fill_n.h>
135136
# include <__algorithm/find.h>

0 commit comments

Comments
 (0)