-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Optimize the is_permutation family and _Hash::operator== for multicontainers #423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fea9cba
3d7f760
ce1ff2d
02c0d90
49bac6f
38453b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4658,18 +4658,6 @@ template <class _ExPo, class _FwdIt, class _Ty, _Enable_if_execution_policy_t<_E | |
| _NODISCARD _FwdIt find(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates | ||
| #endif // _HAS_CXX17 | ||
|
|
||
| // FUNCTION TEMPLATE _Find_pr | ||
| template <class _InIt, class _Ty, class _Pr> | ||
| _InIt _Find_pr(_InIt _First, _InIt _Last, const _Ty& _Val, _Pr _Pred) { // find first matching _Val, using _Pred | ||
| for (; _First != _Last; ++_First) { | ||
| if (_Pred(*_First, _Val)) { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| return _First; | ||
| } | ||
|
|
||
| // FUNCTION TEMPLATE count | ||
| template <class _InIt, class _Ty> | ||
| _NODISCARD _Iter_diff_t<_InIt> count(const _InIt _First, const _InIt _Last, const _Ty& _Val) { | ||
|
|
@@ -4694,10 +4682,20 @@ _NODISCARD _Iter_diff_t<_FwdIt> count( | |
| _ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates | ||
| #endif // _HAS_CXX17 | ||
|
|
||
| // FUNCTION TEMPLATE _Count_pr | ||
| // FUNCTION TEMPLATE is_permutation | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, #279 tracks a possible improvement to
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do agree that looks interesting but would prefer that be a separate change (as it'll need its own perf tests and similar justification) |
||
| template <class _InIt, class _Ty, class _Pr> | ||
| _Iter_diff_t<_InIt> _Count_pr(_InIt _First, _InIt _Last, const _Ty& _Val, _Pr _Pred) { | ||
| // count elements that match _Val, using _Pred | ||
| _NODISCARD _InIt _Find_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { | ||
BillyONeal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| for (; _First != _Last; ++_First) { | ||
| if (_Pred(*_First, _Val)) { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| return _First; | ||
| } | ||
|
|
||
| template <class _InIt, class _Ty, class _Pr> | ||
| _NODISCARD _Iter_diff_t<_InIt> _Count_pr(_InIt _First, const _InIt _Last, const _Ty& _Val, _Pr _Pred) { | ||
| _Iter_diff_t<_InIt> _Count = 0; | ||
|
|
||
| for (; _First != _Last; ++_First) { | ||
|
|
@@ -4709,7 +4707,7 @@ _Iter_diff_t<_InIt> _Count_pr(_InIt _First, _InIt _Last, const _Ty& _Val, _Pr _P | |
| return _Count; | ||
| } | ||
|
|
||
| // FUNCTION TEMPLATE _Trim_matching_suffixes | ||
| #if !_HAS_IF_CONSTEXPR | ||
| template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
| void _Trim_matching_suffixes(_FwdIt1&, _FwdIt2&, _Pr, forward_iterator_tag, forward_iterator_tag) { | ||
| // trim matching suffixes, forward iterators (do nothing) | ||
|
|
@@ -4727,39 +4725,53 @@ void _Trim_matching_suffixes( | |
| ++_Last1; | ||
| ++_Last2; | ||
| } | ||
| #endif // !_HAS_IF_CONSTEXPR | ||
|
|
||
| // FUNCTION TEMPLATE _Check_match_counts | ||
| template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
| bool _Check_match_counts(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { | ||
| // test if [_First1, _Last1) == permuted [_First2, _Last2), using _Pred, same lengths | ||
| _NODISCARD bool _Check_match_counts( | ||
| const _FwdIt1 _First1, _FwdIt1 _Last1, const _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { | ||
| // test if [_First1, _Last1) == permuted [_First2, _Last2), after matching prefix removal | ||
| _STL_INTERNAL_CHECK(!_Pred(*_First1, *_First2)); | ||
| _STL_INTERNAL_CHECK(_STD distance(_First1, _Last1) == _STD distance(_First2, _Last2)); | ||
| #if _HAS_IF_CONSTEXPR | ||
| if constexpr (_Is_bidi_iter_v<_FwdIt1> && _Is_bidi_iter_v<_FwdIt2>) { | ||
| do { // find last inequality | ||
BillyONeal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| --_Last1; | ||
| --_Last2; | ||
| } while (_Pred(*_Last1, *_Last2)); | ||
| ++_Last1; | ||
| ++_Last2; | ||
| } | ||
| #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv | ||
| _Trim_matching_suffixes(_Last1, _Last2, _Pred, _Iter_cat_t<_FwdIt1>(), _Iter_cat_t<_FwdIt2>()); | ||
| #endif // _HAS_IF_CONSTEXPR | ||
| for (_FwdIt1 _Next1 = _First1; _Next1 != _Last1; ++_Next1) { | ||
| if (_Next1 == _Find_pr(_First1, _Next1, *_Next1, _Pred)) { // new value, compare match counts | ||
| _Iter_diff_t<_FwdIt2> _Count2 = _Count_pr(_First2, _Last2, *_Next1, _Pred); | ||
| if (_Count2 == 0) { | ||
| return false; // second range lacks value, fail | ||
| return false; // second range lacks value, not a permutation | ||
| } | ||
|
|
||
| _FwdIt1 _Skip1 = _Next_iter(_Next1); | ||
| _Iter_diff_t<_FwdIt1> _Count1 = _Count_pr(_Skip1, _Last1, *_Next1, _Pred) + 1; | ||
| if (_Count2 != _Count1) { | ||
| return false; // match counts differ, fail | ||
| return false; // match counts differ, not a permutation | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| // FUNCTION TEMPLATE is_permutation | ||
| template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
| bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { | ||
| _NODISCARD bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { | ||
| // test if [_First1, _Last1) == permuted [_First2, ...), using _Pred | ||
| for (; _First1 != _Last1; ++_First1, (void) ++_First2) { | ||
| for (; _First1 != _Last1; ++_First1, (void) ++_First2) { // trim matching prefix | ||
| if (!_Pred(*_First1, *_First2)) { | ||
CaseyCarter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // found first inequality, check match counts in suffix narrowing _Iter_diff_t<_FwdIt1> to | ||
| // _Iter_diff_t<_FwdIt2> is OK because if the 2nd range is shorter than the 1st, the user already | ||
| // triggered UB | ||
| // found first inequality, check match counts in suffix | ||
| // | ||
| // narrowing _Iter_diff_t<_FwdIt1> to _Iter_diff_t<_FwdIt2> is OK because if the second range is shorter | ||
| // than the first, the user already triggered UB | ||
| auto _Last2 = _STD next(_First2, static_cast<_Iter_diff_t<_FwdIt2>>(_STD distance(_First1, _Last1))); | ||
| return _Check_match_counts(_First1, _Last1, _First2, _Last2, _Pred); | ||
| } | ||
|
|
@@ -4805,17 +4817,41 @@ template <class _FwdIt1, class _FwdIt2, class _Pr> | |
| bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, | ||
| forward_iterator_tag, forward_iterator_tag) { | ||
| // test if [_First1, _Last1) == permuted [_First2, _Last2), using _Pred, arbitrary iterators | ||
| for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, (void) ++_First2) { | ||
| for (;;) { // trim matching prefix | ||
| if (_First1 == _Last1) { | ||
| return _First2 == _Last2; | ||
| } | ||
|
|
||
| if (_First2 == _Last2) { | ||
CaseyCarter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return false; | ||
| } | ||
|
|
||
| if (!_Pred(*_First1, *_First2)) { // found first inequality, check match counts in suffix | ||
| if (_STD distance(_First1, _Last1) == _STD distance(_First2, _Last2)) { | ||
| break; | ||
| } | ||
|
|
||
| ++_First1; | ||
| ++_First2; | ||
| } | ||
|
|
||
| auto _Next1 = _First1; | ||
| auto _Next2 = _First2; | ||
| for (;;) { // check for same lengths | ||
| if (_Next1 == _Last1) { | ||
| if (_Next2 == _Last2) { | ||
| return _Check_match_counts(_First1, _Last1, _First2, _Last2, _Pred); | ||
| } else { | ||
| return false; // lengths differ, fail | ||
| } | ||
|
|
||
| return false; // sequence 1 is shorter than sequence 2, not a permutation | ||
| } | ||
| } | ||
|
|
||
| return _First1 == _Last1 && _First2 == _Last2; | ||
| if (_Next2 == _Last2) { | ||
| return false; // sequence 1 is longer than sequence 2, not a permutation | ||
| } | ||
|
|
||
| ++_Next1; | ||
| ++_Next2; | ||
| } | ||
| } | ||
|
|
||
| template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
|
|
@@ -4826,7 +4862,14 @@ bool _Is_permutation_unchecked(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, | |
| return false; | ||
| } | ||
|
|
||
| return _Is_permutation_unchecked(_First1, _Last1, _First2, _Pred); | ||
| for (; _First1 != _Last1; ++_First1, (void) ++_First2) { // trim matching prefix | ||
| if (!_Pred(*_First1, *_First2)) { | ||
| // found first inequality, check match counts in suffix | ||
| return _Check_match_counts(_First1, _Last1, _First2, _Last2, _Pred); | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
|
|
@@ -4838,7 +4881,6 @@ _NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, | |
| _Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_FwdIt1>(), _Iter_cat_t<_FwdIt2>()); | ||
| } | ||
|
|
||
| // FUNCTION TEMPLATE is_permutation WITH TWO RANGES | ||
| template <class _FwdIt1, class _FwdIt2> | ||
| _NODISCARD bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { | ||
| // test if [_First1, _Last1) == permuted [_First2, _Last2) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.