diff --git a/doc/container.qbk b/doc/container.qbk index 0ab4a5c..34fb069 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1247,6 +1247,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/pull/110 GitHub #110: ['"Avoid gcc 9 deprecated copy warnings in new_allocator.hpp"]]. * [@https://github.com/boostorg/container/issues/112 GitHub #112: ['"vector::resize() compilation error with msvc-10..12: data is not a member of boost::detail::aligned_storage"]]. * [@https://github.com/boostorg/container/issues/117 GitHub #117: ['"flat_map/map::insert_or_assign with hint has wrong return types"]]. + * [@https://github.com/boostorg/container/issues/118 GitHub #118: ['"Non-unique inplace_set_difference used in in flat_tree_merge_unique and iterator invalidation in insert_unique"]]. [endsect] diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index c1a5b34..4d86f9e 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -205,7 +205,7 @@ BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == f size_type const old_sz = dest.size(); iterator const first_new = dest.insert(dest.cend(), first, last ); - iterator e = boost::movelib::inplace_set_difference(first_new, dest.end(), dest.begin(), first_new, comp); + iterator e = boost::movelib::inplace_set_unique_difference(first_new, dest.end(), dest.begin(), first_new, comp); dest.erase(e, dest.end()); dtl::bool_::value> contiguous_tag; (flat_tree_container_inplace_merge)(dest, dest.begin()+old_sz, comp, contiguous_tag); @@ -883,10 +883,14 @@ class flat_tree //Step 3: only left unique values from the back not already present in the original range typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference (it, seq.end(), seq.begin(), it, val_cmp); - seq.erase(e, seq.cend()); - //Step 4: merge both ranges - (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag); + seq.erase(e, seq.cend()); + //it might be invalidated by erasing [e, seq.end) if e == it + if (it != e) + { + //Step 4: merge both ranges + (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag); + } } template diff --git a/test/flat_map_adaptor_test.cpp b/test/flat_map_adaptor_test.cpp new file mode 100644 index 0000000..520ef3c --- /dev/null +++ b/test/flat_map_adaptor_test.cpp @@ -0,0 +1,104 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include + +#include "map_test.hpp" +#include + +using namespace boost::container; + +template +struct GetMapContainer +{ + template + struct apply + { + typedef std::pair type_t; + typedef flat_map< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > map_type; + + typedef flat_multimap< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multimap_type; + }; +}; + +int main() +{ + using namespace boost::container::test; + + //////////////////////////////////// + // Testing sequence container implementations + //////////////////////////////////// + { + typedef std::map MyStdMap; + typedef std::multimap MyStdMultiMap; + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer, 7> >::apply::map_type + , MyStdMap + , GetMapContainer, 7> >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, 7> >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer, MaxElem * 10> >::apply::map_type + , MyStdMap + , GetMapContainer, MaxElem * 10> >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, MaxElem * 10> >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/test/flat_set_adaptor_test.cpp b/test/flat_set_adaptor_test.cpp new file mode 100644 index 0000000..b59ab17 --- /dev/null +++ b/test/flat_set_adaptor_test.cpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include + +#include "set_test.hpp" +#include + +using namespace boost::container; + +template +struct GetSetContainer +{ + template + struct apply + { + typedef flat_set < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > set_type; + + typedef flat_multiset < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multiset_type; + }; +}; + +int main() +{ + using namespace boost::container::test; + + //////////////////////////////////// + // Testing sequence container implementations + //////////////////////////////////// + { + typedef std::set MyStdSet; + typedef std::multiset MyStdMultiSet; + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/test/map_test.hpp b/test/map_test.hpp index 99bd42d..160c46a 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -14,6 +14,7 @@ #include #include "check_equal_containers.hpp" #include "print_container.hpp" +#include "movable_int.hpp" #include #include #include diff --git a/test/set_test.hpp b/test/set_test.hpp index c31882a..7bc3a09 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -14,6 +14,7 @@ #include #include "check_equal_containers.hpp" #include "print_container.hpp" +#include "movable_int.hpp" #include #include #include