Indirect vector checks (#1239)

* Check in indirect_vector::emplace_back if the vector is full, when push pop checks are requested

* Add extra checks to indirect_vector

* Fix emplace in indirect_vector not taking const_iterator

* Fix usage of ipool::create<T> in indirect_vector, so that there are no intermitten objects created

---------

Co-authored-by: Béla Iványi <bela.ivanyi@idata.hu>
This commit is contained in:
Iványi Béla 2026-01-01 10:56:25 +01:00 committed by GitHub
parent 4f70ed5329
commit 16389b3eea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 308 additions and 28 deletions

View File

@ -292,6 +292,11 @@ namespace etl
return lhs.lookup_itr < rhs.lookup_itr;
}
friend bool operator <= (const iterator& lhs, const iterator& rhs)
{
return lhs.lookup_itr <= rhs.lookup_itr;
}
private:
iterator(indirect_iterator itr_)
@ -424,6 +429,11 @@ namespace etl
return lhs.lookup_itr < rhs.lookup_itr;
}
friend bool operator <= (const const_iterator& lhs, const const_iterator& rhs)
{
return lhs.lookup_itr <= rhs.lookup_itr;
}
private:
typedef typename etl::ivector<T*>::const_iterator lookup_itr_t;
@ -757,7 +767,7 @@ namespace etl
//*********************************************************************
void push_back(const_reference value)
{
ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(value);
lookup.push_back(p);
@ -771,7 +781,7 @@ namespace etl
//*********************************************************************
void push_back(rvalue_reference value)
{
ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(size() != capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(etl::move(value));
lookup.push_back(p);
@ -787,6 +797,8 @@ namespace etl
template <typename ... Args>
reference emplace_back(Args && ... args)
{
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(etl::forward<Args>(args)...);
lookup.push_back(p);
return back();
@ -799,7 +811,9 @@ namespace etl
//*********************************************************************
reference emplace_back()
{
T* p = storage.create<T>(T());
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>();
lookup.push_back(p);
return back();
}
@ -812,7 +826,9 @@ namespace etl
template <typename T1>
reference emplace_back(const T1& value1)
{
T* p = storage.create<T>(T(value1));
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(value1);
lookup.push_back(p);
return back();
}
@ -825,7 +841,9 @@ namespace etl
template <typename T1, typename T2>
reference emplace_back(const T1& value1, const T2& value2)
{
T* p = storage.create<T>(T(value1, value2));
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(value1, value2);
lookup.push_back(p);
return back();
}
@ -838,7 +856,9 @@ namespace etl
template <typename T1, typename T2, typename T3>
reference emplace_back(const T1& value1, const T2& value2, const T3& value3)
{
T* p = storage.create<T>(T(value1, value2, value3));
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(value1, value2, value3);
lookup.push_back(p);
return back();
}
@ -851,7 +871,9 @@ namespace etl
template <typename T1, typename T2, typename T3, typename T4>
reference emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
T* p = storage.create<T>(T(value1, value2, value3, value4));
ETL_ASSERT_CHECK_PUSH_POP(!full(), ETL_ERROR(vector_full));
T* p = storage.create<T>(value1, value2, value3, value4);
lookup.push_back(p);
return back();
}
@ -862,7 +884,7 @@ namespace etl
//*************************************************************************
void pop_back()
{
ETL_ASSERT(!empty(), ETL_ERROR(vector_empty));
ETL_ASSERT_CHECK_PUSH_POP_OR_RETURN(!empty(), ETL_ERROR(vector_empty));
reference object = back();
storage.destroy<T>(etl::addressof(object));
@ -878,8 +900,9 @@ namespace etl
iterator insert(const_iterator position, const_reference value)
{
ETL_ASSERT(size() != capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(value));
T* p = storage.create<T>(value);
position = iterator(lookup.insert(position.lookup_itr, p));
return to_iterator(position);
@ -895,8 +918,9 @@ namespace etl
iterator insert(const_iterator position, rvalue_reference value)
{
ETL_ASSERT(size() != capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(etl::move(value)));
T* p = storage.create<T>(etl::move(value));
position = iterator(lookup.insert(position.lookup_itr, p));
return to_iterator(position);
@ -908,68 +932,74 @@ namespace etl
//*************************************************************************
#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_VECTOR_FORCE_CPP03_IMPLEMENTATION)
template <typename ... Args>
iterator emplace(iterator position, Args && ... args)
iterator emplace(const_iterator position, Args && ... args)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(etl::forward<Args>(args)...));
T* p = storage.create<T>(etl::forward<Args>(args)...);
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
#else
iterator emplace(iterator position)
iterator emplace(const_iterator position)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T());
T* p = storage.create<T>();
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
template <typename T1>
iterator emplace(iterator position, const T1& value1)
iterator emplace(const_iterator position, const T1& value1)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(value1));
T* p = storage.create<T>(value1);
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
template <typename T1, typename T2>
iterator emplace(iterator position, const T1& value1, const T2& value2)
iterator emplace(const_iterator position, const T1& value1, const T2& value2)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(value1, value2));
T* p = storage.create<T>(value1, value2);
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
template <typename T1, typename T2, typename T3>
iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3)
iterator emplace(const_iterator position, const T1& value1, const T2& value2, const T3& value3)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(value1, value2, value3));
T* p = storage.create<T>(value1, value2, value3);
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
template <typename T1, typename T2, typename T3, typename T4>
iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
iterator emplace(const_iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
ETL_ASSERT(!full(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
T* p = storage.create<T>(T(value1, value2, value3, value4));
T* p = storage.create<T>(value1, value2, value3, value4);
position = iterator(lookup.insert(position.lookup_itr, p));
return position;
return to_iterator(position);
}
#endif
@ -983,6 +1013,7 @@ namespace etl
iterator insert(const_iterator position, size_t n, parameter_t value)
{
ETL_ASSERT((size() + n) <= capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
iterator position_ = to_iterator(position);
@ -1012,6 +1043,7 @@ namespace etl
size_t count = size_t(etl::distance(first, last));
ETL_ASSERT((size() + count) <= capacity(), ETL_ERROR(vector_full));
ETL_ASSERT_CHECK_EXTRA(cbegin() <= position && position <= cend(), ETL_ERROR(vector_out_of_bounds));
// Make space for the new lookup pointers.
typename etl::ivector<T*>::iterator lookup_itr = to_iterator(position).lookup_itr;
@ -1034,6 +1066,8 @@ namespace etl
//*********************************************************************
iterator erase(iterator i_element)
{
ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds));
storage.destroy<T>(etl::addressof(*i_element));
return iterator(lookup.erase(i_element.lookup_itr));
@ -1046,6 +1080,8 @@ namespace etl
//*********************************************************************
iterator erase(const_iterator i_element)
{
ETL_ASSERT_CHECK_EXTRA(cbegin() <= i_element && i_element < cend(), ETL_ERROR(vector_out_of_bounds));
storage.destroy<T>(etl::addressof(*i_element));
return iterator(lookup.erase(i_element.lookup_itr));
@ -1061,6 +1097,8 @@ namespace etl
//*********************************************************************
iterator erase(const_iterator first, const_iterator last)
{
ETL_ASSERT_CHECK_EXTRA(cbegin() <= first && first <= last && last <= cend(), ETL_ERROR(vector_out_of_bounds));
iterator element = to_iterator(first);
while (element != last)

View File

@ -536,6 +536,8 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}
CHECK_THROW(data[data.size()], etl::vector_out_of_bounds);
}
//*************************************************************************
@ -549,6 +551,8 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}
CHECK_THROW(data[data.size()], etl::vector_out_of_bounds);
}
//*************************************************************************
@ -586,6 +590,9 @@ namespace
DataNDC data(initial_data.begin(), initial_data.end());
CHECK(data.front() == compare_data.front());
DataNDC emptyData;
CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -595,6 +602,9 @@ namespace
const DataNDC data(initial_data.begin(), initial_data.end());
CHECK(data.front() == compare_data.front());
const DataNDC emptyData;
CHECK_THROW(emptyData.front(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -604,6 +614,9 @@ namespace
DataNDC data(initial_data.begin(), initial_data.end());
CHECK(data.back() == compare_data.back());
DataNDC emptyData;
CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -613,6 +626,9 @@ namespace
const DataNDC data(initial_data.begin(), initial_data.end());
CHECK(data.back() == compare_data.back());
const DataNDC emptyData;
CHECK_THROW(emptyData.back(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -759,6 +775,21 @@ namespace
CHECK_EQUAL(back, data.back());
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_emplace_back_excess)
{
DataNDC data;
for (size_t i = 0UL; i < SIZE; ++i)
{
std::string value(" ");
value[0] = char('A' + i);
data.emplace_back(value);
}
CHECK_THROW(data.emplace_back("Z"), etl::vector_full);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_push_back_unique_ptr)
{
@ -996,6 +1027,18 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds)
{
const size_t INITIAL_SIZE = 5;
const NDC INITIAL_VALUE("1");
DataNDC data;
DataNDC data2;
data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE);
CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_emplace_position_default_value)
{
@ -1048,6 +1091,18 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds)
{
const size_t INITIAL_SIZE = 5;
const std::string INITIAL_VALUE("1");
DataNDC data;
DataNDC data2;
data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE);
CHECK_THROW(data.emplace(data2.begin(), INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_value_excess)
{
@ -1097,6 +1152,17 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds)
{
const NDC INITIAL_VALUE("1");
DataNDC data;
DataNDC data2;
CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess)
{
@ -1151,6 +1217,15 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_range_outofbounds)
{
DataNDC data;
DataNDC data2;
CHECK_THROW(data.insert(data2.end(), insert_data.begin(), insert_data.end()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_range_excess)
{
@ -1195,6 +1270,15 @@ namespace
CHECK(is_equal);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_single_outofbounds)
{
DataNDC data(initial_data.begin(), initial_data.end());
CHECK_THROW(data.erase(data.end()), etl::vector_out_of_bounds);
CHECK_THROW(data.erase(data.cend()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_range)
{
@ -1214,6 +1298,15 @@ namespace
CHECK(is_equal);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds)
{
DataNDC data(initial_data.begin(), initial_data.end());
DataNDC data2(initial_data.begin(), initial_data.end());
CHECK_THROW(data.erase(data2.begin(), data2.end()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_clear)
{

View File

@ -646,6 +646,8 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}
CHECK_THROW(data[data.size()], etl::vector_out_of_bounds);
}
//*************************************************************************
@ -662,6 +664,8 @@ namespace
{
CHECK_EQUAL(data[i], compare_data[i]);
}
CHECK_THROW(data[data.size()], etl::vector_out_of_bounds);
}
//*************************************************************************
@ -708,6 +712,12 @@ namespace
DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
CHECK(data.front() == compare_data.front());
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
CHECK_THROW(data2.front(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -720,6 +730,12 @@ namespace
const DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
CHECK(data.front() == compare_data.front());
LookupNDC lookup2;
PoolNDC pool2;
const DataNDC data2(lookup2, pool2);
CHECK_THROW(data2.front(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -732,6 +748,12 @@ namespace
DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
CHECK(data.back() == compare_data.back());
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
CHECK_THROW(data2.back(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -744,6 +766,12 @@ namespace
const DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
CHECK(data.back() == compare_data.back());
LookupNDC lookup2;
PoolNDC pool2;
const DataNDC data2(lookup2, pool2);
CHECK_THROW(data2.back(), etl::vector_out_of_bounds);
}
//*************************************************************************
@ -875,6 +903,24 @@ namespace
CHECK(is_equal);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_emplace_back_excess)
{
LookupNDC lookup;
PoolNDC pool;
DataNDC data(lookup, pool);
for (size_t i = 0UL; i < SIZE; ++i)
{
std::string value(" ");
value[0] = char('A' + i);
data.emplace_back(value);
}
CHECK_THROW(data.emplace_back("Z"), etl::vector_full);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_push_back_unique_ptr)
{
@ -1028,6 +1074,26 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_value_outofbounds)
{
const size_t INITIAL_SIZE = 5UL;
const NDC INITIAL_VALUE("1");
LookupNDC lookup;
PoolNDC pool;
DataNDC data(lookup, pool);
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE);
CHECK_THROW(data.insert(data2.cbegin(), INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_emplace_position_value)
{
@ -1058,6 +1124,25 @@ namespace
}
}
TEST_FIXTURE(SetupFixture, test_emplace_position_value_outofbounds)
{
const size_t INITIAL_SIZE = 5UL;
const std::string INITIAL_VALUE("1");
LookupNDC lookup;
PoolNDC pool;
DataNDC data(lookup, pool);
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
data.assign(initial_data.begin(), initial_data.begin() + INITIAL_SIZE);
CHECK_THROW(data.emplace(data2.begin(), INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_value_excess)
{
@ -1113,6 +1198,24 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_outofbounds)
{
const NDC INITIAL_VALUE("1");
LookupNDC lookup;
PoolNDC pool;
DataNDC data(lookup, pool);
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
CHECK_THROW(data.insert(data2.end(), 1, INITIAL_VALUE), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_n_value_excess)
{
@ -1173,6 +1276,24 @@ namespace
}
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_range_outofbounds)
{
const NDC INITIAL_VALUE("1");
LookupNDC lookup;
PoolNDC pool;
DataNDC data(lookup, pool);
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(lookup2, pool2);
CHECK_THROW(data.insert(data2.end(), insert_data.begin(), insert_data.end()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_insert_position_range_excess)
{
@ -1223,6 +1344,18 @@ namespace
CHECK(is_equal);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_single_outofbounds)
{
LookupNDC lookup;
PoolNDC pool;
DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
CHECK_THROW(data.erase(data.end()), etl::vector_out_of_bounds);
CHECK_THROW(data.erase(data.cend()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_range)
{
@ -1245,6 +1378,22 @@ namespace
CHECK(is_equal);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_erase_range_outofbounds)
{
LookupNDC lookup;
PoolNDC pool;
DataNDC data(initial_data.begin(), initial_data.end(), lookup, pool);
LookupNDC lookup2;
PoolNDC pool2;
DataNDC data2(initial_data.begin(), initial_data.end(), lookup2, pool2);
CHECK_THROW(data.erase(data2.begin(), data2.end()), etl::vector_out_of_bounds);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_clear)
{