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
This commit is contained in:
cristianchiriac 2026-10-15 19:40:48 +03:00
parent ea54954c54
commit 442c6baac9
2 changed files with 77 additions and 3 deletions

View File

@ -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;
}

View File

@ -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<ptrdiff_t>(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<ptrdiff_t>(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)