diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 5f1e521bd79c2..4a82461b80534 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -334,7 +334,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_expected`` ``202211L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_flat_map`` ``202207L`` + ``__cpp_lib_flat_map`` ``202511L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_flat_set`` ``202207L`` ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index 76d3bb263290f..268de27b97a71 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -51,6 +51,7 @@ Implemented Papers - P2835R7: Expose ``std::atomic_ref``'s object address (`Github `__) - P2944R3: Comparisons for ``reference_wrapper`` (`Github `__) - P3168R2: Give ``std::optional`` Range Support (`Github `__) +- P3567R2: ``flat_meow`` Fixes (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 4c941294ccb40..a9904e2d38422 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -159,7 +159,7 @@ "","","","","","","" "`P3920R0 `__","Wording for NB comment resolution on trivial relocation","2025-11 (Kona)","","","`#171269 `__","" "`P3016R6 `__","Resolve inconsistencies in begin/end for ``valarray`` and braced initializer lists","2025-11 (Kona)","","","`#171271 `__","" -"`P3567R2 `__","``flat_meow`` Fixes","2025-11 (Kona)","","","`#171272 `__","" +"`P3567R2 `__","``flat_meow`` Fixes","2025-11 (Kona)","|Complete|","22","`#171272 `__","" "`P3663R3 `__","Future-proof ``submdspan_mapping``","2025-11 (Kona)","","","`#166089 `__","" "`P3914R0 `__","Assorted NB comment resolutions for Kona 2025","2025-11 (Kona)","","","`#171274 `__","" "`P3836R2 `__","Make ``optional`` trivially copyable","2025-11 (Kona)","","","`#171275 `__","" diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h index 4cd938b54cbf4..97180ab99e441 100644 --- a/libcxx/include/__flat_map/flat_map.h +++ b/libcxx/include/__flat_map/flat_map.h @@ -592,6 +592,15 @@ class flat_map { __append_sort_merge_unique(ranges::begin(__range), ranges::end(__range)); } + template <_ContainerCompatibleRange _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(ranges::begin(__range), ranges::end(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -741,14 +750,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 && + is_nothrow_swappable_v && is_nothrow_swappable_v) { + 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 { @@ -886,7 +898,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 3db669066ba97..f0540a7d5e8a3 100644 --- a/libcxx/include/__flat_map/flat_multimap.h +++ b/libcxx/include/__flat_map/flat_multimap.h @@ -573,6 +573,15 @@ class flat_multimap { __append_sort_merge(ranges::begin(__range), ranges::end(__range)); } + template <_ContainerCompatibleRange _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(ranges::begin(__range), ranges::end(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -633,13 +642,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 && is_nothrow_swappable_v && + is_nothrow_swappable_v) { + 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 { @@ -781,7 +794,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 6a93ec7210e74..b2de63bc3038c 100644 --- a/libcxx/include/__flat_set/flat_multiset.h +++ b/libcxx/include/__flat_set/flat_multiset.h @@ -449,6 +449,15 @@ class flat_multiset { __append_sort_merge(std::forward<_Range>(__range)); } + template <_ContainerCompatibleRange _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(std::forward<_Range>(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -505,13 +514,15 @@ class flat_multiset { return iterator(std::move(__key_it)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 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 _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_multiset& __y) noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v) { + 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(); } @@ -646,7 +657,7 @@ class flat_multiset { } friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void - swap(flat_multiset& __x, flat_multiset& __y) noexcept { + swap(flat_multiset& __x, flat_multiset& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } @@ -660,7 +671,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/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index 1be38f10ea9f3..dad747e7857cd 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -466,6 +466,15 @@ class flat_set { __append_sort_merge_unique(std::forward<_Range>(__range)); } + template <_ContainerCompatibleRange _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(std::forward<_Range>(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list __il) { insert(__il.begin(), __il.end()); } @@ -524,13 +533,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 && is_nothrow_swappable_v) { + 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(); } @@ -661,7 +672,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/include/flat_map b/libcxx/include/flat_map index eea9896165f06..f2566c7745c88 100644 --- a/libcxx/include/flat_map +++ b/libcxx/include/flat_map @@ -17,18 +17,359 @@ #include // see [initializer.list.syn] namespace std { + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + // [flat.map], class template flat_map template, class KeyContainer = vector, class MappedContainer = vector> - class flat_map; + class flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; + class value_compare { + private: + key_compare comp; // exposition only + constexpr value_compare(key_compare c) : comp(c) { } // exposition only + + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return comp(x.first, y.first); + } + }; + + struct containers { + key_container_type keys; + mapped_container_type values; + }; + + // [flat.map.cons], constructors + constexpr flat_map() : flat_map(key_compare()) { } + + constexpr flat_map(const flat_map&); + constexpr flat_map(flat_map&&); + constexpr flat_map& operator=(const flat_map&); + constexpr flat_map& operator=(flat_map&&); + + constexpr explicit flat_map(const key_compare& comp) + : c(), compare(comp) { } + + constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + constexpr flat_map(sorted_unique_t, key_container_type key_cont, + mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + template + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(first, last); } + + template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(sorted_unique, first, last); } + + template R> + constexpr flat_map(from_range_t, R&& rg) + : flat_map(from_range, std::forward(rg), key_compare()) { } + template R> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp) + : flat_map(comp) { insert_range(std::forward(rg)); } + + constexpr flat_map(initializer_list il, const key_compare& comp = key_compare()) + : flat_map(il.begin(), il.end(), comp) { } + + constexpr flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp = key_compare()) + : flat_map(sorted_unique, il.begin(), il.end(), comp) { } + + // [flat.map.cons.alloc], constructors with allocators + + template + constexpr explicit flat_map(const Alloc& a); + template + constexpr flat_map(const key_compare& comp, const Alloc& a); + template + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const Alloc& a); + template + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); + template + constexpr flat_map(const flat_map&, const Alloc& a); + template + constexpr flat_map(flat_map&&, const Alloc& a); + template + constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const Alloc& a); + template R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_map(initializer_list il, const Alloc& a); + template + constexpr flat_map(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_map(sorted_unique_t, initializer_list il, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_map& operator=(initializer_list); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // [flat.map.capacity], capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.map.access], element access + constexpr mapped_type& operator[](const key_type& x); + constexpr mapped_type& operator[](key_type&& x); + template constexpr mapped_type& operator[](K&& x); + constexpr mapped_type& at(const key_type& x); + constexpr const mapped_type& at(const key_type& x) const; + template constexpr mapped_type& at(const K& x); + template constexpr const mapped_type& at(const K& x) const; + + // [flat.map.modifiers], modifiers + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr pair insert(const value_type& x) + { return emplace(x); } + constexpr pair insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template constexpr pair insert(P&& x); + template + constexpr iterator insert(const_iterator position, P&&); + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); + template R> + constexpr void insert_range(R&& rg); + template R> + constexpr void insert_range(sorted_unique_t, R&& rg); + + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_unique_t, initializer_list il) + { insert(sorted_unique, il.begin(), il.end()); } + + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + template + constexpr pair try_emplace(const key_type& k, Args&&... args); + template + constexpr pair try_emplace(key_type&& k, Args&&... args); + template + constexpr pair try_emplace(K&& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + template + constexpr pair insert_or_assign(const key_type& k, M&& obj); + template + constexpr pair insert_or_assign(key_type&& k, M&& obj); + template + constexpr pair insert_or_assign(K&& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_map& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + constexpr const key_container_type& keys() const noexcept { return c.keys; } + constexpr const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_map& x, const flat_map& y); + + friend constexpr synth-three-way-result + operator<=>(const flat_map& x, const flat_map& y); + + friend constexpr void swap(flat_map& x, flat_map& y) noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + containers c; // exposition only + key_compare compare; // exposition only + + struct key-equiv { // exposition only + constexpr key-equiv(key_compare c) : comp(c) { } + constexpr bool operator()(const_reference x, const_reference y) const { + return !comp(x.first, y.first) && !comp(y.first, x.first); + } + key_compare comp; + }; + }; + + template> + flat_map(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map; + + template + flat_map(KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + template + flat_map(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map; + + template> + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map; + + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map; + + template>> + flat_map(InputIterator, InputIterator, Compare = Compare()) + -> flat_map, iter-mapped-type, Compare>; + + template>> + flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_map, iter-mapped-type, Compare>; + + template>, + class Allocator = allocator> + flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_map, range-mapped-type, Compare, + vector, alloc-rebind>>, + vector, alloc-rebind>>>; + + template + flat_map(from_range_t, R&&, Allocator) + -> flat_map, range-mapped-type, less>, + vector, alloc-rebind>>, + vector, alloc-rebind>>>; + + template> + flat_map(initializer_list>, Compare = Compare()) + -> flat_map; + + template> + flat_map(sorted_unique_t, initializer_list>, Compare = Compare()) + -> flat_map; template - struct uses_allocator, - Allocator>; + class Allocator> + struct uses_allocator, Allocator> + : bool_constant && + uses_allocator_v> { }; // [flat.map.erasure], erasure for flat_map template::size_type erase_if(flat_map& c, Predicate pred); + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multimap], class template flat_multimap template, class KeyContainer = vector, class MappedContainer = vector> - class flat_multimap; + class flat_multimap { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; + class value_compare { + private: + key_compare comp; // exposition only + constexpr value_compare(key_compare c) : comp(c) { } // exposition only + + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return comp(x.first, y.first); + } + }; + + struct containers { + key_container_type keys; + mapped_container_type values; + }; + + // [flat.multimap.cons], constructors + constexpr flat_multimap() : flat_multimap(key_compare()) { } + + constexpr flat_multimap(const flat_multimap&); + constexpr flat_multimap(flat_multimap&&); + constexpr flat_multimap& operator=(const flat_multimap&); + constexpr flat_multimap& operator=(flat_multimap&&); + + constexpr explicit flat_multimap(const key_compare& comp) + : c(), compare(comp) { } + + constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + constexpr flat_multimap(sorted_equivalent_t, + key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + template + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(sorted_equivalent, first, last); } + + template R> + constexpr flat_multimap(from_range_t, R&& rg) + : flat_multimap(from_range, std::forward(rg), key_compare()) { } + template R> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp) + : flat_multimap(comp) { insert_range(std::forward(rg)); } + + constexpr flat_multimap(initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(il.begin(), il.end(), comp) { } + + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(sorted_equivalent, il.begin(), il.end(), comp) { } + + // [flat.multimap.cons.alloc], constructors with allocators + + template + constexpr explicit flat_multimap(const Alloc& a); + template + constexpr flat_multimap(const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(const flat_multimap&, const Alloc& a); + template + constexpr flat_multimap(flat_multimap&&, const Alloc& a); + template + constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a); + template R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(initializer_list il, const Alloc& a); + template + constexpr flat_multimap(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + flat_multimap& operator=(initializer_list); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // modifiers + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr iterator insert(const value_type& x) + { return emplace(x); } + constexpr iterator insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template constexpr iterator insert(P&& x); + template + constexpr iterator insert(const_iterator position, P&&); + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template R> + constexpr void insert_range(R&& rg); + template R> + constexpr void insert_range(sorted_equivalent_t, R&& rg); + + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_equivalent_t, initializer_list il) + { insert(sorted_equivalent, il.begin(), il.end()); } + + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_multimap&) + noexcept(is_nothrow_swappable_v && + is_nothrow_swappable_v && + is_nothrow_swappable_v); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + constexpr const key_container_type& keys() const noexcept { return c.keys; } + constexpr const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template + constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_multimap& x, const flat_multimap& y); + + friend constexpr synth-three-way-result + operator<=>(const flat_multimap& x, const flat_multimap& y); + + friend constexpr void swap(flat_multimap& x, flat_multimap& y) + noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + containers c; // exposition only + key_compare compare; // exposition only + }; + + template> + flat_multimap(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap; + + template + flat_multimap(KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + template + flat_multimap(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap; + + template> + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap; + + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap; + + template>> + flat_multimap(InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap, iter-mapped-type, Compare>; + + template>> + flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap, iter-mapped-type, Compare>; + + template>, + class Allocator = allocator> + flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multimap, range-mapped-type, Compare, + vector, + alloc-rebind>>, + vector, + alloc-rebind>>>; + + template + flat_multimap(from_range_t, R&&, Allocator) + -> flat_multimap, range-mapped-type, less>, + vector, + alloc-rebind>>, + vector, + alloc-rebind>>>; + + template> + flat_multimap(initializer_list>, Compare = Compare()) + -> flat_multimap; + + template> + flat_multimap(sorted_equivalent_t, initializer_list>, Compare = Compare()) + -> flat_multimap; template + class Allocator> struct uses_allocator, - Allocator>; + Allocator> + : bool_constant && + uses_allocator_v> { }; // [flat.multimap.erasure], erasure for flat_multimap template // see [initializer.list.syn] namespace std { + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + // [flat.set], class template flat_set template, class KeyContainer = vector> - class flat_set; + class flat_set { + public: + // types + using key_type = Key; + using value_type = Key; + using key_compare = Compare; + using value_compare = Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = KeyContainer::size_type; + using difference_type = KeyContainer::difference_type; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = KeyContainer; - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; + // [flat.set.cons], constructors + constexpr flat_set() : flat_set(key_compare()) { } + + constexpr flat_set(const flat_set&); + constexpr flat_set(flat_set&&); + constexpr flat_set& operator=(const flat_set&); + constexpr flat_set& operator=(flat_set&&); + + constexpr explicit flat_set(const key_compare& comp) + : c(), compare(comp) { } + + constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare()); + + constexpr flat_set(sorted_unique_t, container_type cont, + const key_compare& comp = key_compare()) + : c(std::move(cont)), compare(comp) { } + + template + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(first, last), compare(comp) { } + + template R> + constexpr flat_set(from_range_t, R&& rg) + : flat_set(from_range, std::forward(rg), key_compare()) { } + template R> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp) + : flat_set(comp) + { insert_range(std::forward(rg)); } + + constexpr flat_set(initializer_list il, const key_compare& comp = key_compare()) + : flat_set(il.begin(), il.end(), comp) { } + + constexpr flat_set(sorted_unique_t, initializer_list il, + const key_compare& comp = key_compare()) + : flat_set(sorted_unique, il.begin(), il.end(), comp) { } + + // [flat.set.cons.alloc], constructors with allocators + + template + constexpr explicit flat_set(const Alloc& a); + template + constexpr flat_set(const key_compare& comp, const Alloc& a); + template + constexpr flat_set(const container_type& cont, const Alloc& a); + template + constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_set(const flat_set&, const Alloc& a); + template + constexpr flat_set(flat_set&&, const Alloc& a); + template + constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const Alloc& a); + template R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_set(initializer_list il, const Alloc& a); + template + constexpr flat_set(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_set& operator=(initializer_list); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.set.modifiers], modifiers + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr pair insert(const value_type& x) + { return emplace(x); } + constexpr pair insert(value_type&& x) + { return emplace(std::move(x)); } + template constexpr pair insert(K&& x); + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + template constexpr iterator insert(const_iterator hint, K&& x); + + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); + template R> + constexpr void insert_range(R&& rg); + template R> + constexpr void insert_range(sorted_unique_t, R&& rg); + + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_unique_t, initializer_list il) + { insert(sorted_unique, il.begin(), il.end()); } + + constexpr container_type extract() &&; + constexpr void replace(container_type&&); + + constexpr iterator erase(iterator position) requires (!same_as); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_set& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + // set operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template + constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_set& x, const flat_set& y); + + friend constexpr synth-three-way-result + operator<=>(const flat_set& x, const flat_set& y); + + friend constexpr void swap(flat_set& x, flat_set& y) noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + container_type c; // exposition only + key_compare compare; // exposition only + }; + + template> + flat_set(KeyContainer, Compare = Compare()) + -> flat_set; + template + flat_set(KeyContainer, Allocator) + -> flat_set, KeyContainer>; + template + flat_set(KeyContainer, Compare, Allocator) + -> flat_set; + + template> + flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) + -> flat_set; + template + flat_set(sorted_unique_t, KeyContainer, Allocator) + -> flat_set, KeyContainer>; + template + flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) + -> flat_set; + + template>> + flat_set(InputIterator, InputIterator, Compare = Compare()) + -> flat_set, Compare>; + + template>> + flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_set, Compare>; + + template>, + class Allocator = allocator>> + flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_set, Compare, + vector, + alloc-rebind>>>; + + template + flat_set(from_range_t, R&&, Allocator) + -> flat_set, less>, + vector, + alloc-rebind>>>; + + template> + flat_set(initializer_list, Compare = Compare()) + -> flat_set; + + template> + flat_set(sorted_unique_t, initializer_list, Compare = Compare()) + -> flat_set; template - struct uses_allocator, Allocator>; + struct uses_allocator, Allocator> + : bool_constant> { }; // [flat.set.erasure], erasure for flat_set template typename flat_set::size_type erase_if(flat_set& c, Predicate pred); + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multiset], class template flat_multiset template, class KeyContainer = vector> - class flat_multiset; + class flat_multiset { + public: + // types + using key_type = Key; + using value_type = Key; + using key_compare = Compare; + using value_compare = Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = KeyContainer::size_type; + using difference_type = KeyContainer::difference_type; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = KeyContainer; - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multiset.cons], constructors + constexpr flat_multiset() : flat_multiset(key_compare()) { } + + constexpr flat_multiset(const flat_multiset&); + constexpr flat_multiset(flat_multiset&&); + constexpr flat_multiset& operator=(const flat_multiset&); + constexpr flat_multiset& operator=(flat_multiset&&); + + constexpr explicit flat_multiset(const key_compare& comp) + : c(), compare(comp) { } + + constexpr explicit flat_multiset(container_type cont, + const key_compare& comp = key_compare()); + + constexpr flat_multiset(sorted_equivalent_t, container_type cont, + const key_compare& comp = key_compare()) + : c(std::move(cont)), compare(comp) { } + + template + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(first, last), compare(comp) { } + + template R> + constexpr flat_multiset(from_range_t, R&& rg) + : flat_multiset(from_range, std::forward(rg), key_compare()) { } + template R> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp) + : flat_multiset(comp) + { insert_range(std::forward(rg)); } + + constexpr flat_multiset(initializer_list il, + const key_compare& comp = key_compare()) + : flat_multiset(il.begin(), il.end(), comp) { } + + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const key_compare& comp = key_compare()) + : flat_multiset(sorted_equivalent, il.begin(), il.end(), comp) { } + + // [flat.multiset.cons.alloc], constructors with allocators + + template + constexpr explicit flat_multiset(const Alloc& a); + template + constexpr flat_multiset(const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(const container_type& cont, const Alloc& a); + template + constexpr flat_multiset(const container_type& cont, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(const flat_multiset&, const Alloc& a); + template + constexpr flat_multiset(flat_multiset&&, const Alloc& a); + template + constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); + template R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(initializer_list il, const Alloc& a); + template + constexpr flat_multiset(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_multiset& operator=(initializer_list); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.multiset.modifiers], modifiers + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr iterator insert(const value_type& x) + { return emplace(x); } + constexpr iterator insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template R> + constexpr void insert_range(R&& rg); + template R> + constexpr void insert_range(sorted_equivalent_t, R&& rg); + + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_equivalent_t, initializer_list il) + { insert(sorted_equivalent, il.begin(), il.end()); } + + constexpr container_type extract() &&; + constexpr void replace(container_type&&); + + constexpr iterator erase(iterator position) requires (!same_as); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_multiset& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + // set operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template + constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_multiset& x, const flat_multiset& y); + + friend constexpr synth-three-way-result + operator<=>(const flat_multiset& x, const flat_multiset& y); + + friend constexpr void swap(flat_multiset& x, flat_multiset& y) + noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + container_type c; // exposition only + key_compare compare; // exposition only + }; + + template> + flat_multiset(KeyContainer, Compare = Compare()) + -> flat_multiset; + template + flat_multiset(KeyContainer, Allocator) + -> flat_multiset, KeyContainer>; + template + flat_multiset(KeyContainer, Compare, Allocator) + -> flat_multiset; + + template> + flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare()) + -> flat_multiset; + template + flat_multiset(sorted_equivalent_t, KeyContainer, Allocator) + -> flat_multiset, KeyContainer>; + template + flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator) + -> flat_multiset; + + template>> + flat_multiset(InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset, Compare>; + + template>> + flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset, Compare>; + + template>, + class Allocator = allocator>> + flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multiset, Compare, + vector, + alloc-rebind>>>; + + template + flat_multiset(from_range_t, R&&, Allocator) + -> flat_multiset, less>, + vector, + alloc-rebind>>>; + + template> + flat_multiset(initializer_list, Compare = Compare()) + -> flat_multiset; + + template> + flat_multiset(sorted_equivalent_t, initializer_list, Compare = Compare()) + -> flat_multiset; template - struct uses_allocator, Allocator>; + struct uses_allocator, Allocator> + : bool_constant> { }; // [flat.multiset.erasure], erasure for flat_multiset template diff --git a/libcxx/include/version b/libcxx/include/version index c4daaffd89acf..f959c0ab227ac 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -111,7 +111,7 @@ __cpp_lib_execution 201902L 201603L // C++17 __cpp_lib_expected 202211L __cpp_lib_filesystem 201703L -__cpp_lib_flat_map 202207L +__cpp_lib_flat_map 202511L __cpp_lib_flat_set 202207L __cpp_lib_format 202110L __cpp_lib_format_path 202403L @@ -498,7 +498,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_constexpr_typeinfo 202106L # define __cpp_lib_containers_ranges 202202L # define __cpp_lib_expected 202211L -# define __cpp_lib_flat_map 202207L +# define __cpp_lib_flat_map 202511L # define __cpp_lib_flat_set 202207L # define __cpp_lib_format_ranges 202207L // # define __cpp_lib_formatters 202302L 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 + +// + +// template R> +// void insert_range(sorted_unique, R&& rg); + +#include +#include +#include +#include +#include +#include + +#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 +concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward(r)); }; + +using Map = std::flat_map; + +static_assert(CanInsertRangeSortedUnique*>>); +static_assert(CanInsertRangeSortedUnique*>>); +static_assert(!CanInsertRangeSortedUnique>); +static_assert(!CanInsertRangeSortedUnique>); + +template +constexpr void test() { + using Key = typename KeyContainer::value_type; + using Value = typename ValueContainer::value_type; + + { + using P = std::pair; + using M = std::flat_map, KeyContainer, ValueContainer>; + using It = forward_iterator; + 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); + 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; + using M = std::flat_map, KeyContainer, ValueContainer>; + using It = cpp20_input_iterator; + 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(ar + 5))}; + static_assert(!std::ranges::common_range); + 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; + using M = std::flat_map, 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>(); +#ifndef __cpp_lib_constexpr_deque + if (!TEST_IS_CONSTANT_EVALUATED) +#endif + { + test, std::vector>(); + } + test, MinSequenceContainer>(); + test>, std::vector>>(); + { + // Items are forwarded correctly from the input range + std::pair a[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}}; + std::flat_map m; + m.insert_range(std::sorted_unique, a | std::views::as_rvalue); + std::pair 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 pa[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}}; + std::vector>> a(pa, pa + 4); + std::flat_map m; + m.insert_range(std::sorted_unique, a); + std::pair 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..16f9f8fdbff9f 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 // @@ -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 invariants are maintained if any exception is thrown during swap #include #include @@ -27,7 +24,6 @@ #include "test_macros.h" #include "../helpers.h" -#include "check_assertion.h" template void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { @@ -42,8 +38,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 +61,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>); - +static_assert(NoExceptAdlSwap, std::vector, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS static_assert( - NoExceptAdlSwap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); + !NoExceptAdlSwap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); #endif template 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 @@ // -// void swap(flat_map& y) noexcept; +// void swap(flat_map& y) noexcept(see below); #include #include @@ -31,10 +31,10 @@ concept NoExceptMemberSwap = requires(T t1, T t2) { { t1.swap(t2) } noexcept; }; -static_assert(NoExceptMemberSwap>); +static_assert(NoExceptMemberSwap, std::vector, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS static_assert( - NoExceptMemberSwap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); + !NoExceptMemberSwap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); #endif template 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 + +// + +// class flat_multimap + +// template R> +// void insert_range(sorted_equivalent_t, R&& rg); + +#include +#include +#include +#include +#include +#include + +#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 +concept CanInsertRangeSortedEquivalent = + requires(M m, R&& r) { m.insert_range(std::sorted_equivalent, std::forward(r)); }; + +using Map = std::flat_multimap; + +static_assert(CanInsertRangeSortedEquivalent*>>); +static_assert(CanInsertRangeSortedEquivalent*>>); +static_assert(!CanInsertRangeSortedEquivalent>); +static_assert(!CanInsertRangeSortedEquivalent>); + +template +constexpr void test() { + using Key = typename KeyContainer::value_type; + using Value = typename ValueContainer::value_type; + + { + using P = std::pair; + using M = std::flat_multimap, KeyContainer, ValueContainer>; + using It = forward_iterator; + 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); + m.insert_range(std::sorted_equivalent, r); + std::vector

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; + using M = std::flat_multimap, KeyContainer, ValueContainer>; + using It = cpp20_input_iterator; + 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(ar + 6))}; + static_assert(!std::ranges::common_range); + m.insert_range(std::sorted_equivalent, r); + std::vector

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; + using M = std::flat_multimap, 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>(); +#ifndef __cpp_lib_constexpr_deque + if (!TEST_IS_CONSTANT_EVALUATED) +#endif + test, std::vector>(); + test, MinSequenceContainer>(); + test>, std::vector>>(); + { + // Items are forwarded correctly from the input range + std::pair a[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}}; + std::flat_multimap m; + m.insert_range(std::sorted_equivalent, a | std::views::as_rvalue); + std::pair 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 pa[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}}; + std::vector>> a(pa, pa + 5); + std::flat_multimap m; + m.insert_range(a); + std::pair 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..79ae419d1df37 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,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 // @@ -29,7 +26,6 @@ #include "test_macros.h" #include "../helpers.h" -#include "check_assertion.h" template void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { @@ -44,8 +40,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 +63,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>); - +static_assert(NoExceptAdlSwap< std::flat_multimap, std::vector, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptAdlSwap< +static_assert(!NoExceptAdlSwap< std::flat_multimap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); #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>); +static_assert(NoExceptMemberSwap< std::flat_multimap, std::vector, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptMemberSwap< +static_assert(!NoExceptMemberSwap< std::flat_multimap, ThrowOnMoveContainer, ThrowOnMoveContainer>>); #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..840f688795e5b --- /dev/null +++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.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 + +// + +// template R> +// void insert_range(sorted_equivalent_t, R&& rg); + +#include +#include +#include +#include +#include +#include + +#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 +concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward(r)); }; + +using Set = std::flat_multiset; + +static_assert(CanInsertRange>); +static_assert(CanInsertRange>); +static_assert(!CanInsertRange*>>); +static_assert(!CanInsertRange*>>); + +template +constexpr void test_one() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_multiset, KeyContainer>; + using It = forward_iterator; + 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); + 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, KeyContainer>; + using It = cpp20_input_iterator; + 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(ar + 6))}; + static_assert(!std::ranges::common_range); + 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, 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})); + } +} + +constexpr bool test() { + test_one>(); +#ifndef __cpp_lib_constexpr_deque + if (!TEST_IS_CONSTANT_EVALUATED) +#endif + test_one>(); + test_one>(); + test_one>>(); + { + // Items are forwarded correctly from the input range. + MoveOnly a[] = {1, 1, 3, 4, 5}; + std::flat_multiset 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)); + } + + return true; +} + +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(); +#if TEST_STD_VER >= 26 + static_assert(test()); +#endif + 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..4c6f55dd13fe8 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,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 // @@ -27,7 +24,6 @@ #include "test_macros.h" #include "../helpers.h" -#include "check_assertion.h" template void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { @@ -41,8 +37,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 241f2cf9e0a73..158520d36869c 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>); - +static_assert(NoExceptAdlSwap, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +static_assert(!NoExceptAdlSwap, ThrowOnMoveContainer>>); #endif template 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 7ad96ed340955..d5192fa742e81 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>); +static_assert(NoExceptMemberSwap, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +static_assert(!NoExceptMemberSwap, ThrowOnMoveContainer>>); #endif template 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 + +// + +// template R> +// void insert_range(sorted_unique_t, R&& rg); + +#include +#include +#include +#include +#include +#include + +#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 +concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward(r)); }; + +using Set = std::flat_set; + +static_assert(CanInsertRangeSortedUnique>); +static_assert(CanInsertRangeSortedUnique>); +static_assert(!CanInsertRangeSortedUnique*>>); +static_assert(!CanInsertRangeSortedUnique*>>); + +template +constexpr void test_one() { + using Key = typename KeyContainer::value_type; + + { + using M = std::flat_set, KeyContainer>; + using It = forward_iterator; + 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); + m.insert_range(std::sorted_unique, r); + assert((m == M{1, 2, 3, 4, 5, 8, 9, 10})); + } + { + using M = std::flat_set, KeyContainer>; + using It = cpp20_input_iterator; + M m = {8, 5, 3, 2}; + int ar[] = {9, 5, 4, 3, 1}; + std::ranges::subrange r = {It(ar), sentinel_wrapper(It(ar + 5))}; + static_assert(!std::ranges::common_range); + m.insert_range(std::sorted_unique, r); + assert((m == M{1, 2, 3, 4, 5, 8, 9})); + } + { + // was empty + using M = std::flat_set, 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>(); +#ifndef __cpp_lib_constexpr_deque + if (!TEST_IS_CONSTANT_EVALUATED) +#endif + test_one>(); + test_one>(); + test_one>>(); + { + // Items are forwarded correctly from the input range. + MoveOnly a[] = {1, 3, 4, 5}; + std::flat_set 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..eed92bcf4308f 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,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 // @@ -27,7 +24,6 @@ #include "test_macros.h" #include "../helpers.h" -#include "check_assertion.h" template void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) { @@ -41,8 +37,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>); - +static_assert(NoExceptAdlSwap, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptAdlSwap, ThrowOnMoveContainer>>); +static_assert(!NoExceptAdlSwap, ThrowOnMoveContainer>>); #endif template 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>); +static_assert(NoExceptMemberSwap, std::vector>>); #ifndef TEST_HAS_NO_EXCEPTIONS -static_assert(NoExceptMemberSwap, ThrowOnMoveContainer>>); +static_assert(!NoExceptMemberSwap, ThrowOnMoveContainer>>); #endif template diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp index 26c8e1bc7d66f..34820de6a53aa 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp @@ -67,8 +67,8 @@ # ifndef __cpp_lib_flat_map # error "__cpp_lib_flat_map should be defined in c++23" # endif -# if __cpp_lib_flat_map != 202207L -# error "__cpp_lib_flat_map should have the value 202207L in c++23" +# if __cpp_lib_flat_map != 202511L +# error "__cpp_lib_flat_map should have the value 202511L in c++23" # endif #elif TEST_STD_VER > 23 @@ -83,8 +83,8 @@ # ifndef __cpp_lib_flat_map # error "__cpp_lib_flat_map should be defined in c++26" # endif -# if __cpp_lib_flat_map != 202207L -# error "__cpp_lib_flat_map should have the value 202207L in c++26" +# if __cpp_lib_flat_map != 202511L +# error "__cpp_lib_flat_map should have the value 202511L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 65cdf2ded816d..28fae95c1c1f7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -5093,8 +5093,8 @@ # ifndef __cpp_lib_flat_map # error "__cpp_lib_flat_map should be defined in c++23" # endif -# if __cpp_lib_flat_map != 202207L -# error "__cpp_lib_flat_map should have the value 202207L in c++23" +# if __cpp_lib_flat_map != 202511L +# error "__cpp_lib_flat_map should have the value 202511L in c++23" # endif # ifndef __cpp_lib_flat_set @@ -6844,8 +6844,8 @@ # ifndef __cpp_lib_flat_map # error "__cpp_lib_flat_map should be defined in c++26" # endif -# if __cpp_lib_flat_map != 202207L -# error "__cpp_lib_flat_map should have the value 202207L in c++26" +# if __cpp_lib_flat_map != 202511L +# error "__cpp_lib_flat_map should have the value 202511L in c++26" # endif # ifndef __cpp_lib_flat_set diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index c91bdf4ed99ec..ff965aaa4ff89 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -557,7 +557,7 @@ def add_version_header(tc): }, { "name": "__cpp_lib_flat_map", - "values": {"c++23": 202207}, + "values": {"c++23": 202511}, "headers": ["flat_map"], }, {