/* Copyright 2025-2026 Joaquin M Lopez Munoz. * 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) */ #include #if BOOST_CXX_VERSION < 201103L int main() { return 0; } #else #include #include #include #include #include #include #include #include #include #include #include "hub_utility.hpp" struct tidy_int { tidy_int(int n_ = 0): n{n_} {} ~tidy_int() { n = 0x0BADBEEF; } operator int() const { return n; } tidy_int& operator+=(const tidy_int& x) { n += x.n; return *this; } int n; }; template using erase_callback = std::function; template struct track_info { typename Hub::iterator it; typename Hub::pointer pointer; typename Hub::value_type value; bool valid() const { return std::addressof(*it) == pointer && *it == value; } }; template using track_info_vector = std::vector>; template void call_optionally_with_impl(F& f, Arg, ...) { f(); } template< typename F, typename Arg, typename = typename std::enable_if< sizeof(std::declval()(std::declval()), 0) != 0 >::type > void call_optionally_with_impl(F& f, Arg arg, int) { f(arg); } template void call_optionally_with(F& f, Arg arg) { call_optionally_with_impl(f, arg, 0); } template void save_track_info(Hub& x, track_info_vector& track) { for(auto it = x.begin(); it != x.end(); ++it) { track.push_back(track_info{it, std::addressof(*it), *it}); } } #if BOOST_WORKAROUND(BOOST_GCC, < 70000) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wattributes" #endif template bool check_stability(F f, track_info_vector&& track = {}) { using iterator = typename Hub::iterator; call_optionally_with( f, erase_callback{[&] (iterator it) { track.erase(std::find_if( track.begin(), track.end(), [&] (const track_info& info) { return info.it == it; })); }}); for(const auto& info: track) if(!info.valid()) return false; return true; } #if BOOST_WORKAROUND(BOOST_GCC, < 70000) #pragma GCC diagnostic pop #endif template bool check_stability(Hub& x, F f, track_info_vector&& track = {}) { auto last = x.end(); save_track_info(x, track); if(!check_stability(f, std::move(track))) return false; return (x.end() == last); } template bool check_stability(Hub& x, Hub& y, F f, track_info_vector&& track = {}) { auto last = x.end(); save_track_info(x, track); if(!check_stability(y, f, std::move(track))) return false; return (x.end() == last); } template void test() { using value_type = typename Hub::value_type; using difference_type = typename Hub::difference_type; using erase_callback = ::erase_callback; auto rng = make_range(200); { Hub x(rng.begin(), rng.end()); BOOST_TEST(check_stability(x, [&] (erase_callback callback) { puncture(x, callback); x.insert(rng.begin(), rng.end()); })); } { Hub x(rng.begin(), rng.end()); std::shared_ptr py; BOOST_TEST(check_stability(x, [&] { py = std::make_shared(std::move(x)); })); } { Hub x(rng.begin(), rng.end()), y; BOOST_TEST(check_stability(x, y, [&] { y = std::move(x); })); } { Hub x(rng.begin(), rng.end()); BOOST_TEST(check_stability(x, [&] { x.reserve(x.capacity() + 100); })); } { Hub x(rng.begin(), rng.end()); puncture(x); x.shrink_to_fit(); BOOST_TEST(check_stability(x, [&] { x.shrink_to_fit(); })); } { Hub x(rng.begin(), rng.end()); puncture(x); auto c = x.capacity(); x.reserve(c + 1000); BOOST_TEST(check_stability(x, [&] { x.trim_capacity(c+500); })); BOOST_TEST(check_stability(x, [&] { x.trim_capacity(); })); } { Hub x(rng.begin(), rng.end()); BOOST_TEST(check_stability(x, [&] (erase_callback callback) { callback(x.begin()); x.erase(x.begin()); })); } { Hub x(rng.begin(), rng.end()); BOOST_TEST(check_stability(x, [&] (erase_callback callback) { auto first = std::next(x.begin(), (difference_type)(x.size() / 3)), last = std::next(x.begin(), (difference_type)(x.size() * 2 / 3)); for(auto it = first; it != last; ++it) callback(it); x.erase(first,last); })); } { Hub x(rng.begin(), rng.begin() + (difference_type)(rng.size() / 2)), y(rng.begin() + (difference_type)(rng.size() / 2), rng.end()); BOOST_TEST(check_stability(x, y, [&] { x.swap(y); })); } { Hub x(rng.begin(), rng.begin() + (difference_type)(rng.size() / 2)), y(rng.begin() + (difference_type)(rng.size() / 2), rng.end()); BOOST_TEST(check_stability(x, y, [&] { x.splice(y); })); BOOST_TEST(check_stability(x, y, [&] { y.splice(std::move(x)); })); } { Hub x; x.insert(rng.begin(), rng.end()); x.insert(rng.begin(), rng.end()); x.sort(); BOOST_TEST(check_stability(x, [&] (erase_callback callback) { for(auto it = x.begin(); it != x.end(); ) { auto next = std::next(it); while(next != x.end() && *next == *it) callback(next++); it = next; } x.unique(); })); } { Hub x(rng.begin(), rng.end()); auto is_even = [] (const value_type& v) { return v % 2 == 0; }; BOOST_TEST(check_stability(x, [&] (erase_callback callback) { for(auto it = x.begin(); it != x.end(); ++it) { if(is_even(*it)) callback(it); } erase_if(x, is_even); })); } } int main() { test>(); test>(); return boost::report_errors(); } #endif