[libcxx-commits] [libcxx] [libc++] Implement P3567R2 flat_meow fixes (PR #162022)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Oct 5 13:14:55 PDT 2025
https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/162022
>From 2b106389aff6d39b5ccda530470343738bc652bb Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 5 Oct 2025 19:13:45 +0100
Subject: [PATCH 1/3] [libc++] Implement P3567R2 flat_meow fixes
---
libcxx/include/__flat_map/flat_map.h | 25 +++-
libcxx/include/__flat_map/flat_multimap.h | 23 +++-
libcxx/include/__flat_set/flat_multiset.h | 25 +++-
libcxx/include/__flat_set/flat_set.h | 24 +++-
.../insert_range_sorted_unique.pass.cpp | 121 +++++++++++++++++
.../swap_exception.pass.cpp | 27 ++--
.../flat.map.modifiers/swap_free.pass.cpp | 5 +-
.../flat.map.modifiers/swap_member.pass.cpp | 6 +-
.../insert_range_sorted_equivalent.pass.cpp | 123 ++++++++++++++++++
.../swap_exception.pass.cpp | 22 +++-
.../swap_free.pass.cpp | 5 +-
.../swap_member.pass.cpp | 4 +-
.../insert_range_sorted_equivalent.pass.cpp | 100 ++++++++++++++
.../swap_exception.pass.cpp | 12 +-
.../swap_free.pass.cpp | 5 +-
.../swap_member.pass.cpp | 4 +-
.../insert_range_sorted_unique.pass.cpp | 108 +++++++++++++++
.../swap_exception.pass.cpp | 12 +-
.../flat.set.modifiers/swap_free.pass.cpp | 5 +-
.../flat.set.modifiers/swap_member.pass.cpp | 4 +-
20 files changed, 600 insertions(+), 60 deletions(-)
create mode 100644 libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
create mode 100644 libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
create mode 100644 libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
create mode 100644 libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp
diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 7bb235ba76503..0b27b5a0d5f9c 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -587,6 +587,15 @@ class flat_map {
__append_sort_merge_unique</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range));
}
+ template <_ContainerCompatibleRange<value_type> _Range>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_unique_t, _Range&& __range) {
+ if constexpr (ranges::sized_range<_Range>) {
+ __reserve(ranges::size(__range));
+ }
+
+ __append_sort_merge_unique</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range));
+ }
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
insert(__il.begin(), __il.end());
}
@@ -736,14 +745,17 @@ class flat_map {
return iterator(std::move(__key_it), std::move(__mapped_it));
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __y) noexcept {
- // warning: The spec has unconditional noexcept, which means that
- // if any of the following functions throw an exception,
- // std::terminate will be called.
- // This is discussed in P2767, which hasn't been voted on yet.
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ swap(flat_map& __y) noexcept(is_nothrow_swappable_v<key_container_type> &&
+ is_nothrow_swappable_v<mapped_container_type> && is_nothrow_swappable_v<key_compare>) {
+ auto __on_failure = std::__make_exception_guard([&]() noexcept {
+ clear() /* noexcept */;
+ __y.clear() /* noexcept */;
+ });
ranges::swap(__compare_, __y.__compare_);
ranges::swap(__containers_.keys, __y.__containers_.keys);
ranges::swap(__containers_.values, __y.__containers_.values);
+ __on_failure.__complete();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
@@ -876,7 +888,8 @@ class flat_map {
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
- friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __x, flat_map& __y) noexcept {
+ friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ swap(flat_map& __x, flat_map& __y) noexcept(noexcept(__x.swap(__y))) {
__x.swap(__y);
}
diff --git a/libcxx/include/__flat_map/flat_multimap.h b/libcxx/include/__flat_map/flat_multimap.h
index 96d945405cffe..27fe6547bbdfe 100644
--- a/libcxx/include/__flat_map/flat_multimap.h
+++ b/libcxx/include/__flat_map/flat_multimap.h
@@ -568,6 +568,15 @@ class flat_multimap {
__append_sort_merge</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range));
}
+ template <_ContainerCompatibleRange<value_type> _Range>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_equivalent_t, _Range&& __range) {
+ if constexpr (ranges::sized_range<_Range>) {
+ __reserve(ranges::size(__range));
+ }
+
+ __append_sort_merge</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range));
+ }
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
insert(__il.begin(), __il.end());
}
@@ -628,13 +637,17 @@ class flat_multimap {
return iterator(std::move(__key_it), std::move(__mapped_it));
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept {
- // warning: The spec has unconditional noexcept, which means that
- // if any of the following functions throw an exception,
- // std::terminate will be called
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept(
+ is_nothrow_swappable_v<key_container_type> && is_nothrow_swappable_v<mapped_container_type> &&
+ is_nothrow_swappable_v<key_compare>) {
+ auto __on_failure = std::__make_exception_guard([&]() noexcept {
+ clear() /* noexcept */;
+ __y.clear() /* noexcept */;
+ });
ranges::swap(__compare_, __y.__compare_);
ranges::swap(__containers_.keys, __y.__containers_.keys);
ranges::swap(__containers_.values, __y.__containers_.values);
+ __on_failure.__complete();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
@@ -771,7 +784,7 @@ class flat_multimap {
}
friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
- swap(flat_multimap& __x, flat_multimap& __y) noexcept {
+ swap(flat_multimap& __x, flat_multimap& __y) noexcept(noexcept(__x.swap(__y))) {
__x.swap(__y);
}
diff --git a/libcxx/include/__flat_set/flat_multiset.h b/libcxx/include/__flat_set/flat_multiset.h
index b1a4917659c49..19f8b0ff01539 100644
--- a/libcxx/include/__flat_set/flat_multiset.h
+++ b/libcxx/include/__flat_set/flat_multiset.h
@@ -401,6 +401,15 @@ class flat_multiset {
__append_sort_merge</*WasSorted = */ false>(std::forward<_Range>(__range));
}
+ template <_ContainerCompatibleRange<value_type> _Range>
+ _LIBCPP_HIDE_FROM_ABI void insert_range(sorted_equivalent_t, _Range&& __range) {
+ if constexpr (ranges::sized_range<_Range>) {
+ __reserve(ranges::size(__range));
+ }
+
+ __append_sort_merge</*WasSorted = */ true>(std::forward<_Range>(__range));
+ }
+
_LIBCPP_HIDE_FROM_ABI void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); }
_LIBCPP_HIDE_FROM_ABI void insert(sorted_equivalent_t, initializer_list<value_type> __il) {
@@ -454,13 +463,15 @@ class flat_multiset {
return iterator(std::move(__key_it));
}
- _LIBCPP_HIDE_FROM_ABI void swap(flat_multiset& __y) noexcept {
- // warning: The spec has unconditional noexcept, which means that
- // if any of the following functions throw an exception,
- // std::terminate will be called
- // This is discussed in P3567, which hasn't been voted on yet.
+ _LIBCPP_HIDE_FROM_ABI void
+ swap(flat_multiset& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) {
+ auto __on_failure = std::__make_exception_guard([&]() noexcept {
+ clear() /* noexcept */;
+ __y.clear() /* noexcept */;
+ });
ranges::swap(__compare_, __y.__compare_);
ranges::swap(__keys_, __y.__keys_);
+ __on_failure.__complete();
}
_LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); }
@@ -578,7 +589,9 @@ class flat_multiset {
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
- friend _LIBCPP_HIDE_FROM_ABI void swap(flat_multiset& __x, flat_multiset& __y) noexcept { __x.swap(__y); }
+ friend _LIBCPP_HIDE_FROM_ABI void swap(flat_multiset& __x, flat_multiset& __y) noexcept(noexcept(__x.swap(__y))) {
+ __x.swap(__y);
+ }
private:
template <bool _WasSorted, class... _Args>
diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h
index 5fa1f2d8acb9b..b4ef9ead2b70b 100644
--- a/libcxx/include/__flat_set/flat_set.h
+++ b/libcxx/include/__flat_set/flat_set.h
@@ -458,6 +458,15 @@ class flat_set {
__append_sort_merge_unique</*WasSorted = */ false>(std::forward<_Range>(__range));
}
+ template <_ContainerCompatibleRange<value_type> _Range>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(std::sorted_unique_t, _Range&& __range) {
+ if constexpr (ranges::sized_range<_Range>) {
+ __reserve(ranges::size(__range));
+ }
+
+ __append_sort_merge_unique</*WasSorted = */ true>(std::forward<_Range>(__range));
+ }
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
insert(__il.begin(), __il.end());
}
@@ -516,13 +525,15 @@ class flat_set {
return iterator(std::move(__key_it));
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __y) noexcept {
- // warning: The spec has unconditional noexcept, which means that
- // if any of the following functions throw an exception,
- // std::terminate will be called.
- // This is discussed in P2767, which hasn't been voted on yet.
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ swap(flat_set& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) {
+ auto __on_failure = std::__make_exception_guard([&]() noexcept {
+ clear() /* noexcept */;
+ __y.clear() /* noexcept */;
+ });
ranges::swap(__compare_, __y.__compare_);
ranges::swap(__keys_, __y.__keys_);
+ __on_failure.__complete();
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __keys_.clear(); }
@@ -647,7 +658,8 @@ class flat_set {
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
- friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __x, flat_set& __y) noexcept {
+ friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+ swap(flat_set& __x, flat_set& __y) noexcept(noexcept(__x.swap(__y))) {
__x.swap(__y);
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
new file mode 100644
index 0000000000000..124130aa3e108
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
@@ -0,0 +1,121 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_map>
+
+// template<container-compatible-range<value_type> R>
+// void insert_range(sorted_unique, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_map>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward<R>(r)); };
+
+using Map = std::flat_map<int, double>;
+
+static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<int, double>*>>);
+static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<short, double>*>>);
+static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<int*>>);
+static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<double*>>);
+
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
+
+ {
+ using P = std::pair<int, int>;
+ using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ using It = forward_iterator<const P*>;
+ M m = {{10, 1}, {8, 2}, {5, 3}, {2, 4}, {1, 5}};
+ P ar[] = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+ std::ranges::subrange r = {It(ar), It(ar + 5)};
+ static_assert(std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_unique, r);
+ assert((m == M{{1, 5}, {2, 4}, {3, 1}, {4, 3}, {5, 3}, {8, 2}, {9, 6}, {10, 1}}));
+ }
+ {
+ using P = std::pair<int, int>;
+ using M = std::flat_map<Key, Value, std::greater<>, KeyContainer, ValueContainer>;
+ using It = cpp20_input_iterator<const P*>;
+ M m = {{8, 1}, {5, 2}, {3, 3}, {2, 4}};
+ P ar[] = {{9, 6}, {5, 5}, {4, 3}, {3, 1}, {1, 2}};
+ std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 5))};
+ static_assert(!std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_unique, r);
+ assert((m == M{{1, 2}, {2, 4}, {3, 3}, {4, 3}, {5, 2}, {8, 1}, {9, 6}}));
+ }
+ {
+ // was empty
+ using P = std::pair<int, int>;
+ using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ M m;
+ P ar[] = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+ m.insert_range(std::sorted_unique, ar);
+ assert(std::ranges::equal(m, ar));
+ }
+}
+
+constexpr bool test() {
+ test<std::vector<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ test<std::deque<int>, std::vector<int>>();
+ }
+ test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ {
+ // Items are forwarded correctly from the input range
+ std::pair<MoveOnly, MoveOnly> a[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ std::flat_map<MoveOnly, MoveOnly> m;
+ m.insert_range(std::sorted_unique, a | std::views::as_rvalue);
+ std::pair<MoveOnly, MoveOnly> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ // The element type of the range doesn't need to be std::pair
+ std::pair<int, int> pa[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 4);
+ std::flat_map<int, int> m;
+ m.insert_range(std::sorted_unique, a);
+ std::pair<int, int> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ assert(std::ranges::equal(m, expected));
+ }
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_unique, newValues); };
+ test_insert_range_exception_guarantee(insert_func);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
index f9708aac62c7e..96b88a5fbfacb 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
@@ -7,9 +7,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
-// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
// <flat_map>
@@ -17,7 +14,7 @@
// void swap(flat_map& y) noexcept;
// friend void swap(flat_map& x, flat_map& y) noexcept
-// Test that std::terminate is called if any exception is thrown during swap
+// Test that the variants are hold if any exception is thrown during swap
#include <flat_map>
#include <cassert>
@@ -42,8 +39,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m1.emplace(2, 2);
m2.emplace(3, 3);
m2.emplace(4, 4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
{
@@ -58,8 +62,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m2.emplace(3, 3);
m2.emplace(4, 4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
index 37f2914ebfdb2..c7410960ef5a8 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
@@ -31,11 +31,10 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
-static_assert(NoExceptAdlSwap<std::flat_map<int, int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(
- NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
+ !NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer, class ValueContainer>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
index 771bcd3de2c09..6a00a155f8e16 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
@@ -10,7 +10,7 @@
// <flat_map>
-// void swap(flat_map& y) noexcept;
+// void swap(flat_map& y) noexcept(see below);
#include <flat_map>
#include <cassert>
@@ -31,10 +31,10 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
{ t1.swap(t2) } noexcept;
};
-static_assert(NoExceptMemberSwap<std::flat_map<int, int>>);
+static_assert(NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(
- NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
+ !NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer, class ValueContainer>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
new file mode 100644
index 0000000000000..95d56478970e9
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
@@ -0,0 +1,123 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_map>
+
+// class flat_multimap
+
+// template<container-compatible-range<value_type> R>
+// void insert_range(sorted_equivalent_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_map>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedEquivalent =
+ requires(M m, R&& r) { m.insert_range(std::sorted_equivalent, std::forward<R>(r)); };
+
+using Map = std::flat_multimap<int, double>;
+
+static_assert(CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<std::pair<int, double>*>>);
+static_assert(CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<std::pair<short, double>*>>);
+static_assert(!CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<int*>>);
+static_assert(!CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<double*>>);
+
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+ using Key = typename KeyContainer::value_type;
+ using Value = typename ValueContainer::value_type;
+
+ {
+ using P = std::pair<int, int>;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ using It = forward_iterator<const P*>;
+ M m = {{10, 1}, {8, 2}, {5, 3}, {2, 4}, {1, 5}};
+ P ar[] = {{1, 2}, {1, 4}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+ std::ranges::subrange r = {It(ar), It(ar + 6)};
+ static_assert(std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_equivalent, r);
+ std::vector<P> expected = {{1, 5}, {1, 2}, {1, 4}, {2, 4}, {3, 1}, {4, 3}, {5, 3}, {5, 5}, {8, 2}, {9, 6}, {10, 1}};
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ using P = std::pair<int, int>;
+ using M = std::flat_multimap<Key, Value, std::greater<>, KeyContainer, ValueContainer>;
+ using It = cpp20_input_iterator<const P*>;
+ M m = {{8, 1}, {5, 2}, {3, 3}, {2, 4}};
+ P ar[] = {{9, 6}, {5, 5}, {4, 3}, {3, 1}, {1, 2}, {1, 4}};
+ std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 6))};
+ static_assert(!std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_equivalent, r);
+ std::vector<P> expected = {{9, 6}, {8, 1}, {5, 2}, {5, 5}, {4, 3}, {3, 3}, {3, 1}, {2, 4}, {1, 2}, {1, 4}};
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ // was empty
+ using P = std::pair<int, int>;
+ using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+ M m;
+ P ar[] = {{1, 2}, {1, 4}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+ m.insert_range(std::sorted_equivalent, ar);
+ assert(std::ranges::equal(m, ar));
+ }
+}
+
+constexpr bool test() {
+ test<std::vector<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test<std::deque<int>, std::vector<int>>();
+ test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
+ test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+ {
+ // Items are forwarded correctly from the input range
+ std::pair<MoveOnly, MoveOnly> a[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ std::flat_multimap<MoveOnly, MoveOnly> m;
+ m.insert_range(std::sorted_equivalent, a | std::views::as_rvalue);
+ std::pair<MoveOnly, MoveOnly> expected[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ assert(std::ranges::equal(m, expected));
+ }
+ {
+ // The element type of the range doesn't need to be std::pair
+ std::pair<int, int> pa[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 5);
+ std::flat_multimap<int, int> m;
+ m.insert_range(a);
+ std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+ assert(std::ranges::equal(m, expected));
+ }
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_equivalent, newValues); };
+ test_insert_range_exception_guarantee(insert_func);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
index a1252f301309a..85e2df982a7fc 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
@@ -44,8 +44,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m1.emplace(1, 2);
m2.emplace(3, 3);
m2.emplace(3, 4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
{
@@ -60,8 +67,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m2.emplace(3, 3);
m2.emplace(3, 4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
index efad2d78d5b76..f714af77ca647 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
@@ -33,10 +33,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
-static_assert(NoExceptAdlSwap<std::flat_multimap<int, int>>);
-
+static_assert(NoExceptAdlSwap< std::flat_multimap<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<
+static_assert(!NoExceptAdlSwap<
std::flat_multimap<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
#endif
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
index 8f31884aa3a5f..0c6211ab3c2cc 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
@@ -33,9 +33,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
{ t1.swap(t2) } noexcept;
};
-static_assert(NoExceptMemberSwap<std::flat_multimap<int, int>>);
+static_assert(NoExceptMemberSwap< std::flat_multimap<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<
+static_assert(!NoExceptMemberSwap<
std::flat_multimap<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
#endif
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
new file mode 100644
index 0000000000000..f6382a200250b
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_set>
+
+// template<container-compatible-range<value_type> R>
+// void insert_range(sorted_equivalent_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_set>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward<R>(r)); };
+
+using Set = std::flat_multiset<int, double>;
+
+static_assert(CanInsertRange<Set, std::ranges::subrange<int*>>);
+static_assert(CanInsertRange<Set, std::ranges::subrange<short*>>);
+static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<int, int>*>>);
+static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<short, short>*>>);
+
+template <class KeyContainer>
+void test_one() {
+ using Key = typename KeyContainer::value_type;
+
+ {
+ using M = std::flat_multiset<Key, std::less<Key>, KeyContainer>;
+ using It = forward_iterator<const int*>;
+ M m = {10, 10, 8, 5, 2, 1, 1};
+ int ar[] = {1, 1, 3, 4, 5, 9};
+ std::ranges::subrange r = {It(ar), It(ar + 6)};
+ static_assert(std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_equivalent, r);
+ assert((m == M{1, 1, 1, 1, 2, 3, 4, 5, 5, 8, 9, 10, 10}));
+ }
+ {
+ using M = std::flat_multiset<Key, std::greater<>, KeyContainer>;
+ using It = cpp20_input_iterator<const int*>;
+ M m = {10, 10, 8, 5, 2, 1, 1};
+ int ar[] = {9, 5, 4, 3, 1, 1};
+ std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 6))};
+ static_assert(!std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_equivalent, r);
+ assert((m == M{1, 1, 1, 1, 2, 3, 4, 5, 5, 8, 9, 10, 10}));
+ }
+ {
+ // was empty
+ using M = std::flat_multiset<Key, std::less<Key>, KeyContainer>;
+ M m;
+ int ar[] = {1, 1, 3, 4, 5, 9};
+ m.insert_range(std::sorted_equivalent, ar);
+ assert((m == M{1, 1, 3, 4, 5, 9}));
+ }
+}
+
+void test() {
+ test_one<std::vector<int>>();
+ test_one<std::deque<int>>();
+ test_one<MinSequenceContainer<int>>();
+ test_one<std::vector<int, min_allocator<int>>>();
+ {
+ // Items are forwarded correctly from the input range.
+ MoveOnly a[] = {1, 1, 3, 4, 5};
+ std::flat_multiset<MoveOnly> m;
+ m.insert_range(std::sorted_equivalent, a | std::views::as_rvalue);
+ MoveOnly expected[] = {1, 1, 3, 4, 5};
+ assert(std::ranges::equal(m, expected));
+ }
+}
+
+void test_exception() {
+ auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_equivalent, newValues); };
+ test_insert_range_exception_guarantee(insert_func);
+}
+
+int main(int, char**) {
+ test();
+ test_exception();
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
index 705ee88994872..03dbe95c4e221 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
@@ -41,8 +41,16 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m1.emplace(1);
m2.emplace(1);
m2.emplace(4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
index 2e3ed02c3c00e..7746e40c96d8c 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
@@ -31,10 +31,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
-static_assert(NoExceptAdlSwap<std::flat_multiset<int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
index 1d0d9152d1c1f..ca641fdc9f113 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
@@ -31,9 +31,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
{ t1.swap(t2) } noexcept;
};
-static_assert(NoExceptMemberSwap<std::flat_multiset<int>>);
+static_assert(NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp
new file mode 100644
index 0000000000000..8d41914fe7ac9
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_set>
+
+// template<container-compatible-range<value_type> R>
+// void insert_range(sorted_unique_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_set>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward<R>(r)); };
+
+using Set = std::flat_set<int, double>;
+
+static_assert(CanInsertRangeSortedUnique<Set, std::ranges::subrange<int*>>);
+static_assert(CanInsertRangeSortedUnique<Set, std::ranges::subrange<short*>>);
+static_assert(!CanInsertRangeSortedUnique<Set, std::ranges::subrange<std::pair<int, int>*>>);
+static_assert(!CanInsertRangeSortedUnique<Set, std::ranges::subrange<std::pair<short, short>*>>);
+
+template <class KeyContainer>
+constexpr void test_one() {
+ using Key = typename KeyContainer::value_type;
+
+ {
+ using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
+ using It = forward_iterator<const int*>;
+ M m = {10, 8, 5, 2, 1};
+ int ar[] = {1, 3, 4, 5, 9};
+ std::ranges::subrange r = {It(ar), It(ar + 5)};
+ static_assert(std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_unique, r);
+ assert((m == M{1, 2, 3, 4, 5, 8, 9, 10}));
+ }
+ {
+ using M = std::flat_set<Key, std::greater<>, KeyContainer>;
+ using It = cpp20_input_iterator<const int*>;
+ M m = {8, 5, 3, 2};
+ int ar[] = {9, 5, 4, 3, 1};
+ std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 5))};
+ static_assert(!std::ranges::common_range<decltype(r)>);
+ m.insert_range(std::sorted_unique, r);
+ assert((m == M{1, 2, 3, 4, 5, 8, 9}));
+ }
+ {
+ // was empty
+ using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
+ M m;
+ int ar[] = {1, 3, 4, 5, 9};
+ m.insert_range(std::sorted_unique, ar);
+ assert((m == M{1, 3, 4, 5, 9}));
+ }
+}
+
+constexpr bool test() {
+ test_one<std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ test_one<std::deque<int>>();
+ test_one<MinSequenceContainer<int>>();
+ test_one<std::vector<int, min_allocator<int>>>();
+ {
+ // Items are forwarded correctly from the input range.
+ MoveOnly a[] = {1, 3, 4, 5};
+ std::flat_set<MoveOnly> m;
+ m.insert_range(std::sorted_unique, a | std::views::as_rvalue);
+ MoveOnly expected[] = {1, 3, 4, 5};
+ assert(std::ranges::equal(m, expected));
+ }
+
+ return true;
+}
+
+void test_exception() {
+ auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_unique, newValues); };
+ test_insert_range_exception_guarantee(insert_func);
+}
+
+int main(int, char**) {
+ test();
+ test_exception();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
index 23a2dc85989bb..268dd11fe83df 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
@@ -41,8 +41,16 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m1.emplace(2);
m2.emplace(3);
m2.emplace(4);
- // swap is noexcept
- EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+
+ try {
+ swap_function(m1, m2);
+ assert(false);
+ } catch (int) {
+ check_invariant(m1);
+ check_invariant(m2);
+ LIBCPP_ASSERT(m1.size() == 0);
+ LIBCPP_ASSERT(m2.size() == 0);
+ }
}
}
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
index 6b4a65e4701b2..b07af85063093 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
@@ -31,10 +31,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
-static_assert(NoExceptAdlSwap<std::flat_set<int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_set<int, std::less<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptAdlSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
index a3b605ee94cfb..eaecd5f15a661 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
@@ -31,9 +31,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
{ t1.swap(t2) } noexcept;
};
-static_assert(NoExceptMemberSwap<std::flat_set<int>>);
+static_assert(NoExceptMemberSwap<std::flat_set<int, std::less<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptMemberSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
>From 90923829109cc2196b9575e1f553d4bede04bbb7 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 5 Oct 2025 21:13:41 +0100
Subject: [PATCH 2/3] ci
---
libcxx/include/__flat_set/flat_multiset.h | 2 +-
.../flat.map/flat.map.modifiers/swap_exception.pass.cpp | 1 +
.../flat.multimap.modifiers/swap_exception.pass.cpp | 2 --
.../flat.multiset.modifiers/swap_exception.pass.cpp | 2 --
.../flat.set/flat.set.modifiers/swap_exception.pass.cpp | 2 --
5 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/libcxx/include/__flat_set/flat_multiset.h b/libcxx/include/__flat_set/flat_multiset.h
index 19f8b0ff01539..7754e9435d4f4 100644
--- a/libcxx/include/__flat_set/flat_multiset.h
+++ b/libcxx/include/__flat_set/flat_multiset.h
@@ -603,7 +603,7 @@ class flat_multiset {
ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_);
} else {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
- ranges::is_sorted(__keys_ | ranges::views::drop(__old_size)), "Key container is not sorted");
+ ranges::is_sorted(__keys_ | ranges::views::drop(__old_size), __compare_), "Key container is not sorted");
}
ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_);
__on_failure.__complete();
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
index 96b88a5fbfacb..a5db32813bf46 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
// <flat_map>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
index 85e2df982a7fc..1ad7d9697b8e4 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
index 03dbe95c4e221..76903f30353b7 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
index 268dd11fe83df..e4b5f24b3e824 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
>From b2373bbff4cfce90eb9d63e8ed8b9039dd3969ec Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 5 Oct 2025 21:14:44 +0100
Subject: [PATCH 3/3] remove headers from test
---
.../flat.map/flat.map.modifiers/swap_exception.pass.cpp | 1 -
.../flat.multimap.modifiers/swap_exception.pass.cpp | 1 -
.../flat.multiset.modifiers/swap_exception.pass.cpp | 1 -
.../flat.set/flat.set.modifiers/swap_exception.pass.cpp | 1 -
4 files changed, 4 deletions(-)
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
index a5db32813bf46..8b8e70fab41e1 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
@@ -25,7 +25,6 @@
#include "test_macros.h"
#include "../helpers.h"
-#include "check_assertion.h"
template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
index 1ad7d9697b8e4..d426944c9463a 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
@@ -27,7 +27,6 @@
#include "test_macros.h"
#include "../helpers.h"
-#include "check_assertion.h"
template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
index 76903f30353b7..af035f6464696 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
@@ -25,7 +25,6 @@
#include "test_macros.h"
#include "../helpers.h"
-#include "check_assertion.h"
template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
index e4b5f24b3e824..ae0d4f0950fa7 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
@@ -25,7 +25,6 @@
#include "test_macros.h"
#include "../helpers.h"
-#include "check_assertion.h"
template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
More information about the libcxx-commits
mailing list