From 442c6baac95fd5e2d1de2b4aacfdedb452e76dd8 Mon Sep 17 00:00:00 2001 From: cristianchiriac <80774326+cristianchiriac@users.noreply.github.com> Date: Thu, 15 Oct 2026 19:40:48 +0300 Subject: [PATCH] Fix vector insert of a value that refers to an element of the vector insert(position, value) and insert(position, n, value) shifted the elements before reading value, so a value taken from the vector at or after the insert position read the shifted element instead. Fixes #1629 --- include/etl/vector.h | 23 +++++++++++++++--- test/test_vector.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/include/etl/vector.h b/include/etl/vector.h index beac6cdc..ae3bb89a 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -611,9 +611,18 @@ namespace etl } else { + // value may refer to an element that is about to be shifted. + const_pointer p_value = etl::addressof(value); + create_back(back()); etl::move_backward(position_, p_end - 2, p_end - 1); - *position_ = value; + + if ((p_value >= position_) && (p_value < p_end)) + { + ++p_value; + } + + *position_ = *p_value; } return position_; @@ -836,6 +845,14 @@ namespace etl size_t copy_new_n = construct_old_n; size_t construct_new_n = insert_n - copy_new_n; + // value may refer to an element that is about to be shifted. + const_pointer p_value = etl::addressof(value); + + if ((p_value >= position_) && (p_value < p_end)) + { + p_value += n; + } + // Construct old. etl::uninitialized_move(p_end - construct_old_n, p_end, p_construct_old); ETL_ADD_DEBUG_COUNT(construct_old_n); @@ -844,11 +861,11 @@ namespace etl etl::move_backward(p_buffer + insert_begin, p_buffer + insert_begin + copy_old_n, p_buffer + insert_end + copy_old_n); // Construct new. - etl::uninitialized_fill_n(p_end, construct_new_n, value); + etl::uninitialized_fill_n(p_end, construct_new_n, *p_value); ETL_ADD_DEBUG_COUNT(construct_new_n); // Copy new. - etl::fill_n(p_buffer + insert_begin, copy_new_n, value); + etl::fill_n(p_buffer + insert_begin, copy_new_n, *p_value); p_end += n; } diff --git a/test/test_vector.cpp b/test/test_vector.cpp index 32799337..e14542c7 100644 --- a/test/test_vector.cpp +++ b/test/test_vector.cpp @@ -777,6 +777,33 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_value_from_self) + { + const size_t INITIAL_SIZE = 5; + + for (size_t offset = 0; offset <= INITIAL_SIZE; ++offset) + { + for (size_t source = 0; source < INITIAL_SIZE; ++source) + { + Compare_Data compare_data; + Data data; + + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + compare_data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + + data.insert(data.cbegin() + offset, data[source]); + compare_data.insert(compare_data.cbegin() + static_cast(offset), compare_data[source]); + + CHECK_EQUAL(compare_data.size(), data.size()); + + bool is_equal = std::equal(data.cbegin(), data.cend(), compare_data.cbegin()); + + CHECK(is_equal); + } + } + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds) { @@ -971,6 +998,36 @@ namespace } } + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_position_n_value_from_self) + { + const size_t INITIAL_SIZE = 5; + + for (size_t insert_size = 1; insert_size <= 4; ++insert_size) + { + for (size_t offset = 0; offset <= INITIAL_SIZE; ++offset) + { + for (size_t source = 0; source < INITIAL_SIZE; ++source) + { + Compare_Data compare_data; + Data data; + + data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + compare_data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE); + + data.insert(data.cbegin() + offset, insert_size, data[source]); + compare_data.insert(compare_data.cbegin() + static_cast(offset), insert_size, compare_data[source]); + + CHECK_EQUAL(compare_data.size(), data.size()); + + bool is_equal = std::equal(data.cbegin(), data.cend(), compare_data.cbegin()); + + CHECK(is_equal); + } + } + } + } + //************************************************************************* #include "etl/private/diagnostic_uninitialized_push.h" TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds)