Hotfix/etl multiset iterator invalidation during erase leads to incorrect sorted order in depth first traversal (#1317)

* Fixed issue for both multiset and multimap

* Added std::is_sorted checks to all map/set tests

* Updated with coderabbit suggestions

---------

Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
This commit is contained in:
John Wellbelove 2026-03-01 12:27:39 +00:00 committed by GitHub
parent 70e4850a0b
commit 7ee7f10f58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 353 additions and 133 deletions

View File

@ -761,7 +761,7 @@ namespace etl
friend class imultimap;
friend class const_iterator;
iterator()
iterator()
: p_multimap(ETL_NULLPTR)
, p_node(ETL_NULLPTR)
{
@ -2181,7 +2181,7 @@ namespace etl
else
{
// Update the direction to the replace node
node->dir = node->children[(uint_least8_t) kLeft] ? (uint_least8_t) kLeft : (uint_least8_t) kRight;
node->dir = 1 - found->dir;
}
} // while(node)
@ -2506,8 +2506,8 @@ namespace etl
template <typename TKey, typename TMapped, typename TKeyCompare>
bool operator <(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
{
return etl::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
return etl::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
lhs.value_comp());
}

View File

@ -1089,8 +1089,8 @@ namespace etl
size_type count(key_parameter_t key) const
{
return count_nodes(key);
}
}
#if ETL_USING_CPP11
//*********************************************************************
template <typename K, typename KC = TCompare, etl::enable_if_t<comparator_is_transparent<KC>::value, int> = 0>
@ -2167,7 +2167,7 @@ namespace etl
else
{
// Update the direction to the replace node
node->dir = node->children[kLeft] ? kLeft : kRight;
node->dir = 1 - found->dir;
}
} // while(node)
@ -2487,7 +2487,7 @@ namespace etl
bool operator <(const etl::imultiset<TKey, TCompare>& lhs, const etl::imultiset<TKey, TCompare>& rhs)
{
return ETL_OR_STD::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
rhs.begin(), rhs.end(),
etl::imultiset<TKey, TCompare>::value_compare());
}

View File

@ -49,8 +49,8 @@ using Data = etl::map<std::string, int, MAX_SIZE, std::greater<std::stri
using IData = etl::imap<std::string, int, std::greater<std::string>>;
using Compare_Data = std::map<std::string, int, std::greater<std::string>>;
#else
using Data = etl::map<std::string, int, MAX_SIZE, std::less<std::string>>;
using IData = etl::imap<std::string, int, std::less<std::string>>;
using Data = etl::map<std::string, int, MAX_SIZE, std::less<std::string>>;
using IData = etl::imap<std::string, int, std::less<std::string>>;
using Compare_Data = std::map<std::string, int, std::less<std::string>>;
#endif
@ -233,6 +233,8 @@ namespace
CHECK_EQUAL(10U, data.capacity());
CHECK_EQUAL(10U, data.max_size());
CHECK(data == check);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -257,6 +259,8 @@ namespace
data2.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -281,6 +285,8 @@ namespace
CHECK(2 == data2.at("2").value);
CHECK(3 == data2.at("3").value);
CHECK(4 == data2.at("4").value);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -304,6 +310,7 @@ namespace
CHECK(d == MAX_SIZE);
CHECK(data.size() == MAX_SIZE);
CHECK(!data.empty());
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#if ETL_HAS_INITIALIZER_LIST
@ -324,6 +331,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -340,6 +349,8 @@ namespace
otherData.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(otherData.begin(), otherData.end(), otherData.value_comp()));
}
//*************************************************************************
@ -358,6 +369,8 @@ namespace
data2.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -366,9 +379,9 @@ namespace
Data data(initial_data.begin(), initial_data.end());
Data other_data(data);
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
other_data = other_data;
#include "etl/private/diagnostic_pop.h"
#include "etl/private/diagnostic_pop.h"
bool isEqual = std::equal(data.begin(),
data.end(),
@ -399,6 +412,8 @@ namespace
CHECK(2 == data2.at("2").value);
CHECK(3 == data2.at("3").value);
CHECK(4 == data2.at("4").value);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -633,6 +648,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -655,6 +672,8 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -679,6 +698,8 @@ namespace
CHECK(2 == data.at("2").value);
CHECK(3 == data.at("3").value);
CHECK(4 == data.at("4").value);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -704,6 +725,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -723,18 +746,20 @@ namespace
// Check that elements in map are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(data_result.first, ETL_OR_STD::make_pair(std::string("1"), 1));
compare_data.insert(compare_result.first, ETL_OR_STD::make_pair(std::string("1"), 1));
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -754,8 +779,8 @@ namespace
// Check that elements in map are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(Data::const_iterator(data_result.first),
@ -764,10 +789,12 @@ namespace
ETL_OR_STD::make_pair(std::string("1"), 1));
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -792,6 +819,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -804,10 +833,12 @@ namespace
compare_data.insert(random_data.begin(), random_data.end());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -887,8 +918,8 @@ namespace
CHECK(data_result.second->second == compare_result.second->second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
}
@ -932,6 +963,8 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -949,6 +982,8 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -973,6 +1008,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -993,10 +1030,12 @@ namespace
CHECK(i_compare1->second == i_data1->second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -1024,6 +1063,8 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -1048,9 +1089,11 @@ namespace
data.erase(i_data, i_data_end);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -1576,7 +1619,7 @@ namespace
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED)
TEST_FIXTURE(SetupFixture, test_map_template_deduction)
{
using Pair = std::pair<const etl::string<1>, int>;
using Pair = std::pair<const std::string, int>;
etl::map data { Pair{"0", 0}, Pair{"1", 1}, Pair{"2", 2}, Pair{"3", 3}, Pair{"4", 4}, Pair{"5", 5} };
@ -1590,6 +1633,8 @@ namespace
CHECK_EQUAL(3, data.at("3"));
CHECK_EQUAL(4, data.at("4"));
CHECK_EQUAL(5, data.at("5"));
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -1597,9 +1642,9 @@ namespace
#if ETL_HAS_INITIALIZER_LIST
TEST_FIXTURE(SetupFixture, test_make_map)
{
using Pair = ETL_OR_STD::pair<const etl::string<1>, int>;
using Pair = ETL_OR_STD::pair<const std::string, int>;
auto data = etl::make_map<const etl::string<1>, int, std::less<etl::string<1>>>(Pair{ "0", 0 }, Pair{ "1", 1 }, Pair{ "2", 2 }, Pair{ "3", 3 }, Pair{ "4", 4 }, Pair{ "5", 5 });
auto data = etl::make_map<const std::string, int, std::less<std::string>>(Pair{ "0", 0 }, Pair{ "1", 1 }, Pair{ "2", 2 }, Pair{ "3", 3 }, Pair{ "4", 4 }, Pair{ "5", 5 });
auto v = *data.begin();
using Type = decltype(v);
@ -1611,6 +1656,8 @@ namespace
CHECK_EQUAL(3, data.at("3"));
CHECK_EQUAL(4, data.at("4"));
CHECK_EQUAL(5, data.at("5"));
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -1634,5 +1681,34 @@ namespace
CHECK(!data.contains(std::string("99")));
CHECK(!data.contains(Key("99")));
}
//*************************************************************************
TEST(test_if_issue_1298_multiset_iterator_invalidation_during_erase_is_also_in_map)
{
using element = std::pair<int, int>;
std::vector<element> permutation{ {1, 11}, {2, 12}, {3, 13}, {4, 14} };
const std::vector<element> expected{ {1, 11}, {3, 13}, {4, 14} };
do
{
etl::map<int, int, 8> data;
for (auto i : permutation)
{
data.insert(i);
}
auto it = data.find(2);
data.erase(it);
const std::vector<element> actual(data.begin(), data.end());
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
CHECK_EQUAL(expected.size(), actual.size());
CHECK_TRUE(actual == expected);
} while (std::next_permutation(permutation.begin(), permutation.end()));
}
}
}

View File

@ -234,6 +234,7 @@ namespace
CHECK_EQUAL(10U, data.capacity());
CHECK_EQUAL(10U, data.max_size());
CHECK(data == check);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -258,6 +259,7 @@ namespace
data2.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -300,6 +302,8 @@ namespace
CHECK(itr != data2.end());
result = itr->second.value;
CHECK_EQUAL(4, result);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -340,6 +344,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -374,6 +379,7 @@ namespace
data2.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -382,9 +388,9 @@ namespace
Data data(initial_data.begin(), initial_data.end());
Data other_data(data);
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
other_data = other_data;
#include "etl/private/diagnostic_pop.h"
#include "etl/private/diagnostic_pop.h"
bool isEqual = std::equal(data.begin(),
data.end(),
@ -433,6 +439,8 @@ namespace
CHECK(itr != data2.end());
result = itr->second.value;
CHECK_EQUAL(4, result);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.value_comp()));
}
//*************************************************************************
@ -488,6 +496,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -554,6 +563,7 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -573,18 +583,19 @@ namespace
// Check that elements in map are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(data_result, ETL_OR_STD::make_pair(std::string("1"), 1));
compare_data.insert(compare_result, ETL_OR_STD::make_pair(std::string("1"), 1));
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -604,8 +615,8 @@ namespace
// Check that elements in map are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(Data::const_iterator(data_result),
@ -614,10 +625,11 @@ namespace
ETL_OR_STD::make_pair(std::string("1"), 1));
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -642,6 +654,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -654,8 +667,8 @@ namespace
compare_data.insert(random_data.begin(), random_data.end());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
}
@ -730,8 +743,8 @@ namespace
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
}
@ -756,8 +769,8 @@ namespace
CHECK(compare_result.second->second == data_result.second->second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
}
@ -789,10 +802,11 @@ namespace
CHECK(compare_count == data_count);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -825,10 +839,12 @@ namespace
CHECK(compare_count == data_count);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -850,6 +866,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -870,10 +887,11 @@ namespace
CHECK(i_compare1->second == i_data1->second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -901,6 +919,7 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -913,9 +932,10 @@ namespace
data.erase(data.cbegin(), data.cend());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -1622,6 +1642,8 @@ namespace
}
CHECK(pass);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
//*************************************************************************
@ -1649,6 +1671,8 @@ namespace
CHECK_EQUAL(4, itr->second);
++itr;
CHECK_EQUAL(5, itr->second);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -1677,6 +1701,8 @@ namespace
CHECK_EQUAL(4, itr->second);
++itr;
CHECK_EQUAL(5, itr->second);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
}
#endif
@ -1691,5 +1717,35 @@ namespace
CHECK(!data.contains(std::string("99")));
CHECK(!data.contains(Key("99")));
}
//*************************************************************************
TEST(test_if_issue_1298_multiset_iterator_invalidation_during_erase_is_also_in_multimap)
{
using element = std::pair<int, int>;
std::vector<element> permutation{ {1, 11}, {2, 12}, {2, 12}, {3, 14} };
const std::vector<element> expected{ {1, 11}, {2, 12}, {3, 14} };
do
{
etl::multimap<int, int, 8> data;
for (auto i : permutation)
{
data.insert(i);
}
auto it = data.find(2);
++it;
data.erase(it);
const std::vector<element> actual(data.begin(), data.end());
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.value_comp()));
CHECK_EQUAL(expected.size(), actual.size());
CHECK_TRUE(actual == expected);
} while (std::next_permutation(permutation.begin(), permutation.end()));
}
}
}

View File

@ -247,6 +247,7 @@ namespace
CHECK_EQUAL(10U, data.capacity());
CHECK_EQUAL(10U, data.max_size());
CHECK(data == check);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -271,6 +272,7 @@ namespace
data2.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -290,6 +292,7 @@ namespace
DataM data2(std::move(data1));
CHECK(!data1.empty()); // Move does not clear the source.
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -310,6 +313,7 @@ namespace
CHECK(data.size() == MAX_SIZE);
CHECK(!data.empty());
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#if ETL_HAS_INITIALIZER_LIST
@ -325,6 +329,7 @@ namespace
bool isEqual = std::equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -341,6 +346,7 @@ namespace
otherData.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(otherData.begin(), otherData.end(), otherData.key_comp()));
}
//*************************************************************************
@ -359,6 +365,7 @@ namespace
data2.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -367,9 +374,9 @@ namespace
Data data(initial_data.begin(), initial_data.end());
Data other_data(data);
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
other_data = other_data;
#include "etl/private/diagnostic_pop.h"
#include "etl/private/diagnostic_pop.h"
bool isEqual = std::equal(data.begin(),
data.end(),
@ -398,6 +405,7 @@ namespace
data2 = std::move(data1);
CHECK(!data1.empty()); // Move does not clear the source.
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -453,6 +461,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -510,6 +519,7 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -526,18 +536,19 @@ namespace
// Check that elements in multiset are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(data_result, 1);
compare_data.insert(compare_result, 1);
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -566,6 +577,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -590,6 +602,7 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -602,10 +615,11 @@ namespace
compare_data.insert(random_data.begin(), random_data.end());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -638,6 +652,8 @@ namespace
CHECK_EQUAL(2, data.find(ItemM(2))->value);
CHECK_EQUAL(3, data.find(ItemM(3))->value);
CHECK_EQUAL(4, data.find(ItemM(4))->value);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -707,6 +723,7 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -714,7 +731,7 @@ namespace
{
using CSet = std::multiset<int, std::less<int>>;
CSet compare_data(initial_data.begin(), initial_data.end());
using ESet = etl::multiset<int, MAX_SIZE, etl::less<>>;
ESet data(initial_data.begin(), initial_data.end());
@ -741,6 +758,7 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -760,6 +778,7 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -780,10 +799,11 @@ namespace
CHECK_EQUAL(*i_compare1, *i_data1);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -811,6 +831,7 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -823,9 +844,11 @@ namespace
data.erase(data.cbegin(), data.cend());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -1621,5 +1644,31 @@ namespace
CHECK(!data.contains(99));
CHECK(!data.contains(Key(99)));
}
//*************************************************************************
TEST(test_issue_1298_multiset_iterator_invalidation_during_erase)
{
std::vector<int> permutation{1, 2, 2, 3};
const std::vector<int> expected{1, 2, 3};
do
{
etl::multiset<int, 8> data;
for (auto i : permutation)
{
data.insert(i);
}
auto it = data.find(2);
++it;
data.erase(it);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
CHECK_EQUAL(expected.size(), data.size());
CHECK_TRUE((std::equal(data.begin(), data.end(), expected.begin())));
} while (std::next_permutation(permutation.begin(), permutation.end()));
}
}
}

View File

@ -204,6 +204,7 @@ namespace
CHECK_EQUAL(10U, data.capacity());
CHECK_EQUAL(10U, data.max_size());
CHECK(data == check);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -228,6 +229,8 @@ namespace
data2.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -252,6 +255,8 @@ namespace
CHECK(data2.find(ItemM(2)) != data2.end());
CHECK(data2.find(ItemM(3)) != data2.end());
CHECK(data2.find(ItemM(4)) != data2.end());
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -275,6 +280,8 @@ namespace
bool isEqual = std::equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#if ETL_HAS_INITIALIZER_LIST
@ -290,6 +297,8 @@ namespace
bool isEqual = std::equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -306,6 +315,8 @@ namespace
otherData.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(otherData.begin(), otherData.end(), otherData.key_comp()));
}
//*************************************************************************
@ -324,6 +335,8 @@ namespace
data2.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -332,15 +345,17 @@ namespace
Data data(initial_data.begin(), initial_data.end());
Data otherData(data);
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
#include "etl/private/diagnostic_self_assign_overloaded_push.h"
data = data;
#include "etl/private/diagnostic_pop.h"
#include "etl/private/diagnostic_pop.h"
bool isEqual = Check_Equal(data.begin(),
data.end(),
otherData.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -363,6 +378,8 @@ namespace
data2 = std::move(data1);
CHECK(!data1.empty()); // Move does not clear the source.
CHECK_TRUE(std::is_sorted(data2.begin(), data2.end(), data2.key_comp()));
}
//*************************************************************************
@ -418,6 +435,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -464,6 +483,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -480,18 +501,20 @@ namespace
// Check that elements in set are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(data_result.first, 1);
compare_data.insert(compare_result.first, 1);
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -510,18 +533,20 @@ namespace
// Check that elements in set are the same
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
data.insert(data_result.first, 1);
compare_data.insert(compare_result.first, 1);
isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -546,6 +571,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -558,10 +585,12 @@ namespace
compare_data.insert(random_data.begin(), random_data.end());
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -594,6 +623,8 @@ namespace
CHECK_EQUAL(2, data.find(ItemM(2))->value);
CHECK_EQUAL(3, data.find(ItemM(3))->value);
CHECK_EQUAL(4, data.find(ItemM(4))->value);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -634,46 +665,9 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
////*************************************************************************
//TEST_FIXTURE(SetupFixture, test_emplace_value)
//{
// Compare_Data compare_data;
// Data data;
// ETL_OR_STD::pair<Data::iterator, bool> data_result = data.emplace(0);
// ETL_OR_STD::pair<Compare_Data::iterator, bool> compare_result = compare_data.emplace(0);
// // Check that both return successful return results
// CHECK_EQUAL(*data_result.first, *compare_result.first);
// // Try adding a duplicate (should return iterator pointing to duplicate)
// data_result = data.insert(0);
// compare_result = compare_data.insert(0);
// // Check that both return successful return results
// CHECK_EQUAL(*data_result.first, *compare_result.first);
// // Check that elements in set are the same
// bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
// CHECK(isEqual);
// data.insert(2);
// compare_data.insert(2);
// isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
// CHECK(isEqual);
// data.insert(1);
// compare_data.insert(1);
// isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
// CHECK(isEqual);
//}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_equal_range)
{
@ -693,6 +687,8 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -711,10 +707,12 @@ namespace
CHECK_EQUAL(*data_result.second, *compare_result.second);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -729,6 +727,8 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -746,6 +746,8 @@ namespace
bool isEqual = Check_Equal(data.begin(), data.end(), compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -770,6 +772,8 @@ namespace
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -790,10 +794,12 @@ namespace
CHECK_EQUAL(*i_compare1, *i_data1);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -821,6 +827,8 @@ namespace
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -845,9 +853,11 @@ namespace
data.erase(i_data, i_data_end);
bool isEqual = Check_Equal(data.begin(),
data.end(),
compare_data.begin());
data.end(),
compare_data.begin());
CHECK(isEqual);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
//*************************************************************************
@ -1298,14 +1308,14 @@ namespace
ETL_OR_STD::pair<Data::const_iterator, Data::const_iterator> etlret = data.equal_range(i);
CHECK_EQUAL(stlret.first == compare.end(), etlret.first == data.end());
if((stlret.first != compare.end()) && (etlret.first != data.end()))
{
CHECK_EQUAL(*stlret.first, *etlret.first);
}
CHECK_EQUAL(stlret.second == compare.end(), etlret.second == data.end());
if((stlret.second != compare.end()) && (etlret.second != data.end()))
{
CHECK_EQUAL(*stlret.second, *etlret.second);
@ -1365,14 +1375,14 @@ namespace
ETL_OR_STD::pair<EMap::const_iterator, EMap::const_iterator> etlret = data.equal_range(Key(i));
CHECK_EQUAL(stlret.first == compare.end(), etlret.first == data.end());
if ((stlret.first != compare.end()) && (etlret.first != data.end()))
{
CHECK_EQUAL(*stlret.first, *etlret.first);
}
CHECK_EQUAL(stlret.second == compare.end(), etlret.second == data.end());
if ((stlret.second != compare.end()) && (etlret.second != data.end()))
{
CHECK_EQUAL(*stlret.second, *etlret.second);
@ -1417,6 +1427,8 @@ namespace
CHECK_EQUAL("E", *itr);
++itr;
CHECK_EQUAL("F", *itr);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -1443,6 +1455,8 @@ namespace
CHECK_EQUAL("E", *itr);
++itr;
CHECK_EQUAL("F", *itr);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
}
#endif
@ -1468,5 +1482,30 @@ namespace
CHECK(!data.contains(99));
CHECK(!data.contains(Key(99)));
}
//*************************************************************************
TEST(test_if_issue_1298_multiset_iterator_invalidation_during_erase_is_also_in_set)
{
std::vector<int> permutation{1, 2, 3, 4};
const std::vector<int> expected{1, 3, 4};
do
{
etl::set<int, 8> data;
for (auto i : permutation)
{
data.insert(i);
}
auto it = data.find(2);
data.erase(it);
CHECK_TRUE(std::is_sorted(data.begin(), data.end(), data.key_comp()));
CHECK_EQUAL(expected.size(), data.size());
CHECK_TRUE((std::equal(data.begin(), data.end(), expected.begin())));
} while (std::next_permutation(permutation.begin(), permutation.end()));
}
}
}

View File

@ -1278,9 +1278,6 @@
<ClInclude Include="..\..\include\etl\shared_message.h">
<Filter>ETL\Messaging</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\generators\message_packet_generator.h">
<Filter>ETL\Messaging\Generators</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\generators\message_router_generator.h">
<Filter>ETL\Messaging\Generators</Filter>
</ClInclude>
@ -1539,6 +1536,9 @@
<ClInclude Include="..\..\include\etl\inplace_function.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\generators\message_packet_generator.h">
<Filter>ETL\Messaging</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\test_string_char.cpp">