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]); } }; }