[libc++] Implement P3567R2 flat_meow fixes (#162022)

Fixes #171272

---------

Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
This commit is contained in:
Hui 2025-12-20 21:18:44 +00:00 committed by GitHub
parent 611a271e8d
commit cd13170aea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1833 additions and 112 deletions

View File

@ -334,7 +334,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_expected`` ``202211L``
---------------------------------------------------------- -----------------
``__cpp_lib_flat_map`` ``202207L``
``__cpp_lib_flat_map`` ``202511L``
---------------------------------------------------------- -----------------
``__cpp_lib_flat_set`` ``202207L``
---------------------------------------------------------- -----------------

View File

@ -51,6 +51,7 @@ Implemented Papers
- P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
- P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
Improvements and New Features
-----------------------------

View File

@ -159,7 +159,7 @@
"","","","","","",""
"`P3920R0 <https://wg21.link/P3920R0>`__","Wording for NB comment resolution on trivial relocation","2025-11 (Kona)","","","`#171269 <https://github.com/llvm/llvm-project/issues/171269>`__",""
"`P3016R6 <https://wg21.link/P3016R6>`__","Resolve inconsistencies in begin/end for ``valarray`` and braced initializer lists","2025-11 (Kona)","","","`#171271 <https://github.com/llvm/llvm-project/issues/171271>`__",""
"`P3567R2 <https://wg21.link/P3567R2>`__","``flat_meow`` Fixes","2025-11 (Kona)","","","`#171272 <https://github.com/llvm/llvm-project/issues/171272>`__",""
"`P3567R2 <https://wg21.link/P3567R2>`__","``flat_meow`` Fixes","2025-11 (Kona)","|Complete|","22","`#171272 <https://github.com/llvm/llvm-project/issues/171272>`__",""
"`P3663R3 <https://wg21.link/P3663R3>`__","Future-proof ``submdspan_mapping``","2025-11 (Kona)","","","`#166089 <https://github.com/llvm/llvm-project/issues/166089>`__",""
"`P3914R0 <https://wg21.link/P3914R0>`__","Assorted NB comment resolutions for Kona 2025","2025-11 (Kona)","","","`#171274 <https://github.com/llvm/llvm-project/issues/171274>`__",""
"`P3836R2 <https://wg21.link/P3836R2>`__","Make ``optional<T&>`` trivially copyable","2025-11 (Kona)","","","`#171275 <https://github.com/llvm/llvm-project/issues/171275>`__",""

1 Paper # Paper Name Meeting Status First released version GitHub issue Notes
159
160 `P3920R0 <https://wg21.link/P3920R0>`__ Wording for NB comment resolution on trivial relocation 2025-11 (Kona) `#171269 <https://github.com/llvm/llvm-project/issues/171269>`__
161 `P3016R6 <https://wg21.link/P3016R6>`__ Resolve inconsistencies in begin/end for ``valarray`` and braced initializer lists 2025-11 (Kona) `#171271 <https://github.com/llvm/llvm-project/issues/171271>`__
162 `P3567R2 <https://wg21.link/P3567R2>`__ ``flat_meow`` Fixes 2025-11 (Kona) |Complete| 22 `#171272 <https://github.com/llvm/llvm-project/issues/171272>`__
163 `P3663R3 <https://wg21.link/P3663R3>`__ Future-proof ``submdspan_mapping`` 2025-11 (Kona) `#166089 <https://github.com/llvm/llvm-project/issues/166089>`__
164 `P3914R0 <https://wg21.link/P3914R0>`__ Assorted NB comment resolutions for Kona 2025 2025-11 (Kona) `#171274 <https://github.com/llvm/llvm-project/issues/171274>`__
165 `P3836R2 <https://wg21.link/P3836R2>`__ Make ``optional<T&>`` trivially copyable 2025-11 (Kona) `#171275 <https://github.com/llvm/llvm-project/issues/171275>`__

View File

@ -592,6 +592,15 @@ public:
__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());
}
@ -741,14 +750,17 @@ public:
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 {
@ -886,7 +898,8 @@ public:
__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);
}

View File

@ -573,6 +573,15 @@ public:
__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());
}
@ -633,13 +642,17 @@ public:
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 {
@ -781,7 +794,7 @@ public:
}
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);
}

View File

@ -449,6 +449,15 @@ public:
__append_sort_merge</*WasSorted = */ false>(std::forward<_Range>(__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>(std::forward<_Range>(__range));
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
insert(__il.begin(), __il.end());
}
@ -505,13 +514,15 @@ public:
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<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(); }
@ -646,7 +657,7 @@ public:
}
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 @@ private:
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();

View File

@ -466,6 +466,15 @@ public:
__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());
}
@ -524,13 +533,15 @@ public:
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(); }
@ -661,7 +672,8 @@ public:
__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);
}

View File

@ -17,18 +17,359 @@
#include <initializer_list> // see [initializer.list.syn]
namespace std {
// [flat.map], class template flat_map
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_map;
struct sorted_unique_t { explicit sorted_unique_t() = default; };
inline constexpr sorted_unique_t sorted_unique{};
// [flat.map], class template flat_map
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_map {
public:
// types
using key_type = Key;
using mapped_type = T;
using value_type = pair<key_type, mapped_type>;
using key_compare = Compare;
using reference = pair<const key_type&, mapped_type&>;
using const_reference = pair<const key_type&, const mapped_type&>;
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using key_container_type = KeyContainer;
using mapped_container_type = MappedContainer;
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<class InputIterator>
constexpr flat_map(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp) { insert(first, last); }
template<class InputIterator>
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<container-compatible-range<value_type> R>
constexpr flat_map(from_range_t, R&& rg)
: flat_map(from_range, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_map(from_range_t, R&& rg, const key_compare& comp)
: flat_map(comp) { insert_range(std::forward<R>(rg)); }
constexpr flat_map(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_map(il.begin(), il.end(), comp) { }
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_map(sorted_unique, il.begin(), il.end(), comp) { }
// [flat.map.cons.alloc], constructors with allocators
template<class Alloc>
constexpr explicit flat_map(const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_container_type& key_cont,
const mapped_container_type& mapped_cont,
const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_container_type& key_cont,
const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
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<class Alloc>
constexpr flat_map(const flat_map&, const Alloc& a);
template<class Alloc>
constexpr flat_map(flat_map&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_map& operator=(initializer_list<value_type>);
// 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<class K> 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<class K> constexpr mapped_type& at(const K& x);
template<class K> constexpr const mapped_type& at(const K& x) const;
// [flat.map.modifiers], modifiers
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& x)
{ return emplace(x); }
constexpr pair<iterator, bool> 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<class P> constexpr pair<iterator, bool> insert(P&& x);
template<class P>
constexpr iterator insert(const_iterator position, P&&);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
template<container-compatible-range<value_type> R>
constexpr void insert_range(sorted_unique_t, R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_unique_t, initializer_list<value_type> 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<class... Args>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class K, class M>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
template<class K, class M>
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<class K> 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<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> 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<class K> constexpr iterator lower_bound(const K& x);
template<class K> 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<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K> constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
friend constexpr bool operator==(const flat_map& x, const flat_map& y);
friend constexpr synth-three-way-result<value_type>
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<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_map(KeyContainer, MappedContainer, Compare = Compare())
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_map(KeyContainer, MappedContainer, Allocator)
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_map(KeyContainer, MappedContainer, Compare, Allocator)
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare())
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator)
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator)
-> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_map(InputIterator, InputIterator, Compare = Compare())
-> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())
-> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
template<ranges::input_range R, class Compare = less<range-key-type<R>>,
class Allocator = allocator<byte>>
flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_map<range-key-type<R>, range-mapped-type<R>, Compare,
vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>,
vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>;
template<ranges::input_range R, class Allocator>
flat_map(from_range_t, R&&, Allocator)
-> flat_map<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>,
vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>,
vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>;
template<class Key, class T, class Compare = less<Key>>
flat_map(initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_map<Key, T, Compare>;
template<class Key, class T, class Compare = less<Key>>
flat_map(sorted_unique_t, initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_map<Key, T, Compare>;
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
class Allocator>
struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>,
Allocator>;
class Allocator>
struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>, Allocator>
: bool_constant<uses_allocator_v<KeyContainer, Allocator> &&
uses_allocator_v<MappedContainer, Allocator>> { };
// [flat.map.erasure], erasure for flat_map
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
@ -36,18 +377,329 @@ namespace std {
typename flat_map<Key, T, Compare, KeyContainer, MappedContainer>::size_type
erase_if(flat_map<Key, T, Compare, KeyContainer, MappedContainer>& c, Predicate pred);
// [flat.multimap], class template flat_multimap
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_multimap;
struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
inline constexpr sorted_equivalent_t sorted_equivalent{};
// [flat.multimap], class template flat_multimap
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_multimap {
public:
// types
using key_type = Key;
using mapped_type = T;
using value_type = pair<key_type, mapped_type>;
using key_compare = Compare;
using reference = pair<const key_type&, mapped_type&>;
using const_reference = pair<const key_type&, const mapped_type&>;
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using key_container_type = KeyContainer;
using mapped_container_type = MappedContainer;
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<class InputIterator>
constexpr flat_multimap(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
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<container-compatible-range<value_type> R>
constexpr flat_multimap(from_range_t, R&& rg)
: flat_multimap(from_range, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp)
: flat_multimap(comp) { insert_range(std::forward<R>(rg)); }
constexpr flat_multimap(initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multimap(il.begin(), il.end(), comp) { }
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multimap(sorted_equivalent, il.begin(), il.end(), comp) { }
// [flat.multimap.cons.alloc], constructors with allocators
template<class Alloc>
constexpr explicit flat_multimap(const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_container_type& key_cont,
const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
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<class Alloc>
constexpr flat_multimap(const flat_multimap&, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(flat_multimap&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
flat_multimap& operator=(initializer_list<value_type>);
// 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<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args>
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<class P> constexpr iterator insert(P&& x);
template<class P>
constexpr iterator insert(const_iterator position, P&&);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
template<container-compatible-range<value_type> R>
constexpr void insert_range(sorted_equivalent_t, R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_equivalent_t, initializer_list<value_type> 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<class K> 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<key_container_type> &&
is_nothrow_swappable_v<mapped_container_type> &&
is_nothrow_swappable_v<key_compare>);
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<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> 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<class K> constexpr iterator lower_bound(const K& x);
template<class K> 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<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
friend constexpr bool operator==(const flat_multimap& x, const flat_multimap& y);
friend constexpr synth-three-way-result<value_type>
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<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_multimap(KeyContainer, MappedContainer, Compare = Compare())
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_multimap(KeyContainer, MappedContainer, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_multimap(KeyContainer, MappedContainer, Compare, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare())
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_multimap(InputIterator, InputIterator, Compare = Compare())
-> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
-> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
template<ranges::input_range R, class Compare = less<range-key-type<R>>,
class Allocator = allocator<byte>>
flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_multimap<range-key-type<R>, range-mapped-type<R>, Compare,
vector<range-key-type<R>,
alloc-rebind<Allocator, range-key-type<R>>>,
vector<range-mapped-type<R>,
alloc-rebind<Allocator, range-mapped-type<R>>>>;
template<ranges::input_range R, class Allocator>
flat_multimap(from_range_t, R&&, Allocator)
-> flat_multimap<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>,
vector<range-key-type<R>,
alloc-rebind<Allocator, range-key-type<R>>>,
vector<range-mapped-type<R>,
alloc-rebind<Allocator, range-mapped-type<R>>>>;
template<class Key, class T, class Compare = less<Key>>
flat_multimap(initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_multimap<Key, T, Compare>;
template<class Key, class T, class Compare = less<Key>>
flat_multimap(sorted_equivalent_t, initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_multimap<Key, T, Compare>;
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
class Allocator>
class Allocator>
struct uses_allocator<flat_multimap<Key, T, Compare, KeyContainer, MappedContainer>,
Allocator>;
Allocator>
: bool_constant<uses_allocator_v<KeyContainer, Allocator> &&
uses_allocator_v<MappedContainer, Allocator>> { };
// [flat.multimap.erasure], erasure for flat_multimap
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,

View File

@ -17,30 +17,565 @@
#include <initializer_list> // see [initializer.list.syn]
namespace std {
// [flat.set], class template flat_set
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_set;
struct sorted_unique_t { explicit sorted_unique_t() = default; };
inline constexpr sorted_unique_t sorted_unique{};
// [flat.set], class template flat_set
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using container_type = KeyContainer;
// [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<class InputIterator>
constexpr flat_set(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(first, last), compare(comp) { }
template<container-compatible-range<value_type> R>
constexpr flat_set(from_range_t, R&& rg)
: flat_set(from_range, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_set(from_range_t, R&& rg, const key_compare& comp)
: flat_set(comp)
{ insert_range(std::forward<R>(rg)); }
constexpr flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_set(il.begin(), il.end(), comp) { }
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_set(sorted_unique, il.begin(), il.end(), comp) { }
// [flat.set.cons.alloc], constructors with allocators
template<class Alloc>
constexpr explicit flat_set(const Alloc& a);
template<class Alloc>
constexpr flat_set(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, const container_type& cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(const flat_set&, const Alloc& a);
template<class Alloc>
constexpr flat_set(flat_set&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_set& operator=(initializer_list<value_type>);
// 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<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& x)
{ return emplace(x); }
constexpr pair<iterator, bool> insert(value_type&& x)
{ return emplace(std::move(x)); }
template<class K> constexpr pair<iterator, bool> 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<class K> constexpr iterator insert(const_iterator hint, K&& x);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
template<container-compatible-range<value_type> R>
constexpr void insert_range(sorted_unique_t, R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_unique_t, initializer_list<value_type> 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<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> 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<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> 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<class K> constexpr iterator lower_bound(const K& x);
template<class K> 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<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
friend constexpr bool operator==(const flat_set& x, const flat_set& y);
friend constexpr synth-three-way-result<value_type>
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<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_set(KeyContainer, Compare = Compare())
-> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_set(KeyContainer, Allocator)
-> flat_set<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_set(KeyContainer, Compare, Allocator)
-> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_set(sorted_unique_t, KeyContainer, Compare = Compare())
-> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_set(sorted_unique_t, KeyContainer, Allocator)
-> flat_set<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_set(sorted_unique_t, KeyContainer, Compare, Allocator)
-> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_set(InputIterator, InputIterator, Compare = Compare())
-> flat_set<iter-value-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())
-> flat_set<iter-value-type<InputIterator>, Compare>;
template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_set<ranges::range_value_t<R>, Compare,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<ranges::input_range R, class Allocator>
flat_set(from_range_t, R&&, Allocator)
-> flat_set<ranges::range_value_t<R>, less<ranges::range_value_t<R>>,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<class Key, class Compare = less<Key>>
flat_set(initializer_list<Key>, Compare = Compare())
-> flat_set<Key, Compare>;
template<class Key, class Compare = less<Key>>
flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare())
-> flat_set<Key, Compare>;
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>;
struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>
: bool_constant<uses_allocator_v<KeyContainer, Allocator>> { };
// [flat.set.erasure], erasure for flat_set
template<class Key, class Compare, class KeyContainer, class Predicate>
typename flat_set<Key, Compare, KeyContainer>::size_type
erase_if(flat_set<Key, Compare, KeyContainer>& c, Predicate pred);
// [flat.multiset], class template flat_multiset
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_multiset;
struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
inline constexpr sorted_equivalent_t sorted_equivalent{};
// [flat.multiset], class template flat_multiset
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using container_type = KeyContainer;
// [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<class InputIterator>
constexpr flat_multiset(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(first, last), compare(comp) { }
template<container-compatible-range<value_type> R>
constexpr flat_multiset(from_range_t, R&& rg)
: flat_multiset(from_range, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp)
: flat_multiset(comp)
{ insert_range(std::forward<R>(rg)); }
constexpr flat_multiset(initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multiset(il.begin(), il.end(), comp) { }
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multiset(sorted_equivalent, il.begin(), il.end(), comp) { }
// [flat.multiset.cons.alloc], constructors with allocators
template<class Alloc>
constexpr explicit flat_multiset(const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const container_type& cont, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, const container_type& cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const flat_multiset&, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(flat_multiset&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_multiset& operator=(initializer_list<value_type>);
// 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<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args>
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<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
template<container-compatible-range<value_type> R>
constexpr void insert_range(sorted_equivalent_t, R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_equivalent_t, initializer_list<value_type> 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<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> 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<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> 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<class K> constexpr iterator lower_bound(const K& x);
template<class K> 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<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
friend constexpr bool operator==(const flat_multiset& x, const flat_multiset& y);
friend constexpr synth-three-way-result<value_type>
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<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_multiset(KeyContainer, Compare = Compare())
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_multiset(KeyContainer, Allocator)
-> flat_multiset<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_multiset(KeyContainer, Compare, Allocator)
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare())
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_multiset(sorted_equivalent_t, KeyContainer, Allocator)
-> flat_multiset<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator)
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_multiset(InputIterator, InputIterator, Compare = Compare())
-> flat_multiset<iter-value-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
-> flat_multiset<iter-value-type<InputIterator>, Compare>;
template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_multiset<ranges::range_value_t<R>, Compare,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<ranges::input_range R, class Allocator>
flat_multiset(from_range_t, R&&, Allocator)
-> flat_multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<class Key, class Compare = less<Key>>
flat_multiset(initializer_list<Key>, Compare = Compare())
-> flat_multiset<Key, Compare>;
template<class Key, class Compare = less<Key>>
flat_multiset(sorted_equivalent_t, initializer_list<Key>, Compare = Compare())
-> flat_multiset<Key, Compare>;
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>;
struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>
: bool_constant<uses_allocator_v<KeyContainer, Allocator>> { };
// [flat.multiset.erasure], erasure for flat_multiset
template<class Key, class Compare, class KeyContainer, class Predicate>

View File

@ -111,7 +111,7 @@ __cpp_lib_execution 201902L <execution>
201603L // C++17
__cpp_lib_expected 202211L <expected>
__cpp_lib_filesystem 201703L <filesystem>
__cpp_lib_flat_map 202207L <flat_map>
__cpp_lib_flat_map 202511L <flat_map>
__cpp_lib_flat_set 202207L <flat_set>
__cpp_lib_format 202110L <format>
__cpp_lib_format_path 202403L <filesystem>
@ -498,7 +498,7 @@ __cpp_lib_void_t 201411L <type_traits>
# 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

View File

@ -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;
}

View File

@ -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 invariants are maintained if any exception is thrown during swap
#include <flat_map>
#include <cassert>
@ -27,7 +24,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) {
@ -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);
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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>
@ -29,7 +26,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) {
@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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_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>
constexpr 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}));
}
}
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, 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));
}
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;
}

View File

@ -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_set>
@ -27,7 +24,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) {
@ -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);
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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_set>
@ -27,7 +24,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) {
@ -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);
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -557,7 +557,7 @@ feature_test_macros = [
},
{
"name": "__cpp_lib_flat_map",
"values": {"c++23": 202207},
"values": {"c++23": 202511},
"headers": ["flat_map"],
},
{