From 48a2a4fd8d459f8e3fb270ec63e8d1c34ec5ebe5 Mon Sep 17 00:00:00 2001 From: chodimka <46093415+chodimka@users.noreply.github.com> Date: Tue, 12 Feb 2019 19:25:42 +0100 Subject: [PATCH 1/5] atomic_std: removed extra ';' semicolon after namespace (#114) --- 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 87d73bf602b889e040af32f385db7fad260bad97 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 11:29:02 +0100 Subject: [PATCH 2/5] Merge remote-tracking branch 'origin/development' # Conflicts: # include/etl/version.h # support/Release notes.txt --- 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 6aa0d0a3a516d372699b0f223438fc47c46eee86 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 13 Feb 2019 20:37:28 +0100 Subject: [PATCH 3/5] Merge remote-tracking branch 'origin/development' # Conflicts: # include/etl/version.h # support/Release notes.txt --- include/etl/unordered_multimap.h | 70 +++++++++++++++++++++++++++--- include/etl/unordered_multiset.h | 70 +++++++++++++++++++++++++++--- include/etl/unordered_set.h | 70 +++++++++++++++++++++++++++--- include/etl/version.h | 2 +- support/Release notes.txt | 4 ++ test/test_unordered_multimap.cpp | 30 +++++++++++++ test/test_unordered_set.cpp | 30 +++++++++++++ test/vs2017/.vs/etl/v15/.gitignore | 1 + 8 files changed, 255 insertions(+), 22 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/include/etl/version.h b/include/etl/version.h index 35a86903..5e652972 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 1 +#define ETL_VERSION_PATCH 2 #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 3dfa22ad..3644844d 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.10.2 +Fix for unordered_multimap, unordered_set and unordered_multiset insert and erase bug. + =============================================================================== 14.10.1 Fix for unordered_map insert and erase bug. 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]); + } }; } 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 55ed3640b202faee8de46fe288b85c93cfdd37e7 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 14 Feb 2019 12:54:28 +0100 Subject: [PATCH 4/5] Merge remote-tracking branch 'origin/development' # Conflicts: # include/etl/version.h # support/Release notes.txt --- include/etl/forward_list.h | 168 +++++++++++++++++++++++++++++++++---- include/etl/version.h | 4 +- support/Release notes.txt | 4 + test/test_forward_list.cpp | 125 +++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 18 deletions(-) diff --git a/include/etl/forward_list.h b/include/etl/forward_list.h index 038e5de3..a858e621 100644 --- a/include/etl/forward_list.h +++ b/include/etl/forward_list.h @@ -38,6 +38,7 @@ SOFTWARE. #include "stl/algorithm.h" #include "stl/iterator.h" #include "stl/functional.h" +#include "stl/utility.h" #include "pool.h" #include "container.h" @@ -377,6 +378,10 @@ namespace etl typedef const T& const_reference; typedef size_t size_type; +#if ETL_CPP11_SUPPORTED + typedef T&& rvalue_reference; +#endif + protected: //************************************************************************* @@ -717,7 +722,22 @@ namespace etl insert_node_after(start_node, data_node); } -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Pushes a value to the front of the forward_list. + //************************************************************************* + void push_front(rvalue_reference value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + + data_node_t& data_node = allocate_data_node(std::move(value)); + insert_node_after(start_node, data_node); + } +#endif + +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) //************************************************************************* /// Emplaces a value to the front of the list.. //************************************************************************* @@ -792,7 +812,7 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT insert_node_after(start_node, *p_data_node); } -#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) //************************************************************************* /// Removes a value from the front of the forward_list. @@ -870,7 +890,7 @@ namespace etl return iterator(&data_node); } -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) //************************************************************************* /// Emplaces a value to the forward_list after the specified position. //************************************************************************* @@ -950,7 +970,7 @@ namespace etl return iterator(p_data_node); } -#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) //************************************************************************* /// Inserts 'n' copies of a value to the forward_list after the specified position. @@ -1332,6 +1352,18 @@ namespace etl return *this; } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move assignment operator. + //************************************************************************* + iforward_list& operator = (iforward_list&& rhs) + { + move_container(std::move(rhs)); + + return *this; + } +#endif + protected: //************************************************************************* @@ -1381,6 +1413,63 @@ namespace etl start_node.next = nullptr; } + //************************************************************************* + /// Allocate a data_node_t. + //************************************************************************* + data_node_t& allocate_data_node(const_reference value) + { + data_node_t* p_node = p_node_pool->allocate(); + ::new (&(p_node->value)) T(value); + ETL_INCREMENT_DEBUG_COUNT + + return *p_node; + } + +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Allocate a data_node_t. + //************************************************************************* + data_node_t& allocate_data_node(rvalue_reference value) + { + data_node_t* p_node = p_node_pool->allocate(); + ::new (&(p_node->value)) T(std::move(value)); + ETL_INCREMENT_DEBUG_COUNT + + return *p_node; + } +#endif + +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move a forward list + //************************************************************************* + void move_container(iforward_list&& rhs) + { + if (&rhs != this) + { + this->initialise(); + + node_t* p_last_node = &start_node; + + etl::iforward_list::iterator first = rhs.begin(); + etl::iforward_list::iterator last = rhs.end(); + + // Add all of the elements. + while (first != last) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t& data_node = this->allocate_data_node(std::move(*first++)); + join(p_last_node, &data_node); + data_node.next = nullptr; + p_last_node = &data_node; + } + + rhs.initialise(); + } + } +#endif + private: //************************************************************************* @@ -1433,18 +1522,6 @@ namespace etl } } - //************************************************************************* - /// Allocate a data_node_t. - //************************************************************************* - data_node_t& allocate_data_node(const T& value) - { - data_node_t* p_node = p_node_pool->allocate(); - ::new (&(p_node->value)) T(value); - ETL_INCREMENT_DEBUG_COUNT - - return *p_node; - } - //************************************************************************* /// Destroy a data_node_t. //************************************************************************* @@ -1521,6 +1598,17 @@ namespace etl this->assign(other.cbegin(), other.cend()); } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move constructor. + //************************************************************************* + forward_list(forward_list&& other) + : etl::iforward_list(node_pool, MAX_SIZE, false) + { + this->move_container(std::move(other)); + } +#endif + //************************************************************************* /// Construct from range. //************************************************************************* @@ -1563,6 +1651,19 @@ namespace etl return *this; } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move assignment operator. + //************************************************************************* + forward_list& operator = (forward_list&& rhs) + { + + this->move_container(std::move(rhs)); + + return *this; + } +#endif + private: /// The pool of nodes used in the list. @@ -1631,6 +1732,29 @@ namespace etl this->assign(other.cbegin(), other.cend()); } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move constructor. + //************************************************************************* + forward_list(forward_list&& other) + : etl::iforward_list(*other.p_node_pool, other.p_node_pool->max_size(), true) + { + if (this != &other) + { + this->initialise(); + + typename etl::iforward_list::iterator itr = other.begin(); + while (itr != other.end()) + { + this->push_back(std::move(*itr)); + ++itr; + } + + other.initialise(); + } + } +#endif + //************************************************************************* /// Construct from range. //************************************************************************* @@ -1673,6 +1797,18 @@ namespace etl return *this; } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move assignment operator. + //************************************************************************* + forward_list& operator = (forward_list&& rhs) + { + this->move_container(std::move(rhs)); + + return *this; + } +#endif + //************************************************************************* /// Set the pool instance. //************************************************************************* diff --git a/include/etl/version.h b/include/etl/version.h index 5e652972..0db94648 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,8 +38,8 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 10 -#define ETL_VERSION_PATCH 2 +#define ETL_VERSION_MINOR 11 +#define ETL_VERSION_PATCH 0 #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 3644844d..d089d725 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.11.0 +Added rvalue reference interfaces to forward_list. + =============================================================================== 14.10.2 Fix for unordered_multimap, unordered_set and unordered_multiset insert and erase bug. diff --git a/test/test_forward_list.cpp b/test/test_forward_list.cpp index c63e8e44..b2f220a6 100644 --- a/test/test_forward_list.cpp +++ b/test/test_forward_list.cpp @@ -48,11 +48,15 @@ namespace typedef TestDataDC ItemDC; typedef TestDataNDC ItemNDC; + typedef TestDataM ItemM; typedef etl::forward_list DataDC; typedef etl::forward_list DataNDC; typedef etl::iforward_list IDataNDC; + typedef etl::forward_list DataM; + typedef etl::iforward_list IDataM; + typedef etl::forward_list DataInt; typedef std::forward_list CompareDataDC; @@ -170,6 +174,98 @@ namespace CHECK(std::equal(data.begin(), data.end(), other_data.begin())); } + //************************************************************************* + TEST(test_move_constructor) + { + ItemM p1(1U); + ItemM p2(2U); + ItemM p3(3U); + ItemM p4(4U); + + DataM data1; + data1.push_front(std::move(p1)); + data1.push_front(std::move(p2)); + data1.push_front(std::move(p3)); + data1.push_front(std::move(p4)); + + CHECK(!bool(p1)); + CHECK(!bool(p2)); + CHECK(!bool(p3)); + CHECK(!bool(p4)); + + DataM data2(std::move(data1)); + + CHECK_EQUAL(0U, data1.size()); + CHECK_EQUAL(4U, data2.size()); + + DataM::const_iterator itr = data2.begin(); + + CHECK_EQUAL(4U, (*itr++).value); + CHECK_EQUAL(3U, (*itr++).value); + CHECK_EQUAL(2U, (*itr++).value); + CHECK_EQUAL(1U, (*itr++).value); + } + + //************************************************************************* + TEST(test_move_assignment) + { + ItemM p1(1U); + ItemM p2(2U); + ItemM p3(3U); + ItemM p4(4U); + + DataM data1; + data1.push_front(std::move(p1)); + data1.push_front(std::move(p2)); + data1.push_front(std::move(p3)); + data1.push_front(std::move(p4)); + + DataM data2; + data2 = std::move(data1); + + CHECK_EQUAL(0U, data1.size()); + CHECK_EQUAL(4U, data2.size()); + + DataM::const_iterator itr = data2.begin(); + + CHECK_EQUAL(4U, (*itr++).value); + CHECK_EQUAL(3U, (*itr++).value); + CHECK_EQUAL(2U, (*itr++).value); + CHECK_EQUAL(1U, (*itr++).value); + } + + //************************************************************************* + TEST(test_move_assignment_interface) + { + ItemM p1(1U); + ItemM p2(2U); + ItemM p3(3U); + ItemM p4(4U); + + DataM data1; + data1.push_front(std::move(p1)); + data1.push_front(std::move(p2)); + data1.push_front(std::move(p3)); + data1.push_front(std::move(p4)); + + DataM data2; + + IDataM& idata1 = data1; + IDataM& idata2 = data2; + + idata2 = std::move(idata1); + + CHECK_EQUAL(0U, data1.size()); + CHECK_EQUAL(4U, data2.size()); + + DataM::const_iterator itr = data2.begin(); + + CHECK_EQUAL(4U, (*itr++).value); + CHECK_EQUAL(3U, (*itr++).value); + CHECK_EQUAL(2U, (*itr++).value); + CHECK_EQUAL(1U, (*itr++).value); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_iterator) { @@ -501,6 +597,35 @@ namespace CHECK(are_equal); } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front_move) + { + ItemM p1(1U); + ItemM p2(2U); + ItemM p3(3U); + ItemM p4(4U); + + DataM data; + data.push_front(std::move(p1)); + data.push_front(std::move(p2)); + data.push_front(std::move(p3)); + data.push_front(std::move(p4)); + + CHECK_EQUAL(4U, data.size()); + + CHECK(!bool(p1)); + CHECK(!bool(p2)); + CHECK(!bool(p3)); + CHECK(!bool(p4)); + + DataM::const_iterator itr = data.begin(); + + CHECK_EQUAL(4U, (*itr++).value); + CHECK_EQUAL(3U, (*itr++).value); + CHECK_EQUAL(2U, (*itr++).value); + CHECK_EQUAL(1U, (*itr++).value); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_emplace_front) { From 3a389a9d9642e1f98e0e46a82bbcc1edd6510e22 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 14 Feb 2019 14:48:31 +0100 Subject: [PATCH 5/5] Created C++03 Code::Blocks project as a quick check for C++03 syntax compatibility. --- include/etl/math_constants.h | 2 +- include/etl/queue_mpmc_mutex.h | 2 +- include/etl/queue_spsc_atomic.h | 2 +- include/etl/queue_spsc_isr.h | 2 +- test/codeblocks/ETLcpp03.cbp | 3 +- test/maincpp03check.cpp | 169 ++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 test/maincpp03check.cpp diff --git a/include/etl/math_constants.h b/include/etl/math_constants.h index 1e26747d..bc76cfcd 100644 --- a/include/etl/math_constants.h +++ b/include/etl/math_constants.h @@ -45,7 +45,7 @@ namespace etl const double root2_reciprocal = 0.70710678118655; const double euler = 0.57721566490153; const double golden_ratio = 1.61803398874989; - }; + } } #endif diff --git a/include/etl/queue_mpmc_mutex.h b/include/etl/queue_mpmc_mutex.h index 2b10cf83..72c3f80e 100644 --- a/include/etl/queue_mpmc_mutex.h +++ b/include/etl/queue_mpmc_mutex.h @@ -582,6 +582,6 @@ namespace etl /// The uninitialised buffer of T used in the queue_mpmc_mutex. typename etl::aligned_storage::value>::type buffer[MAX_SIZE]; }; -}; +} #endif diff --git a/include/etl/queue_spsc_atomic.h b/include/etl/queue_spsc_atomic.h index 925a4672..e7c3d743 100644 --- a/include/etl/queue_spsc_atomic.h +++ b/include/etl/queue_spsc_atomic.h @@ -469,6 +469,6 @@ namespace etl /// The uninitialised buffer of T used in the queue_spsc. typename etl::aligned_storage::value>::type buffer[RESERVED_SIZE]; }; -}; +} #endif diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index 2ff961d3..bb9c530e 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -676,6 +676,6 @@ namespace etl /// The uninitialised buffer of T used in the queue_spsc_isr. typename etl::aligned_storage::value>::type buffer[MAX_SIZE]; }; -}; +} #endif diff --git a/test/codeblocks/ETLcpp03.cbp b/test/codeblocks/ETLcpp03.cbp index bd9a9e74..e3806608 100644 --- a/test/codeblocks/ETLcpp03.cbp +++ b/test/codeblocks/ETLcpp03.cbp @@ -64,7 +64,6 @@ - @@ -324,7 +323,7 @@ - + diff --git a/test/maincpp03check.cpp b/test/maincpp03check.cpp new file mode 100644 index 00000000..2dbd8927 --- /dev/null +++ b/test/maincpp03check.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://www.etlcpp.com +https://github.com/ETLCPP/etl + +Copyright(c) 2019 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" + +#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" + +int main() +{ + return UnitTest::RunAllTests(); +}