ADL-proof implementation of `erase_if` and related algorithms (#4217)

Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
A. Jiang 2023-11-30 04:53:23 +08:00 коммит произвёл GitHub
Родитель c9d52cd6e7
Коммит 21b16b4a8f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 76 добавлений и 46 удалений

Просмотреть файл

@ -1768,12 +1768,12 @@ _NODISCARD bool operator>=(const deque<_Ty, _Alloc>& _Left, const deque<_Ty, _Al
#if _HAS_CXX20
_EXPORT_STD template <class _Ty, class _Alloc, class _Uty>
deque<_Ty, _Alloc>::size_type erase(deque<_Ty, _Alloc>& _Cont, const _Uty& _Val) {
return _Erase_remove(_Cont, _Val);
return _STD _Erase_remove(_Cont, _Val);
}
_EXPORT_STD template <class _Ty, class _Alloc, class _Pr>
deque<_Ty, _Alloc>::size_type erase_if(deque<_Ty, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_remove_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -23,12 +23,12 @@ namespace experimental {
template <class _Ty, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(deque<_Ty, _Alloc>& _Cont, _Pr _Pred) {
_Erase_remove_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Ty, class _Alloc, class _Uty>
_DEPRECATE_EXPERIMENTAL_ERASE void erase(deque<_Ty, _Alloc>& _Cont, const _Uty& _Val) {
_Erase_remove(_Cont, _Val);
_STD _Erase_remove(_Cont, _Val);
}
} // namespace fundamentals_v2

Просмотреть файл

@ -23,7 +23,7 @@ namespace experimental {
template <class _Ty, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(forward_list<_Ty, _Alloc>& _Cont, _Pr _Pred) {
_Cont.remove_if(_Pass_fn(_Pred));
_Cont.remove_if(_STD _Pass_fn(_Pred));
}
template <class _Ty, class _Alloc, class _Uty>

Просмотреть файл

@ -23,7 +23,7 @@ namespace experimental {
template <class _Ty, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(list<_Ty, _Alloc>& _Cont, _Pr _Pred) {
_Cont.remove_if(_Pass_fn(_Pred));
_Cont.remove_if(_STD _Pass_fn(_Pred));
}
template <class _Ty, class _Alloc, class _Uty>

Просмотреть файл

@ -23,12 +23,12 @@ namespace experimental {
template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(map<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(multimap<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
} // namespace fundamentals_v2

Просмотреть файл

@ -23,12 +23,12 @@ namespace experimental {
template <class _Kty, class _Keylt, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(set<_Kty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Kty, class _Keylt, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(multiset<_Kty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
} // namespace fundamentals_v2

Просмотреть файл

@ -23,12 +23,12 @@ namespace experimental {
template <class _Elem, class _Traits, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(basic_string<_Elem, _Traits, _Alloc>& _Cont, _Pr _Pred) {
_Erase_remove_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Elem, class _Traits, class _Alloc, class _Uty>
_DEPRECATE_EXPERIMENTAL_ERASE void erase(basic_string<_Elem, _Traits, _Alloc>& _Cont, const _Uty& _Val) {
_Erase_remove(_Cont, _Val);
_STD _Erase_remove(_Cont, _Val);
}
} // namespace fundamentals_v2

Просмотреть файл

@ -24,13 +24,13 @@ namespace experimental {
template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(
unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
} // namespace fundamentals_v2

Просмотреть файл

@ -23,13 +23,13 @@ namespace experimental {
template <class _Kty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Kty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(
unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
_Erase_nodes_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
} // namespace fundamentals_v2

Просмотреть файл

@ -23,12 +23,12 @@ namespace experimental {
template <class _Ty, class _Alloc, class _Pr>
_DEPRECATE_EXPERIMENTAL_ERASE void erase_if(vector<_Ty, _Alloc>& _Cont, _Pr _Pred) {
_Erase_remove_if(_Cont, _Pass_fn(_Pred));
_STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
template <class _Ty, class _Alloc, class _Uty>
_DEPRECATE_EXPERIMENTAL_ERASE void erase(vector<_Ty, _Alloc>& _Cont, const _Uty& _Val) {
_Erase_remove(_Cont, _Val);
_STD _Erase_remove(_Cont, _Val);
}
} // namespace fundamentals_v2

Просмотреть файл

@ -1619,7 +1619,7 @@ forward_list<_Ty, _Alloc>::size_type erase(forward_list<_Ty, _Alloc>& _Cont, con
_EXPORT_STD template <class _Ty, class _Alloc, class _Pr>
forward_list<_Ty, _Alloc>::size_type erase_if(forward_list<_Ty, _Alloc>& _Cont, _Pr _Pred) {
return _Cont.remove_if(_Pass_fn(_Pred));
return _Cont.remove_if(_STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -1722,12 +1722,12 @@ public:
template <class _Pr2>
void merge(list& _Right, _Pr2 _Pred) { // merge in elements from _Right, both ordered by _Pred
_Merge1(_Right, _Pass_fn(_Pred));
_Merge1(_Right, _STD _Pass_fn(_Pred));
}
template <class _Pr2>
void merge(list&& _Right, _Pr2 _Pred) { // merge in elements from _Right, both ordered by _Pred
_Merge1(_Right, _Pass_fn(_Pred));
_Merge1(_Right, _STD _Pass_fn(_Pred));
}
private:
@ -1773,7 +1773,7 @@ public:
template <class _Pr2>
void sort(_Pr2 _Pred) { // order sequence
auto& _My_data = _Mypair._Myval2;
_Scary_val::_Sort(_My_data._Myhead->_Next, _My_data._Mysize, _Pass_fn(_Pred));
_Scary_val::_Sort(_My_data._Myhead->_Next, _My_data._Mysize, _STD _Pass_fn(_Pred));
}
void reverse() noexcept { // reverse sequence
@ -1921,7 +1921,7 @@ list<_Ty, _Alloc>::size_type erase(list<_Ty, _Alloc>& _Cont, const _Uty& _Val) {
_EXPORT_STD template <class _Ty, class _Alloc, class _Pr>
list<_Ty, _Alloc>::size_type erase_if(list<_Ty, _Alloc>& _Cont, _Pr _Pred) {
return _Cont.remove_if(_Pass_fn(_Pred));
return _Cont.remove_if(_STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -448,7 +448,7 @@ void swap(map<_Kty, _Ty, _Pr, _Alloc>& _Left, map<_Kty, _Ty, _Pr, _Alloc>& _Righ
#if _HAS_CXX20
_EXPORT_STD template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
map<_Kty, _Ty, _Keylt, _Alloc>::size_type erase_if(map<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
@ -687,7 +687,7 @@ void swap(multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, multimap<_Kty, _Ty, _Pr, _All
#if _HAS_CXX20
_EXPORT_STD template <class _Kty, class _Ty, class _Keylt, class _Alloc, class _Pr>
multimap<_Kty, _Ty, _Keylt, _Alloc>::size_type erase_if(multimap<_Kty, _Ty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -256,7 +256,7 @@ void swap(set<_Kty, _Pr, _Alloc>& _Left, set<_Kty, _Pr, _Alloc>& _Right) noexcep
#if _HAS_CXX20
_EXPORT_STD template <class _Kty, class _Keylt, class _Alloc, class _Pr>
set<_Kty, _Keylt, _Alloc>::size_type erase_if(set<_Kty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
@ -474,7 +474,7 @@ void swap(multiset<_Kty, _Pr, _Alloc>& _Left, multiset<_Kty, _Pr, _Alloc>& _Righ
#if _HAS_CXX20
_EXPORT_STD template <class _Kty, class _Keylt, class _Alloc, class _Pr>
multiset<_Kty, _Keylt, _Alloc>::size_type erase_if(multiset<_Kty, _Keylt, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -532,7 +532,7 @@ void swap(unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
_EXPORT_STD template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
@ -903,7 +903,7 @@ void swap(unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
_EXPORT_STD template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_multimap<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -387,7 +387,7 @@ void swap(unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
_EXPORT_STD template <class _Kty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
@ -730,7 +730,7 @@ void swap(unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
_EXPORT_STD template <class _Kty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_multiset<_Kty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_nodes_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -2369,12 +2369,12 @@ _CONSTEXPR20 void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)
#if _HAS_CXX20
_EXPORT_STD template <class _Ty, class _Alloc, class _Uty>
constexpr vector<_Ty, _Alloc>::size_type erase(vector<_Ty, _Alloc>& _Cont, const _Uty& _Val) {
return _Erase_remove(_Cont, _Val);
return _STD _Erase_remove(_Cont, _Val);
}
_EXPORT_STD template <class _Ty, class _Alloc, class _Pr>
constexpr vector<_Ty, _Alloc>::size_type erase_if(vector<_Ty, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_remove_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -2215,9 +2215,9 @@ _NODISCARD_RAW_PTR_ALLOC _CONSTEXPR20 typename allocator_traits<_Alloc>::pointer
_EXPORT_STD template <class _FwdIt, class _Ty>
_NODISCARD_REMOVE_ALG _CONSTEXPR20 _FwdIt remove(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val) {
// remove each matching _Val
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_STD _Adl_verify_range(_First, _Last);
auto _UFirst = _STD _Get_unwrapped(_First);
const auto _ULast = _STD _Get_unwrapped(_Last);
_UFirst = _STD _Find_unchecked(_UFirst, _ULast, _Val);
auto _UNext = _UFirst;
if (_UFirst != _ULast) {
@ -2229,17 +2229,17 @@ _NODISCARD_REMOVE_ALG _CONSTEXPR20 _FwdIt remove(_FwdIt _First, const _FwdIt _La
}
}
_Seek_wrapped(_First, _UNext);
_STD _Seek_wrapped(_First, _UNext);
return _First;
}
_EXPORT_STD template <class _FwdIt, class _Pr>
_NODISCARD_REMOVE_ALG _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) {
// remove each satisfying _Pred
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_UFirst = _STD find_if(_UFirst, _ULast, _Pass_fn(_Pred));
_STD _Adl_verify_range(_First, _Last);
auto _UFirst = _STD _Get_unwrapped(_First);
const auto _ULast = _STD _Get_unwrapped(_Last);
_UFirst = _STD find_if(_UFirst, _ULast, _STD _Pass_fn(_Pred));
auto _UNext = _UFirst;
if (_UFirst != _ULast) {
while (++_UFirst != _ULast) {
@ -2250,7 +2250,7 @@ _NODISCARD_REMOVE_ALG _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt
}
}
_Seek_wrapped(_First, _UNext);
_STD _Seek_wrapped(_First, _UNext);
return _First;
}
@ -2260,7 +2260,7 @@ _CONSTEXPR20 typename _Container::size_type _Erase_remove(_Container& _Cont, con
auto _First = _Cont.begin();
const auto _Last = _Cont.end();
const auto _Old_size = _Cont.size();
_Seek_wrapped(_First, _STD remove(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val));
_STD _Seek_wrapped(_First, _STD remove(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _Val));
_Cont.erase(_First, _Last);
return _Old_size - _Cont.size();
}
@ -2271,7 +2271,7 @@ _CONSTEXPR20 typename _Container::size_type _Erase_remove_if(_Container& _Cont,
auto _First = _Cont.begin();
const auto _Last = _Cont.end();
const auto _Old_size = _Cont.size();
_Seek_wrapped(_First, _STD remove_if(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pred));
_STD _Seek_wrapped(_First, _STD remove_if(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _Pred));
_Cont.erase(_First, _Last);
return _Old_size - _Cont.size();
}

Просмотреть файл

@ -5260,13 +5260,13 @@ inline namespace literals {
_EXPORT_STD template <class _Elem, class _Traits, class _Alloc, class _Uty>
constexpr basic_string<_Elem, _Traits, _Alloc>::size_type erase(
basic_string<_Elem, _Traits, _Alloc>& _Cont, const _Uty& _Val) {
return _Erase_remove(_Cont, _Val);
return _STD _Erase_remove(_Cont, _Val);
}
_EXPORT_STD template <class _Elem, class _Traits, class _Alloc, class _Pr>
constexpr basic_string<_Elem, _Traits, _Alloc>::size_type erase_if(
basic_string<_Elem, _Traits, _Alloc>& _Cont, _Pr _Pred) {
return _Erase_remove_if(_Cont, _Pass_fn(_Pred));
return _STD _Erase_remove_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20

Просмотреть файл

@ -121,6 +121,11 @@ void test_algorithms() {
(void) std::search(varr, varr, varr, varr);
(void) std::search(iarr, iarr, iarr, iarr, validating_equal{});
(void) std::remove(varr, varr, validator{});
(void) std::remove_if(varr, varr, simple_truth{});
(void) std::remove_if(iarr, iarr, validating_truth{});
}
#if _HAS_CXX17

Просмотреть файл

@ -68,6 +68,25 @@ struct convertible_type {
T m_val;
};
#ifndef _M_CEE // TRANSITION, VSO-1659496
template <typename T>
struct tagged_falsity {
template <typename U>
bool operator()(U&&) const {
return false;
}
};
template <typename T>
struct holder {
T t;
};
struct incomplete;
using validating_falsity = tagged_falsity<holder<incomplete>>;
#endif // _M_CEE
template <typename T, typename U>
void math_operators_test(T lhs, U rhs) {
USE_VALUE(lhs * rhs);
@ -219,8 +238,14 @@ template <typename T>
void erase_if_test(T value) {
auto pr1 = [](auto) { return false; };
std::experimental::fundamentals_v2::erase_if(value, pr1);
#ifndef _M_CEE // TRANSITION, VSO-1659496
std::experimental::fundamentals_v2::erase_if(value, validating_falsity{});
#endif // _M_CEE
#if _HAS_CXX20
std::erase_if(value, pr1);
#ifndef _M_CEE // TRANSITION, VSO-1659496
std::erase_if(value, validating_falsity{});
#endif // _M_CEE
#endif // _HAS_CXX20
}