Skip to content

Commit a9633aa

Browse files
authored
[libc++] Fix __hash_table::erase(iterator, iterator) to update the bucket list correctly when erasing the last bucket (#167865)
Fixes #167820
1 parent e69d2bf commit a9633aa

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

libcxx/include/__hash_table

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,6 +1910,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first, const_it
19101910
__bucket_list_[__next_chash] = __before_first;
19111911
__chash = __next_chash;
19121912
}
1913+
} else { // When __next is a nullptr we've fully erased the last bucket. Update the bucket list accordingly.
1914+
__bucket_list_[__chash] = nullptr;
19131915
}
19141916
}
19151917

libcxx/test/std/containers/unord/unord.map/unord.map.modifiers/erase_range.pass.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ int main(int, char**) {
5757
assert(c.size() == 0);
5858
assert(k == c.end());
5959
}
60+
{ // Make sure that we're properly updating the bucket list when we're erasing to the end
61+
std::unordered_map<int, int> m;
62+
m.insert(std::make_pair(1, 1));
63+
m.insert(std::make_pair(2, 2));
64+
65+
{
66+
auto pair = m.equal_range(1);
67+
assert(pair.first != pair.second);
68+
m.erase(pair.first, pair.second);
69+
}
70+
71+
{
72+
auto pair = m.equal_range(2);
73+
assert(pair.first != pair.second);
74+
m.erase(pair.first, pair.second);
75+
}
76+
77+
m.insert(std::make_pair(3, 3));
78+
assert(m.size() == 1);
79+
assert(*m.begin() == std::make_pair(3, 3));
80+
assert(++m.begin() == m.end());
81+
}
6082
#if TEST_STD_VER >= 11
6183
{
6284
typedef std::unordered_map<int,

libcxx/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/erase_range.pass.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,28 @@ int main(int, char**) {
122122
for (const auto& v : map)
123123
assert(v.first == 1 || v.first == collision_val);
124124
}
125+
{ // Make sure that we're properly updating the bucket list when we're erasing to the end
126+
std::unordered_multimap<int, int> m;
127+
m.insert(std::make_pair(1, 1));
128+
m.insert(std::make_pair(2, 2));
129+
130+
{
131+
auto pair = m.equal_range(1);
132+
assert(pair.first != pair.second);
133+
m.erase(pair.first, pair.second);
134+
}
135+
136+
{
137+
auto pair = m.equal_range(2);
138+
assert(pair.first != pair.second);
139+
m.erase(pair.first, pair.second);
140+
}
141+
142+
m.insert(std::make_pair(3, 3));
143+
assert(m.size() == 1);
144+
assert(*m.begin() == std::make_pair(3, 3));
145+
assert(++m.begin() == m.end());
146+
}
125147
#if TEST_STD_VER >= 11
126148
{
127149
typedef std::unordered_multimap<int,

libcxx/test/std/containers/unord/unord.multiset/erase_range.pass.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,28 @@ int main(int, char**) {
6464
for (const auto& v : map)
6565
assert(v == 1 || v == collision_val);
6666
}
67+
{ // Make sure that we're properly updating the bucket list when we're erasing to the end
68+
std::unordered_multiset<int> m;
69+
m.insert(1);
70+
m.insert(2);
71+
72+
{
73+
auto pair = m.equal_range(1);
74+
assert(pair.first != pair.second);
75+
m.erase(pair.first, pair.second);
76+
}
77+
78+
{
79+
auto pair = m.equal_range(2);
80+
assert(pair.first != pair.second);
81+
m.erase(pair.first, pair.second);
82+
}
83+
84+
m.insert(3);
85+
assert(m.size() == 1);
86+
assert(*m.begin() == 3);
87+
assert(++m.begin() == m.end());
88+
}
6789
#if TEST_STD_VER >= 11
6890
{
6991
typedef std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, min_allocator<int>> C;

libcxx/test/std/containers/unord/unord.set/erase_range.pass.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,28 @@ int main(int, char**) {
4747
assert(c.size() == 0);
4848
assert(k == c.end());
4949
}
50+
{ // Make sure that we're properly updating the bucket list when we're erasing to the end
51+
std::unordered_set<int> m;
52+
m.insert(1);
53+
m.insert(2);
54+
55+
{
56+
auto pair = m.equal_range(1);
57+
assert(pair.first != pair.second);
58+
m.erase(pair.first, pair.second);
59+
}
60+
61+
{
62+
auto pair = m.equal_range(2);
63+
assert(pair.first != pair.second);
64+
m.erase(pair.first, pair.second);
65+
}
66+
67+
m.insert(3);
68+
assert(m.size() == 1);
69+
assert(*m.begin() == 3);
70+
assert(++m.begin() == m.end());
71+
}
5072
#if TEST_STD_VER >= 11
5173
{
5274
typedef std::unordered_set<int, std::hash<int>, std::equal_to<int>, min_allocator<int>> C;

0 commit comments

Comments
 (0)