From 90103cbc6d49bf908394509cfad4de5ab407f8b5 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Sat, 15 Nov 2025 11:21:47 +0100 Subject: [PATCH 1/2] P3567R2 flat_meow fixes --- source/containers.tex | 173 ++++++++++++++++++++++++++++++++++++------ source/support.tex | 4 +- 2 files changed, 152 insertions(+), 25 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 397520e4ad..146ab8db4b 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -17052,7 +17052,9 @@ \pnum If any member function in \ref{flat.map.defn} exits via an exception -the invariants are restored. +the invariants of the object argument are restored. +For the move constructor and move assignment operator, +the invariants of both arguments are restored. \begin{note} This can result in the \tcode{flat_map} being emptied. \end{note} @@ -17137,6 +17139,11 @@ // \ref{flat.map.cons}, constructors constexpr flat_map() : flat_map(key_compare()) { } + flat_map(const flat_map&); + flat_map(flat_map&&); + flat_map& operator=(const flat_map&); + flat_map& operator=(flat_map&&); + constexpr explicit flat_map(const key_compare& comp) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -17277,6 +17284,8 @@ constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_unique_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -17317,7 +17326,7 @@ template constexpr size_type erase(K&& x); constexpr iterator erase(const_iterator first, const_iterator last); - constexpr void swap(flat_map& y) noexcept; + constexpr void swap(flat_map& y) noexcept(@\seebelow@); constexpr void clear() noexcept; // observers @@ -17360,7 +17369,7 @@ friend constexpr @\exposid{synth-three-way-result}@ operator<=>(const flat_map& x, const flat_map& y); - friend constexpr void swap(flat_map& x, flat_map& y) noexcept + friend constexpr void swap(flat_map& x, flat_map& y) noexcept(noexcept(x.swap(y))) { x.swap(y); } private: @@ -17835,10 +17844,10 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -for (const auto& e : rg) { - @\exposid{c}@.keys.insert(@\exposid{c}@.keys.end(), e.first); - @\exposid{c}@.values.insert(@\exposid{c}@.values.end(), e.second); -} +ranges::for_each(rg, [&](value_type e) { + @\exposid{c}@.keys.insert(@\exposid{c}@.keys.end(), std::move(e.first)); + @\exposid{c}@.values.insert(@\exposid{c}@.values.end(), std::move(e.second)); +}); \end{codeblock} Then, sorts the range of newly inserted elements with respect to \tcode{value_comp()}; @@ -17864,6 +17873,22 @@ Since this operation performs an in-place merge, it may allocate memory. \end{itemdescr} +\indexlibrarymember{insert_range}{flat_map}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_unique_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert_range(rg)}. + +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. +\end{itemdescr} + \indexlibrarymember{try_emplace}{flat_map}% \begin{itemdecl} template @@ -18066,7 +18091,10 @@ \indexlibrarymember{swap}{flat_map}% \begin{itemdecl} -constexpr void swap(flat_map& y) noexcept; +constexpr void swap(flat_map& y) + noexcept(is_nothrow_swappable_v && + is_nothrow_swappable_v && + is_nothrow_swappable_v); \end{itemdecl} \begin{itemdescr} @@ -18228,7 +18256,9 @@ \pnum If any member function in \ref{flat.multimap.defn} exits via an exception, -the invariants are restored. +the invariants of the object argument are restored. +For the move constructor and move assignment operator, +the invariants of both arguments are restored. \begin{note} This can result in the \tcode{flat_multimap} being emptied. \end{note} @@ -18311,6 +18341,11 @@ // \ref{flat.multimap.cons}, constructors constexpr flat_multimap() : flat_multimap(key_compare()) { } + flat_multimap(const flat_multimap&); + flat_multimap(flat_multimap&&); + flat_multimap& operator=(const flat_multimap&); + flat_multimap& operator=(flat_multimap&&); + constexpr explicit flat_multimap(const key_compare& comp) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -18444,6 +18479,8 @@ constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_equivalent_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -18459,7 +18496,10 @@ template constexpr size_type erase(K&& x); constexpr iterator erase(const_iterator first, const_iterator last); - constexpr void swap(flat_multimap&) noexcept; + constexpr void swap(flat_multimap&) + noexcept(is_nothrow_swappable_v && + is_nothrow_swappable_v && + is_nothrow_swappable_v); constexpr void clear() noexcept; // observers @@ -18503,7 +18543,8 @@ friend constexpr @\exposid{synth-three-way-result}@ operator<=>(const flat_multimap& x, const flat_multimap& y); - friend constexpr void swap(flat_multimap& x, flat_multimap& y) noexcept + friend constexpr void swap(flat_multimap& x, flat_multimap& y) + noexcept(noexcept(x.swap(y))) { x.swap(y); } private: @@ -18871,7 +18912,9 @@ \pnum If any member function in \ref{flat.set.defn} exits via an exception, -the invariant is restored. +the invariant of the object argument is restored. +For the move constructor and move assignment operator, +the invariants of both arguments are restored. \begin{note} This can result in the \tcode{flat_set}'s being emptied. \end{note} @@ -18925,6 +18968,11 @@ // \ref{flat.set.cons}, constructors constexpr flat_set() : flat_set(key_compare()) { } + flat_set(const flat_set&); + flat_set(flat_set&&); + flat_set& operator=(const flat_set&); + flat_set& operator=(flat_set&&); + constexpr explicit flat_set(const key_compare& comp) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -19050,6 +19098,8 @@ constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_unique_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -19065,7 +19115,7 @@ template constexpr size_type erase(K&& x); constexpr iterator erase(const_iterator first, const_iterator last); - constexpr void swap(flat_set& y) noexcept; + constexpr void swap(flat_set& y) noexcept(@\seebelow@); constexpr void clear() noexcept; // observers @@ -19106,7 +19156,8 @@ friend constexpr @\exposid{synth-three-way-result}@ operator<=>(const flat_set& x, const flat_set& y); - friend constexpr void swap(flat_set& x, flat_set& y) noexcept { x.swap(y); } + friend constexpr void swap(flat_set& x, flat_set& y) noexcept(noexcept(x.swap(y))) + { x.swap(y); } private: container_type @\exposidnc{c}@; // \expos @@ -19378,9 +19429,9 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -for (const auto& e : rg) { - @\exposid{c}@.insert(@\exposid{c}@.end(), e); -} +ranges::for_each(rg, [&](auto&& e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +}); \end{codeblock} Then, sorts the range of newly inserted elements with respect to \exposid{compare}; @@ -19399,9 +19450,27 @@ Since this operation performs an in-place merge, it may allocate memory. \end{itemdescr} +\indexlibrarymember{insert_range}{flat_set}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_unique_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert_range(rg)}. + +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. +\end{itemdescr} + \indexlibrarymember{swap}{flat_set}% \begin{itemdecl} -constexpr void swap(flat_set& y) noexcept; +constexpr void swap(flat_set& y) + noexcept(is_nothrow_swappable_v && + is_nothrow_swappable_v); \end{itemdecl} \begin{itemdescr} @@ -19541,7 +19610,9 @@ \pnum If any member function in \ref{flat.multiset.defn} exits via an exception, -the invariant is restored. +the invariant of the object argument is restored. +For the move constructor and move assignment operator, +the invariants of both arguments are restored. \begin{note} This can result in the \tcode{flat_multiset}'s being emptied. \end{note} @@ -19594,6 +19665,11 @@ // \ref{flat.multiset.cons}, constructors constexpr flat_multiset() : flat_multiset(key_compare()) { } + flat_multiset(const flat_multiset&); + flat_multiset(flat_multiset&&); + flat_multiset& operator=(const flat_multiset&); + flat_multiset& operator=(flat_multiset&&); + constexpr explicit flat_multiset(const key_compare& comp) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -19721,6 +19797,8 @@ constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_equivalent_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -19736,7 +19814,7 @@ template constexpr size_type erase(K&& x); constexpr iterator erase(const_iterator first, const_iterator last); - constexpr void swap(flat_multiset& y) noexcept; + constexpr void swap(flat_multiset& y) noexcept(@\seebelow@); constexpr void clear() noexcept; // observers @@ -19777,7 +19855,8 @@ friend constexpr @\exposid{synth-three-way-result}@ operator<=>(const flat_multiset& x, const flat_multiset& y); - friend constexpr void swap(flat_multiset& x, flat_multiset& y) noexcept + friend constexpr void swap(flat_multiset& x, flat_multiset& y) + noexcept(noexcept(x.swap(y))) { x.swap(y); } private: @@ -20024,12 +20103,60 @@ \pnum \complexity -Linear. +Linear in $N$, where $N$ is \tcode{size()} after the operation. +\end{itemdescr} + +\indexlibrarymember{insert_range}{flat_multiset}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Adds elements to \exposid{c} as if by: +\begin{codeblock} +ranges::for_each(rg, [&](auto&& e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +}); +\end{codeblock} +Then, sorts the range of newly inserted elements with respect to \exposid{compare}, +and merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range. + +\pnum +\complexity +$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and $M$ +is \tcode{ranges::distance(rg)}. + +\pnum +\remarks +Since this operation performs an in-place merge, +it may allocate memory. +\end{itemdescr} + +\indexlibrarymember{insert_range}{flat_multiset}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(sorted_equivalent_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert_range(rg)}. + +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. \end{itemdescr} \indexlibrarymember{swap}{flat_multiset}% \begin{itemdecl} -constexpr void swap(flat_multiset& y) noexcept; +constexpr void swap(flat_multiset& y) + noexcept(is_nothrow_swappable_v && + is_nothrow_swappable_v); \end{itemdecl} \begin{itemdescr} diff --git a/source/support.tex b/source/support.tex index 568bc84b0b..94e88374f2 100644 --- a/source/support.tex +++ b/source/support.tex @@ -674,8 +674,8 @@ #define @\defnlibxname{cpp_lib_execution}@ 201902L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_expected}@ 202211L // also in \libheader{expected} #define @\defnlibxname{cpp_lib_filesystem}@ 201703L // also in \libheader{filesystem} -#define @\defnlibxname{cpp_lib_flat_map}@ 202207L // also in \libheader{flat_map} -#define @\defnlibxname{cpp_lib_flat_set}@ 202207L // also in \libheader{flat_set} +#define @\defnlibxname{cpp_lib_flat_map}@ 202511L // also in \libheader{flat_map} +#define @\defnlibxname{cpp_lib_flat_set}@ 202511L // also in \libheader{flat_set} #define @\defnlibxname{cpp_lib_format}@ 202311L // also in \libheader{format} #define @\defnlibxname{cpp_lib_format_path}@ 202506L // also in \libheader{filesystem} #define @\defnlibxname{cpp_lib_format_ranges}@ 202207L // also in \libheader{format} From 1e42c876fb46d837ae3153381c759b436569d30b Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Fri, 21 Nov 2025 17:02:07 +0100 Subject: [PATCH 2/2] [flat.{map,set,multimap,multiset}] Add constexpr to new member functions These functions are not marked constexpr in P3567R2, but the intent of the (already merged) P3372R3 is to mark all member functions constexpr. --- source/containers.tex | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 146ab8db4b..7c699c0201 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -17139,10 +17139,10 @@ // \ref{flat.map.cons}, constructors constexpr flat_map() : flat_map(key_compare()) { } - flat_map(const flat_map&); - flat_map(flat_map&&); - flat_map& operator=(const flat_map&); - flat_map& operator=(flat_map&&); + 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) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -17285,7 +17285,7 @@ template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_unique_t, R&& rg); + constexpr void insert_range(sorted_unique_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -17876,7 +17876,7 @@ \indexlibrarymember{insert_range}{flat_map}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_unique_t, R&& rg); + constexpr void insert_range(sorted_unique_t, R&& rg); \end{itemdecl} \begin{itemdescr} @@ -18341,10 +18341,10 @@ // \ref{flat.multimap.cons}, constructors constexpr flat_multimap() : flat_multimap(key_compare()) { } - flat_multimap(const flat_multimap&); - flat_multimap(flat_multimap&&); - flat_multimap& operator=(const flat_multimap&); - flat_multimap& operator=(flat_multimap&&); + 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) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -18480,7 +18480,7 @@ template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_equivalent_t, R&& rg); + constexpr void insert_range(sorted_equivalent_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -18968,10 +18968,10 @@ // \ref{flat.set.cons}, constructors constexpr flat_set() : flat_set(key_compare()) { } - flat_set(const flat_set&); - flat_set(flat_set&&); - flat_set& operator=(const flat_set&); - flat_set& operator=(flat_set&&); + 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) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -19099,7 +19099,7 @@ template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_unique_t, R&& rg); + constexpr void insert_range(sorted_unique_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -19453,7 +19453,7 @@ \indexlibrarymember{insert_range}{flat_set}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_unique_t, R&& rg); + constexpr void insert_range(sorted_unique_t, R&& rg); \end{itemdecl} \begin{itemdescr} @@ -19665,10 +19665,10 @@ // \ref{flat.multiset.cons}, constructors constexpr flat_multiset() : flat_multiset(key_compare()) { } - flat_multiset(const flat_multiset&); - flat_multiset(flat_multiset&&); - flat_multiset& operator=(const flat_multiset&); - flat_multiset& operator=(flat_multiset&&); + 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) : @\exposid{c}@(), @\exposid{compare}@(comp) { } @@ -19798,7 +19798,7 @@ template<@\exposconcept{container-compatible-range}@ R> constexpr void insert_range(R&& rg); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_equivalent_t, R&& rg); + constexpr void insert_range(sorted_equivalent_t, R&& rg); constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } @@ -20139,7 +20139,7 @@ \indexlibrarymember{insert_range}{flat_multiset}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - void insert_range(sorted_equivalent_t, R&& rg); + constexpr void insert_range(sorted_equivalent_t, R&& rg); \end{itemdecl} \begin{itemdescr}