Fix list/forward_list implementations of remove_if and unique to deal with predicates that are part of the sequence passed in. We already do this for remove.

llvm-svn: 358534
This commit is contained in:
Marshall Clow 2019-04-16 22:11:26 +00:00
parent b2930b8631
commit 896b0c7b99
6 changed files with 107 additions and 6 deletions

View File

@ -1505,7 +1505,7 @@ template <class _Tp, class _Alloc>
void
forward_list<_Tp, _Alloc>::remove(const value_type& __v)
{
forward_list<_Tp, _Alloc> __deleted_nodes; // collect the nodes we're removing
forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing
iterator __e = end();
for (iterator __i = before_begin(); __i.__get_begin()->__next_ != nullptr;)
{
@ -1529,6 +1529,7 @@ template <class _Predicate>
void
forward_list<_Tp, _Alloc>::remove_if(_Predicate __pred)
{
forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing
iterator __e = end();
for (iterator __i = before_begin(); __i.__get_begin()->__next_ != nullptr;)
{
@ -1537,7 +1538,7 @@ forward_list<_Tp, _Alloc>::remove_if(_Predicate __pred)
iterator __j = _VSTD::next(__i, 2);
for (; __j != __e && __pred(*__j); ++__j)
;
erase_after(__i, __j);
__deleted_nodes.splice_after(__deleted_nodes.before_begin(), *this, __i, __j);
if (__j == __e)
break;
__i = __j;
@ -1552,13 +1553,14 @@ template <class _BinaryPredicate>
void
forward_list<_Tp, _Alloc>::unique(_BinaryPredicate __binary_pred)
{
forward_list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing
for (iterator __i = begin(), __e = end(); __i != __e;)
{
iterator __j = _VSTD::next(__i);
for (; __j != __e && __binary_pred(*__i, *__j); ++__j)
;
if (__i.__get_begin()->__next_ != __j.__get_unsafe_node_pointer())
erase_after(__i, __j);
__deleted_nodes.splice_after(__deleted_nodes.before_begin(), *this, __i, __j);
__i = __j;
}
}

View File

@ -2167,6 +2167,7 @@ template <class _Pred>
void
list<_Tp, _Alloc>::remove_if(_Pred __pred)
{
list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing
for (iterator __i = begin(), __e = end(); __i != __e;)
{
if (__pred(*__i))
@ -2174,7 +2175,8 @@ list<_Tp, _Alloc>::remove_if(_Pred __pred)
iterator __j = _VSTD::next(__i);
for (; __j != __e && __pred(*__j); ++__j)
;
__i = erase(__i, __j);
__deleted_nodes.splice(__deleted_nodes.end(), *this, __i, __j);
__i = __j;
if (__i != __e)
++__i;
}
@ -2196,13 +2198,16 @@ template <class _BinaryPred>
void
list<_Tp, _Alloc>::unique(_BinaryPred __binary_pred)
{
list<_Tp, _Alloc> __deleted_nodes(get_allocator()); // collect the nodes we're removing
for (iterator __i = begin(), __e = end(); __i != __e;)
{
iterator __j = _VSTD::next(__i);
for (; __j != __e && __binary_pred(*__i, *__j); ++__j)
;
if (++__i != __j)
__i = erase(__i, __j);
if (++__i != __j) {
__deleted_nodes.splice(__deleted_nodes.end(), *this, __i, __j);
__i = __j;
}
}
}

View File

@ -24,6 +24,15 @@ bool g(int i)
return i < 3;
}
struct PredLWG529 {
PredLWG529 (int i) : i_(i) {};
~PredLWG529() { i_ = -32767; }
bool operator() (const PredLWG529 &p) const { return p.i_ == i_; }
bool operator==(int i) const { return i == i_;}
int i_;
};
int main(int, char**)
{
{
@ -88,6 +97,21 @@ int main(int, char**)
assert(c1 == c2);
assert(cp.count() == static_cast<std::size_t>(std::distance(std::begin(t1), std::end(t1))));
}
{ // LWG issue #526
int a1[] = {1, 2, 1, 3, 5, 8, 11};
int a2[] = { 2, 3, 5, 8, 11};
std::forward_list<PredLWG529> c(a1, a1 + 7);
c.remove_if(std::ref(c.front()));
for (size_t i = 0; i < 5; ++i)
{
assert(!c.empty());
assert(c.front() == a2[i]);
c.pop_front();
}
assert(c.empty());
}
#if TEST_STD_VER >= 11
{
typedef int T;

View File

@ -16,6 +16,16 @@
#include "min_allocator.h"
struct PredLWG529 {
PredLWG529 (int i) : i_(i) {};
~PredLWG529() { i_ = -32767; }
bool operator() (const PredLWG529 &lhs, const PredLWG529 &rhs) const { return lhs.i_ == rhs.i_; }
bool operator==(int i) const { return i == i_;}
int i_;
};
bool g(int x, int y)
{
return x == y;
@ -71,6 +81,21 @@ int main(int, char**)
c1.unique(g);
assert(c1 == c2);
}
{ // LWG issue #526
int a1[] = {1, 1, 1, 2, 3, 5, 2, 11};
int a2[] = {1, 2, 3, 5, 2, 11};
std::forward_list<PredLWG529> c(a1, a1 + 8);
c.unique(std::ref(c.front()));
for (size_t i = 0; i < 6; ++i)
{
assert(!c.empty());
assert(c.front() == a2[i]);
c.pop_front();
}
assert(c.empty());
}
#if TEST_STD_VER >= 11
{
typedef int T;

View File

@ -27,6 +27,15 @@ bool g(int i)
return i < 3;
}
struct PredLWG529 {
PredLWG529 (int i) : i_(i) {};
~PredLWG529() { i_ = -32767; }
bool operator() (const PredLWG529 &p) const { return p.i_ == i_; }
bool operator==(int i) const { return i == i_;}
int i_;
};
typedef unary_counting_predicate<bool(*)(int), int> Predicate;
int main(int, char**)
@ -49,6 +58,19 @@ int main(int, char**)
assert(c == std::list<int>(a2, a2+2));
assert(cp.count() == 4);
}
{ // LWG issue #526
int a1[] = {1, 2, 1, 3, 5, 8, 11};
int a2[] = {2, 3, 5, 8, 11};
std::list<PredLWG529> c(a1, a1 + 7);
c.remove_if(std::ref(c.front()));
assert(c.size() == 5);
for (size_t i = 0; i < c.size(); ++i)
{
assert(c.front() == a2[i]);
c.pop_front();
}
}
#if TEST_STD_VER >= 11
{
int a1[] = {1, 2, 3, 4};

View File

@ -20,6 +20,15 @@ bool g(int x, int y)
return x == y;
}
struct PredLWG529 {
PredLWG529 (int i) : i_(i) {};
~PredLWG529() { i_ = -32767; }
bool operator() (const PredLWG529 &lhs, const PredLWG529 &rhs) const { return lhs.i_ == rhs.i_; }
bool operator==(int i) const { return i == i_;}
int i_;
};
int main(int, char**)
{
{
@ -29,6 +38,20 @@ int main(int, char**)
c.unique(g);
assert(c == std::list<int>(a2, a2+4));
}
{ // LWG issue #526
int a1[] = {1, 1, 1, 2, 3, 5, 5, 2, 11};
int a2[] = {1, 2, 3, 5, 2, 11};
std::list<PredLWG529> c(a1, a1 + 9);
c.unique(std::ref(c.front()));
assert(c.size() == 6);
for (size_t i = 0; i < c.size(); ++i)
{
assert(c.front() == a2[i]);
c.pop_front();
}
}
#if TEST_STD_VER >= 11
{
int a1[] = {2, 1, 1, 4, 4, 4, 4, 3, 3};