From d5b988a6a99a08b0569fe920188b200fde06ae4a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 11 Feb 2019 11:09:06 +0100 Subject: [PATCH 1/5] Added ETL_NOEXCEPT macros. Added std::forward support to alternate STL utility header. --- include/etl/version.h | 2 +- support/Release notes.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/etl/version.h b/include/etl/version.h index 97efaef9..0fc8a57d 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,7 +38,7 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 9 +#define ETL_VERSION_MINOR 10 #define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/support/Release notes.txt b/support/Release notes.txt index 3db09549..2aed565d 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,8 @@ +=============================================================================== +14.10.0 +Added ETL_NOEXCEPT macros. +Added std::forward support to alternate STL utility header. + =============================================================================== 14.9.0 Added constexpr constructors to string_view and array_view. From f61a6ebfdc4ef37a53a7e1408566a0b08cba2976 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 11:12:59 +0100 Subject: [PATCH 2/5] Fix for unordered_map insert and erase bug. --- include/etl/unordered_map.h | 71 ++++++++++++++++-- include/etl/version.h | 2 +- support/Release notes.txt | 4 ++ test/main.cpp | 139 +----------------------------------- test/test_unordered_map.cpp | 30 +++++++- 5 files changed, 102 insertions(+), 144 deletions(-) diff --git a/include/etl/unordered_map.h b/include/etl/unordered_map.h index 7dabff95..c74fce4a 100644 --- a/include/etl/unordered_map.h +++ b/include/etl/unordered_map.h @@ -663,6 +663,8 @@ namespace etl pbucket->insert_after(pbucket->before_begin(), node); + adjust_first_last_markers_after_insert(pbucket); + return pbucket->begin()->key_value_pair.second; } @@ -791,10 +793,10 @@ namespace etl // Just add the pointer to the bucket; bucket.insert_after(bucket.before_begin(), node); + adjust_first_last_markers_after_insert(pbucket); + result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); result.second = true; - - adjust_first_last_markers(pbucket); } else { @@ -824,6 +826,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); @@ -889,6 +892,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 = 1; ETL_DECREMENT_DEBUG_COUNT } @@ -919,6 +923,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; @@ -954,6 +959,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; @@ -1245,15 +1251,68 @@ 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; + last = pbucket; } - else if (pbucket > last) + else { - last = pbucket; + 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. + } } } diff --git a/include/etl/version.h b/include/etl/version.h index 0fc8a57d..35a86903 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -39,7 +39,7 @@ SOFTWARE. #define ETL_VERSION_MAJOR 14 #define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 0 +#define ETL_VERSION_PATCH 1 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_WIDE_STRING(ETL_CONCAT(ETL_CONCAT(ETL_VERSION_MAJOR, ETL_VERSION_MINOR), ETL_VERSION_PATCH)) diff --git a/support/Release notes.txt b/support/Release notes.txt index 2aed565d..3dfa22ad 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.10.1 +Fix for unordered_map insert and erase bug. + =============================================================================== 14.10.0 Added ETL_NOEXCEPT macros. diff --git a/test/main.cpp b/test/main.cpp index c31aa71a..9014a36b 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -25,142 +25,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#include "etl/absolute.h" -#include "etl/algorithm.h" -#include "etl/alignment.h" -#include "etl/array.h" -#include "etl/array_view.h" -#include "etl/array_wrapper.h" -#include "etl/atomic.h" -#include "etl/basic_string.h" -#include "etl/binary.h" -#include "etl/bitset.h" -#include "etl/bit_stream.h" -#include "etl/bloom_filter.h" -#include "etl/callback.h" -#include "etl/callback_service.h" -#include "etl/callback_timer.h" -#include "etl/char_traits.h" -#include "etl/checksum.h" -#include "etl/combinations.h" -#include "etl/compare.h" -#include "etl/constant.h" -#include "etl/container.h" -#include "etl/crc16.h" -#include "etl/crc16_ccitt.h" -#include "etl/crc16_kermit.h" -#include "etl/crc16_modbus.h" -#include "etl/crc32.h" -#include "etl/crc32_c.h" -#include "etl/crc64_ecma.h" -#include "etl/crc8_ccitt.h" -#include "etl/cstring.h" -#include "etl/cumulative_moving_average.h" -#include "etl/cyclic_value.h" -#include "etl/debounce.h" -#include "etl/debug_count.h" -#include "etl/deque.h" -#include "etl/endianness.h" -#include "etl/enum_type.h" -#include "etl/error_handler.h" -#include "etl/exception.h" -#include "etl/factorial.h" -#include "etl/fibonacci.h" -#include "etl/fixed_iterator.h" -#include "etl/flat_map.h" -#include "etl/flat_multimap.h" -#include "etl/flat_multiset.h" -#include "etl/flat_set.h" -#include "etl/fnv_1.h" -#include "etl/forward_list.h" -#include "etl/frame_check_sequence.h" -#include "etl/fsm.h" -#include "etl/function.h" -#include "etl/functional.h" -#include "etl/hash.h" -#include "etl/ihash.h" -#include "etl/instance_count.h" -#include "etl/integral_limits.h" -#include "etl/intrusive_forward_list.h" -#include "etl/intrusive_links.h" -#include "etl/intrusive_list.h" -#include "etl/intrusive_queue.h" -#include "etl/intrusive_stack.h" -#include "etl/io_port.h" -#include "etl/iterator.h" -#include "etl/jenkins.h" -#include "etl/largest.h" -#include "etl/list.h" -#include "etl/log.h" -#include "etl/macros.h" -#include "etl/map.h" -#include "etl/math_constants.h" -#include "etl/memory.h" -#include "etl/memory_model.h" -#include "etl/message.h" -#include "etl/message_bus.h" -#include "etl/message_router.h" -#include "etl/message_timer.h" -#include "etl/message_types.h" -#include "etl/multimap.h" -#include "etl/multiset.h" -#include "etl/murmur3.h" -#include "etl/mutex.h" -#include "etl/nullptr.h" -#include "etl/null_type.h" -#include "etl/numeric.h" -#include "etl/observer.h" -#include "etl/optional.h" -#include "etl/packet.h" -#include "etl/parameter_type.h" -#include "etl/pearson.h" -#include "etl/permutations.h" -#include "etl/platform.h" -#include "etl/pool.h" -#include "etl/power.h" -#include "etl/priority_queue.h" -#include "etl/queue.h" -#include "etl/queue_mpmc_mutex.h" -#include "etl/queue_spsc_atomic.h" -#include "etl/queue_spsc_isr.h" -#include "etl/radix.h" -#include "etl/random.h" -#include "etl/ratio.h" -#include "etl/reference_flat_map.h" -#include "etl/reference_flat_multimap.h" -#include "etl/reference_flat_multiset.h" -#include "etl/reference_flat_set.h" -#include "etl/scaled_rounding.h" -#include "etl/scheduler.h" -#include "etl/set.h" -#include "etl/smallest.h" -#include "etl/sqrt.h" -#include "etl/stack.h" -#include "etl/state_chart.h" -#include "etl/static_assert.h" -#include "etl/string_view.h" -#include "etl/task.h" -#include "etl/timer.h" -#include "etl/type_def.h" -#include "etl/type_lookup.h" -#include "etl/type_select.h" -#include "etl/type_traits.h" -#include "etl/u16string.h" -#include "etl/u32string.h" -#include "etl/unordered_map.h" -#include "etl/unordered_multimap.h" -#include "etl/unordered_multiset.h" -#include "etl/unordered_set.h" -#include "etl/user_type.h" -#include "etl/utility.h" -#include "etl/variant.h" -#include "etl/variant_pool.h" -#include "etl/vector.h" -#include "etl/version.h" -#include "etl/visitor.h" -#include "etl/wstring.h" +#include "UnitTest++.h" int main() { - return 0; -} + return UnitTest::RunAllTests(); +} \ No newline at end of file diff --git a/test/test_unordered_map.cpp b/test/test_unordered_map.cpp index eff6662d..fb03c947 100644 --- a/test/test_unordered_map.cpp +++ b/test/test_unordered_map.cpp @@ -28,6 +28,8 @@ SOFTWARE. #include "UnitTest++.h" +#include + #include #include #include @@ -687,9 +689,35 @@ namespace } //************************************************************************* - TEST_FIXTURE(SetupFixture, test_release) + TEST_FIXTURE(SetupFixture, test_insert_and_erase_bug) { + etl::unordered_map map; + map[1] = 'b'; + map[2] = 'c'; + map[3] = 'd'; + map[4] = 'e'; + + auto it = map.find(1); + map.erase(it); + + it = map.find(4); + map.erase(it); + + std::vector 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]); + CHECK_EQUAL('c', map[2]); + CHECK_EQUAL('d', map[3]); } }; } From 15d49227c1287dd0fb4d32bde98cb3781f844d41 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 11:18:58 +0100 Subject: [PATCH 3/5] Merge branch 'development' into hot-fix/unordered_map_erase # Conflicts: # include/etl/version.h # support/Release notes.txt --- include/etl/atomic/atomic_std.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/etl/atomic/atomic_std.h b/include/etl/atomic/atomic_std.h index e2e7fea9..7a28a930 100644 --- a/include/etl/atomic/atomic_std.h +++ b/include/etl/atomic/atomic_std.h @@ -600,6 +600,6 @@ namespace etl typedef std::atomic atomic_ptrdiff_t; typedef std::atomic atomic_intmax_t; typedef std::atomic atomic_uintmax_t; -}; +} #endif From 25ecc38700ded5eee580fb92b3042a0a01140f83 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 20:07:32 +0100 Subject: [PATCH 4/5] Fix for unordered_multimap, unordered_set and unordered_multiset insert and erase bug. --- include/etl/unordered_multimap.h | 70 +++++++++++++++++++++++++++--- include/etl/unordered_multiset.h | 70 +++++++++++++++++++++++++++--- include/etl/unordered_set.h | 70 +++++++++++++++++++++++++++--- test/vs2017/.vs/etl/v15/.gitignore | 1 + 4 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 test/vs2017/.vs/etl/v15/.gitignore diff --git a/include/etl/unordered_multimap.h b/include/etl/unordered_multimap.h index 80ff8d91..1ca8434d 100644 --- a/include/etl/unordered_multimap.h +++ b/include/etl/unordered_multimap.h @@ -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. diff --git a/include/etl/unordered_multiset.h b/include/etl/unordered_multiset.h index c6e57901..2f87bd0e 100644 --- a/include/etl/unordered_multiset.h +++ b/include/etl/unordered_multiset.h @@ -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. diff --git a/include/etl/unordered_set.h b/include/etl/unordered_set.h index fb208cb4..7331cdc0 100644 --- a/include/etl/unordered_set.h +++ b/include/etl/unordered_set.h @@ -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. diff --git a/test/vs2017/.vs/etl/v15/.gitignore b/test/vs2017/.vs/etl/v15/.gitignore new file mode 100644 index 00000000..83235bb7 --- /dev/null +++ b/test/vs2017/.vs/etl/v15/.gitignore @@ -0,0 +1 @@ +*.VC.opendb From b5b480c0518fa4f510e6df40c7eeba3ff007816b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 20:32:13 +0100 Subject: [PATCH 5/5] Fix for unordered_multimap, unordered_set and unordered_multiset insert and erase bug. --- test/test_unordered_multimap.cpp | 30 ++++++++++++++++++++++++++++++ test/test_unordered_set.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/test/test_unordered_multimap.cpp b/test/test_unordered_multimap.cpp index f0d1a2eb..7c33dc34 100644 --- a/test/test_unordered_multimap.cpp +++ b/test/test_unordered_multimap.cpp @@ -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 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 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]); + } }; } diff --git a/test/test_unordered_set.cpp b/test/test_unordered_set.cpp index 69150180..4ef47cd7 100644 --- a/test/test_unordered_set.cpp +++ b/test/test_unordered_set.cpp @@ -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 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 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]); + } }; }