From bb52c37eca73b114820cb131641397ce9764b85b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 15 Aug 2020 21:00:18 +0100 Subject: [PATCH] Fixed issue for incorrect operation of erase(const_iterator, const_iterator) when the terminating iterator was end() for etl::unordered_map, etl::unordered_multimap, etl::unordered_set and etl::unordered_multiset. --- include/etl/unordered_map.h | 29 +++++++++++--------- include/etl/unordered_multimap.h | 25 +++++++++++------ include/etl/unordered_multiset.h | 27 ++++++++++++------- include/etl/unordered_set.h | 27 ++++++++++++------- include/etl/version.h | 2 +- library.json | 2 +- library.properties | 2 +- support/Release notes.txt | 8 +++++- test/test_unordered_map.cpp | 45 +++++++++++++++++++++++++++++++ test/test_unordered_multimap.cpp | 46 ++++++++++++++++++++++++++++++++ test/test_unordered_multiset.cpp | 46 ++++++++++++++++++++++++++++++++ test/test_unordered_set.cpp | 46 ++++++++++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 2 ++ test/vs2019/etl.vcxproj.filters | 6 +++++ 14 files changed, 271 insertions(+), 42 deletions(-) diff --git a/include/etl/unordered_map.h b/include/etl/unordered_map.h index cad0b6d9..2b3c3cf1 100644 --- a/include/etl/unordered_map.h +++ b/include/etl/unordered_map.h @@ -1033,14 +1033,19 @@ namespace etl //********************************************************************* iterator erase(const_iterator first_, const_iterator last_) { - // Make a note of the last. - iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); + // Erasing everything? + if ((first_ == begin()) && (last_ == end())) + { + clear(); + return end(); + } // Get the starting point. - bucket_t* pbucket = first_.get_bucket_list_iterator(); - local_iterator iprevious = pbucket->before_begin(); - local_iterator icurrent = first_.get_local_iterator(); - local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + bucket_t* pend_bucket = last_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. // Find the node previous to the first one. while (iprevious->etl_next != &*icurrent) @@ -1048,9 +1053,9 @@ namespace etl ++iprevious; } - while (icurrent != iend) + // Until we reach the end. + while ((icurrent != iend) || (pbucket != pend_bucket)) { - 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. @@ -1059,8 +1064,8 @@ namespace etl icurrent = inext; - // Are we there yet? - if (icurrent != iend) + // Have we not reached the end? + if ((icurrent != iend) || (pbucket != pend_bucket)) { // At the end of this bucket? if ((icurrent == pbucket->end())) @@ -1072,12 +1077,12 @@ namespace etl } while (pbucket->empty()); iprevious = pbucket->before_begin(); - icurrent = pbucket->begin(); + icurrent = pbucket->begin(); } } } - return result; + return iterator((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); } //************************************************************************* diff --git a/include/etl/unordered_multimap.h b/include/etl/unordered_multimap.h index fffa8a8d..f1dc9bac 100644 --- a/include/etl/unordered_multimap.h +++ b/include/etl/unordered_multimap.h @@ -909,14 +909,22 @@ namespace etl //********************************************************************* iterator erase(const_iterator first_, const_iterator last_) { + // Erasing everything? + if ((first_ == begin()) && (last_ == end())) + { + clear(); + return end(); + } + // Make a note of the last. iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); // Get the starting point. - bucket_t* pbucket = first_.get_bucket_list_iterator(); - local_iterator iprevious = pbucket->before_begin(); - local_iterator icurrent = first_.get_local_iterator(); - local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + bucket_t* pend_bucket = last_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. // Find the node previous to the first one. while (iprevious->etl_next != &*icurrent) @@ -924,7 +932,8 @@ namespace etl ++iprevious; } - while (icurrent != iend) + // Until we reach the end. + while ((icurrent != iend) || (pbucket != pend_bucket)) { local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. @@ -935,8 +944,8 @@ namespace etl icurrent = inext; - // Are we there yet? - if (icurrent != iend) + // Have we not reached the end? + if ((icurrent != iend) || (pbucket != pend_bucket)) { // At the end of this bucket? if ((icurrent == pbucket->end())) @@ -948,7 +957,7 @@ namespace etl } while (pbucket->empty()); iprevious = pbucket->before_begin(); - icurrent = pbucket->begin(); + icurrent = pbucket->begin(); } } } diff --git a/include/etl/unordered_multiset.h b/include/etl/unordered_multiset.h index decc866e..677a5b1c 100644 --- a/include/etl/unordered_multiset.h +++ b/include/etl/unordered_multiset.h @@ -894,22 +894,31 @@ namespace etl //********************************************************************* iterator erase(const_iterator first_, const_iterator last_) { + // Erasing everything? + if ((first_ == begin()) && (last_ == end())) + { + clear(); + return end(); + } + // Make a note of the last. iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); // Get the starting point. - bucket_t* pbucket = first_.get_bucket_list_iterator(); - local_iterator iprevious = pbucket->before_begin(); - local_iterator icurrent = first_.get_local_iterator(); - local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + bucket_t* pend_bucket = last_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. - // Find the node previous to the first one. + // Find the node previous to the first one. while (iprevious->etl_next != &*icurrent) { ++iprevious; } - while (icurrent != iend) + // Until we reach the end. + while ((icurrent != iend) || (pbucket != pend_bucket)) { local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. @@ -920,8 +929,8 @@ namespace etl icurrent = inext; - // Are we there yet? - if (icurrent != iend) + // Have we not reached the end? + if ((icurrent != iend) || (pbucket != pend_bucket)) { // At the end of this bucket? if ((icurrent == pbucket->end())) @@ -933,7 +942,7 @@ namespace etl } while (pbucket->empty()); iprevious = pbucket->before_begin(); - icurrent = pbucket->begin(); + icurrent = pbucket->begin(); } } } diff --git a/include/etl/unordered_set.h b/include/etl/unordered_set.h index b6257127..4e4322c3 100644 --- a/include/etl/unordered_set.h +++ b/include/etl/unordered_set.h @@ -912,22 +912,31 @@ namespace etl //********************************************************************* iterator erase(const_iterator first_, const_iterator last_) { + // Erasing everything? + if ((first_ == begin()) && (last_ == end())) + { + clear(); + return end(); + } + // Make a note of the last. iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); // Get the starting point. - bucket_t* pbucket = first_.get_bucket_list_iterator(); - local_iterator iprevious = pbucket->before_begin(); - local_iterator icurrent = first_.get_local_iterator(); - local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + bucket_t* pend_bucket = last_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. - // Find the node previous to the first one. + // Find the node previous to the first one. while (iprevious->etl_next != &*icurrent) { ++iprevious; } - while (icurrent != iend) + // Until we reach the end. + while ((icurrent != iend) || (pbucket != pend_bucket)) { local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. @@ -938,8 +947,8 @@ namespace etl icurrent = inext; - // Are we there yet? - if (icurrent != iend) + // Have we not reached the end? + if ((icurrent != iend) || (pbucket != pend_bucket)) { // At the end of this bucket? if ((icurrent == pbucket->end())) @@ -951,7 +960,7 @@ namespace etl } while (pbucket->empty()); iprevious = pbucket->before_begin(); - icurrent = pbucket->begin(); + icurrent = pbucket->begin(); } } } diff --git a/include/etl/version.h b/include/etl/version.h index 93d64b4a..07c33a62 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 18 #define ETL_VERSION_MINOR 12 -#define ETL_VERSION_PATCH 4 +#define ETL_VERSION_PATCH 5 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_U16 ETL_STRINGIFY(ETL_VERSION_MAJOR) u"." ETL_STRINGIFY(ETL_VERSION_MINOR) u"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index ad2a269f..f024aaba 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library", - "version": "18.12.4", + "version": "18.12.5", "authors": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index f28974df..6deb9856 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=18.12.4 +version=18.12.5 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/support/Release notes.txt b/support/Release notes.txt index 6e7cfa7d..360d40d4 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,9 @@ +=============================================================================== +18.12.5 +Fixed issue for incorrect operation of erase(const_iterator, const_iterator) when +the terminating iterator was end() for etl::unordered_map, etl::unordered_multimap, +etl::unordered_set and etl::unordered_multiset. + =============================================================================== 18.12.4 Resolve clang 9 compatibility issues. @@ -84,7 +90,7 @@ Allows set_callback() function to be given run-time and compile-time pointers to =============================================================================== 18.3.4 -Changed std::move to etl::move in std::optional and std::queue +Changed std::move to etl::move in etl::optional and etl::queue Fixed etl::span subspan with etl::dynamic_extent =============================================================================== diff --git a/test/test_unordered_map.cpp b/test/test_unordered_map.cpp index 658e4985..72b36e51 100644 --- a/test/test_unordered_map.cpp +++ b/test/test_unordered_map.cpp @@ -628,6 +628,51 @@ namespace CHECK(idata != data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_first_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator end = data.begin(); + etl::advance(end, data.size() / 2); + + auto itr = data.erase(data.begin(), end); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == end); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_last_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator begin = data.begin(); + etl::advance(begin, data.size() / 2); + + auto itr = data.erase(begin, data.end()); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_all) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + auto itr = data.erase(data.begin(), data.end()); + + CHECK_EQUAL(0U, data.size()); + CHECK(!data.full()); + CHECK(data.empty()); + CHECK(itr == data.end()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_unordered_multimap.cpp b/test/test_unordered_multimap.cpp index ea6f53b9..95d16f46 100644 --- a/test/test_unordered_multimap.cpp +++ b/test/test_unordered_multimap.cpp @@ -541,6 +541,52 @@ namespace CHECK(idata != data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_first_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator end = data.begin(); + etl::advance(end, data.size() / 2); + + auto itr = data.erase(data.begin(), end); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == end); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_last_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator begin = data.begin(); + etl::advance(begin, data.size() / 2); + + auto itr = data.erase(begin, data.end()); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_all) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + auto itr = data.erase(data.begin(), data.end()); + + CHECK_EQUAL(0U, data.size()); + CHECK(!data.full()); + CHECK(data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_unordered_multiset.cpp b/test/test_unordered_multiset.cpp index 6e47557f..6dbb3dc7 100644 --- a/test/test_unordered_multiset.cpp +++ b/test/test_unordered_multiset.cpp @@ -479,6 +479,52 @@ namespace CHECK(idata != data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_first_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator end = data.begin(); + etl::advance(end, data.size() / 2); + + auto itr = data.erase(data.begin(), end); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == end); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_last_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator begin = data.begin(); + etl::advance(begin, data.size() / 2); + + auto itr = data.erase(begin, data.end()); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_all) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + auto itr = data.erase(data.begin(), data.end()); + + CHECK_EQUAL(0U, data.size()); + CHECK(!data.full()); + CHECK(data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/test_unordered_set.cpp b/test/test_unordered_set.cpp index f55cd41c..5d316dd0 100644 --- a/test/test_unordered_set.cpp +++ b/test/test_unordered_set.cpp @@ -459,6 +459,52 @@ namespace CHECK(idata != data.end()); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_first_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator end = data.begin(); + etl::advance(end, data.size() / 2); + + auto itr = data.erase(data.begin(), end); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == end); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_last_half) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + DataNDC::iterator begin = data.begin(); + etl::advance(begin, data.size() / 2); + + auto itr = data.erase(begin, data.end()); + + CHECK_EQUAL(initial_data.size() / 2, data.size()); + CHECK(!data.full()); + CHECK(!data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range_all) + { + DataNDC data(initial_data.begin(), initial_data.end()); + + auto itr = data.erase(data.begin(), data.end()); + + CHECK_EQUAL(0U, data.size()); + CHECK(!data.full()); + CHECK(data.empty()); + CHECK(itr == data.end()); + } + + //************************************************************************* TEST_FIXTURE(SetupFixture, test_clear) { diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 59eb876a..262d2618 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1687,9 +1687,11 @@ + + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index f10c59f7..849cf756 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1444,6 +1444,9 @@ Resource Files\CI\Github + + Resource Files\Make + @@ -1458,6 +1461,9 @@ Resource Files + + Resource Files\Make +