Merge remote-tracking branch 'origin/hot-fix/unordered_map_erase' into development

This commit is contained in:
John Wellbelove 2019-02-13 20:33:18 +01:00
commit 296056357a
6 changed files with 250 additions and 21 deletions

View File

@ -681,10 +681,9 @@ namespace etl
// Just add the pointer to the bucket;
bucket.insert_after(bucket.before_begin(), node);
adjust_first_last_markers_after_insert(pbucket);
result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
adjust_first_last_markers(pbucket);
}
else
{
@ -711,6 +710,7 @@ namespace etl
// Add the node to the end of the bucket;
bucket.insert_after(inode_previous, node);
adjust_first_last_markers_after_insert(&bucket);
++inode_previous;
result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
@ -768,6 +768,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key_value_pair.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
++n;
icurrent = iprevious;
ETL_DECREMENT_DEBUG_COUNT
@ -806,6 +807,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key_value_pair.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
ETL_DECREMENT_DEBUG_COUNT
return inext;
@ -841,6 +843,7 @@ namespace etl
local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
icurrent->key_value_pair.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(pbucket);
ETL_DECREMENT_DEBUG_COUNT
icurrent = inext;
@ -1157,16 +1160,69 @@ namespace etl
//*********************************************************************
/// Adjust the first and last markers according to the new entry.
//*********************************************************************
void adjust_first_last_markers(bucket_t* pbucket)
void adjust_first_last_markers_after_insert(bucket_t* pbucket)
{
if (pbucket < first)
if (size() == 1)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
else
{
if (pbucket < first)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
}
}
//*********************************************************************
/// Adjust the first and last markers according to the erased entry.
//*********************************************************************
void adjust_first_last_markers_after_erase(bucket_t* pbucket)
{
if (empty())
{
first = pbuckets;
last = pbuckets;
}
else
{
if (pbucket == first)
{
// We erased the first so, we need to search again from where we erased.
while (first->empty())
{
++first;
}
}
else if (pbucket == last)
{
// We erased the last, so we need to search again. Start from the first, go no further than the current last.
bucket_t* pbucket = first;
bucket_t* pend = last;
last = first;
while (pbucket != pend)
{
if (!pbucket->empty())
{
last = pbucket;
}
++pbucket;
}
}
else
{
// Nothing to do.
}
}
}
// Disable copy construction.

View File

@ -674,11 +674,10 @@ namespace etl
// Just add the pointer to the bucket;
bucket.insert_after(bucket.before_begin(), node);
adjust_first_last_markers_after_insert(&bucket);
result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
result.second = true;
adjust_first_last_markers(pbucket);
}
else
{
@ -705,6 +704,7 @@ namespace etl
// Add the node to the end of the bucket;
bucket.insert_after(inode_previous, node);
adjust_first_last_markers_after_insert(&bucket);
++inode_previous;
result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
@ -763,6 +763,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
++n;
icurrent = iprevious;
ETL_DECREMENT_DEBUG_COUNT
@ -801,6 +802,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
ETL_DECREMENT_DEBUG_COUNT
return inext;
@ -836,6 +838,7 @@ namespace etl
local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(pbucket);
ETL_DECREMENT_DEBUG_COUNT
icurrent = inext;
@ -1152,16 +1155,69 @@ namespace etl
//*********************************************************************
/// Adjust the first and last markers according to the new entry.
//*********************************************************************
void adjust_first_last_markers(bucket_t* pbucket)
void adjust_first_last_markers_after_insert(bucket_t* pbucket)
{
if (pbucket < first)
if (size() == 1)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
else
{
if (pbucket < first)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
}
}
//*********************************************************************
/// Adjust the first and last markers according to the erased entry.
//*********************************************************************
void adjust_first_last_markers_after_erase(bucket_t* pbucket)
{
if (empty())
{
first = pbuckets;
last = pbuckets;
}
else
{
if (pbucket == first)
{
// We erased the first so, we need to search again from where we erased.
while (first->empty())
{
++first;
}
}
else if (pbucket == last)
{
// We erased the last, so we need to search again. Start from the first, go no further than the current last.
bucket_t* pbucket = first;
bucket_t* pend = last;
last = first;
while (pbucket != pend)
{
if (!pbucket->empty())
{
last = pbucket;
}
++pbucket;
}
}
else
{
// Nothing to do.
}
}
}
// Disable copy construction.

View File

@ -675,11 +675,10 @@ namespace etl
// Just add the pointer to the bucket;
bucket.insert_after(bucket.before_begin(), node);
adjust_first_last_markers_after_insert(&bucket);
result.first = iterator(pbuckets + number_of_buckets, pbucket, pbucket->begin());
result.second = true;
adjust_first_last_markers(pbucket);
}
else
{
@ -709,6 +708,7 @@ namespace etl
// Add the node to the end of the bucket;
bucket.insert_after(inode_previous, node);
adjust_first_last_markers_after_insert(&bucket);
++inode_previous;
result.first = iterator(pbuckets + number_of_buckets, pbucket, inode_previous);
@ -774,6 +774,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
n = 1;
ETL_DECREMENT_DEBUG_COUNT
}
@ -804,6 +805,7 @@ namespace etl
bucket.erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(&bucket);
ETL_DECREMENT_DEBUG_COUNT
return inext;
@ -839,6 +841,7 @@ namespace etl
local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
icurrent->key.~value_type(); // Destroy the value.
pnodepool->release(&*icurrent); // Release it back to the pool.
adjust_first_last_markers_after_erase(pbucket);
ETL_DECREMENT_DEBUG_COUNT
icurrent = inext;
@ -1129,16 +1132,69 @@ namespace etl
//*********************************************************************
/// Adjust the first and last markers according to the new entry.
//*********************************************************************
void adjust_first_last_markers(bucket_t* pbucket)
void adjust_first_last_markers_after_insert(bucket_t* pbucket)
{
if (pbucket < first)
if (size() == 1)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
else
{
if (pbucket < first)
{
first = pbucket;
}
else if (pbucket > last)
{
last = pbucket;
}
}
}
//*********************************************************************
/// Adjust the first and last markers according to the erased entry.
//*********************************************************************
void adjust_first_last_markers_after_erase(bucket_t* pbucket)
{
if (empty())
{
first = pbuckets;
last = pbuckets;
}
else
{
if (pbucket == first)
{
// We erased the first so, we need to search again from where we erased.
while (first->empty())
{
++first;
}
}
else if (pbucket == last)
{
// We erased the last, so we need to search again. Start from the first, go no further than the current last.
bucket_t* pbucket = first;
bucket_t* pend = last;
last = first;
while (pbucket != pend)
{
if (!pbucket->empty())
{
last = pbucket;
}
++pbucket;
}
}
else
{
// Nothing to do.
}
}
}
// Disable copy construction.

View File

@ -614,5 +614,35 @@ namespace
data.assign(initial_data.begin(), initial_data.end());
CHECK_CLOSE(2.0, data.load_factor(), 0.01);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_and_erase_bug)
{
etl::unordered_multimap<uint32_t, char, 5> map;
map.insert(std::make_pair(1, 'b'));
map.insert(std::make_pair(2, 'c'));
map.insert(std::make_pair(3, 'd'));
map.insert(std::make_pair(4, 'e'));
auto it = map.find(1);
map.erase(it);
it = map.find(4);
map.erase(it);
std::vector<std::string> s;
for (const auto &kv : map)
{
std::stringstream ss;
ss << "map[" << kv.first << "] = " << kv.second;
s.push_back(ss.str());
}
CHECK_EQUAL(2, s.size());
CHECK_EQUAL("map[2] = c", s[0]);
CHECK_EQUAL("map[3] = d", s[1]);
}
};
}

View File

@ -453,5 +453,35 @@ namespace
data.assign(initial_data.begin(), initial_data.end());
CHECK_CLOSE(2.0, data.load_factor(), 0.01);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_and_erase_bug)
{
etl::unordered_set<uint32_t, 5> set;
set.insert(1);
set.insert(2);
set.insert(3);
set.insert(4);
auto it = set.find(1);
set.erase(it);
it = set.find(4);
set.erase(it);
std::vector<std::string> s;
for (const auto &kv : set)
{
std::stringstream ss;
ss << "set" << " = " << kv;
s.push_back(ss.str());
}
CHECK_EQUAL(2, s.size());
CHECK_EQUAL("set = 2", s[0]);
CHECK_EQUAL("set = 3", s[1]);
}
};
}

1
test/vs2017/.vs/etl/v15/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.VC.opendb