diff --git a/source/containers.tex b/source/containers.tex index 380ddb2931..1f6f132a61 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26,11 +26,11 @@ \ref{unord} & Unordered associative containers & \tcode{}, \tcode{} \\ \rowsep \ref{container.adaptors} & Container adaptors & - \tcode{}, \tcode{} \\ \rowsep -\ref{views} & Views & \tcode{}, \tcode{} \\ + \tcode{}, \tcode{}, \tcode{} \\ \rowsep +\ref{views} & Views & + \tcode{}, \tcode{} \\ \end{libsumtab} - \rSec1[container.requirements]{Requirements}% \indextext{requirements!container} @@ -1237,8 +1237,8 @@ \tcode{vector}, \tcode{forward_list}, \tcode{list}, and \tcode{deque}. In addition, \tcode{array} is provided as a sequence container which provides limited sequence operations because it has a fixed number of elements. The library also provides container adaptors that -make it easy to construct abstract data types, such as \tcode{stack}s or \tcode{queue}s, out of -the basic sequence container kinds (or out of other kinds of sequence containers that the user defines). +make it easy to construct abstract data types, such as \tcode{stack}s, \tcode{queue}s, \tcode{flat_map}s, or \tcode{flat_multimap}s, out of +the basic sequence container kinds (or out of other program-defined sequence containers). \pnum \begin{note} @@ -2518,6 +2518,11 @@ \tcode{map} and \tcode{multimap}. +The library also provides container adaptors +that make it easy to construct abstract data types, +such as \tcode{flat_map}s or \tcode{flat_multimap}s, +out of the basic sequence container kinds +(or out of other program-defined sequence containers). \pnum Each associative container is parameterized on @@ -12962,21 +12967,32 @@ \rSec2[container.adaptors.general]{In general} \pnum -The headers \libheader{queue} and \libheader{stack} define the container adaptors -\tcode{queue}, \tcode{priority_queue}, and \tcode{stack}. +The headers \libheader{queue}, \libheader{stack}, and \libheader{flat_map} define the container adaptors +\tcode{queue}, \tcode{priority_queue}, \tcode{stack}, and \tcode{flat_map}, respectively. \pnum -The container adaptors each take a \tcode{Container} template parameter, and each constructor takes -a \tcode{Container} reference argument. This container is copied into the \tcode{Container} member -of each adaptor. If the container takes an allocator, then a compatible allocator may be passed in +Each container adaptor takes +one or more template parameters +named \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} +that denote the types of containers that the container adaptor adapts. +Each container adaptor has at least one constructor +that takes a reference argument to one or more such template parameters. +For each constructor reference argument to a container \tcode{C}, +the constructor copies the container into the container adaptor. +If \tcode{C} takes an allocator, then a compatible allocator may be passed in to the adaptor's constructor. Otherwise, normal copy or move construction is used for the container argument. -The first template parameter \tcode{T} of the container adaptors +For the container adaptors +that take a single container template parameter \tcode{Container}, +the first template parameter \tcode{T} of the container adaptor shall denote the same type as \tcode{Container::value_type}. \pnum For container adaptors, no \tcode{swap} function throws an exception unless that -exception is thrown by the swap of the adaptor's \tcode{Container} or +exception is thrown by the swap of the adaptor's +\tcode{Container}, +\tcode{KeyContainer}, +\tcode{MappedContainer}, or \tcode{Compare} object (if any). \pnum @@ -12985,21 +13001,51 @@ if it has an \tcode{InputIterator} template parameter and a type that does not qualify as an input iterator is deduced for that parameter. +\pnum +For container adaptors that have them, +the \tcode{insert}, \tcode{emplace}, and \tcode{erase} members +affect the validity of iterators, references, and pointers +to the adaptor's container(s) in the same way that +the containers' respective +\tcode{insert}, \tcode{emplace}, and \tcode{erase} members do. +\begin{example} +A call to \tcode{flat_map::insert} +can invalidate all iterators to the \tcode{flat_map}. +\end{example} + \pnum A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true: \begin{itemize} \item It has an \tcode{InputIterator} template parameter and a type that does not qualify as an input iterator is deduced for that parameter. \item It has a \tcode{Compare} template parameter and a type that qualifies as an allocator is deduced for that parameter. -\item It has a \tcode{Container} template parameter and a type that qualifies as an allocator is deduced for that parameter. -\item It has no \tcode{Container} template parameter, and it has an \tcode{Allocator} template parameter, and a type that does not qualify as an allocator is deduced for that parameter. +\item It has a \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} template parameter and a type that qualifies as an allocator is deduced for that parameter. +\item It has no \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} template parameter, and it has an \tcode{Allocator} template parameter, and a type that does not qualify as an allocator is deduced for that parameter. \item It has both \tcode{Container} and \tcode{Allocator} template parameters, and \tcode{uses_allocator_v} is \tcode{false}. +\item It has both \tcode{KeyContainer} and \tcode{Allocator} template parameters, and +\tcode{uses_allocator_v} is \tcode{false}. +\item It has both \tcode{MappedContainer} and \tcode{Allocator} template parameters, and +\tcode{uses_allocator_v} is \tcode{false}. \end{itemize} \pnum The exposition-only alias template \exposid{iter-value-type} -defined in \ref{sequences.general} +defined in \ref{sequences.general} and +the exposition-only alias templates \exposid{iter-key-type} and \exposid{iter-mapped-type} +defined in \ref{associative.general} may appear in deduction guides for container adaptors. +\pnum +The following exposition-only alias templates may appear in deduction guides +for container adaptors: +\begin{codeblock} +template + using @\exposid{cont-key-type}@ = // \expos + remove_const_t; +template + using @\exposid{cont-mapped-type}@ = // \expos + typename Container::value_type::second_type; +\end{codeblock} + \rSec2[queue.syn]{Header \tcode{} synopsis} \indexheader{queue} @@ -13076,6 +13122,50 @@ } \end{codeblock} +\rSec2[flat.map.syn]{Header \tcode{} synopsis} + +\indexheader{flat_map}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + + // \ref{flat.map}, class template \tcode{flat_map} + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_map; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + size_t erase_if(flat_map& c, Predicate pred); + + template + struct uses_allocator, + Allocator>; + + // \ref{flat.multimap}, class template \tcode{flat_multimap} + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_multimap; + + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + + template + size_t erase_if(flat_multimap& c, + Predicate pred); + + template + struct uses_allocator, + Allocator>; +} +\end{codeblock} + \rSec2[queue]{Class template \tcode{queue}} \rSec3[queue.defn]{Definition} @@ -14296,6 +14386,1707 @@ As if by \tcode{x.swap(y)}. \end{itemdescr} +\rSec2[flat.map]{Class template \tcode{flat_map}} + +\rSec3[flat.map.overview]{Overview} + +\pnum +\indexlibraryglobal{flatmap}% +A \tcode{flat_map} is a container adaptor +that provides an associative container interface +that supports unique keys +(i.e., contains at most one of each key value) and +provides for fast retrieval of values of another type \tcode{T} +based on the keys. +\tcode{flat_map} supports iterators +that meet the \oldconcept{InputIterator} requirements and +model the +\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. + +\pnum +A \tcode{flat_map} meets all of the requirements +of a container\iref{container.reqmts} and +of a reversible container\iref{container.rev.reqmts}, +plus the optional container requirements\iref{container.opt.reqmts}. +\tcode{flat_map} meets the requirements of +an associative container\iref{associative.reqmts}, +except that: +\begin{itemize} +\item +it does not meet the requirements related to node handles\iref{container.node}, +\item +it does not meet the requirements related to iterator invalidation, and +\item +the time complexity of the operations that insert or erase a single +element from the map is linear, including the ones that take an insertion +position iterator. +\end{itemize} +\begin{note} +A \tcode{flat_map} does not meet the additional requirements of +an allocator-aware container\iref{container.alloc.reqmts}. +\end{note} + +\pnum +A \tcode{flat_map} also provides most operations +described in \ref{associative.reqmts} for unique keys. +This means that a \tcode{flat_map} supports +the \tcode{a_uniq} operations in \ref{associative.reqmts}, +but not the \tcode{a_eq} operations. +For a \tcode{flat_map} +the \tcode{key_type} is \tcode{Key} and +the \tcode{value_type} is \tcode{pair}. + +\pnum +Descriptions are provided here only for operations on \tcode{flat_map} that +are not described in one of those sets of requirements or for operations where +there is additional semantic information. + +\pnum +A \tcode{flat_map} maintains the following invariants: +\begin{itemize} +\item +it contains the same number of keys and values; +\item +the keys are sorted with respect to the comparison object; and +\item +the value at offset \tcode{off} within the value container is +the value associated with the key at offset \tcode{off} +within the key container. +\end{itemize} + +\pnum +If any member function in \ref{flat.map.defn} exits via an exception +the invariants are restored. +\begin{note} +This can result in the \tcode{flat_map} being emptied. +\end{note} + +\pnum +Any sequence container\iref{sequence.reqmts} \tcode{C} +supporting \oldconcept{RandomAccessIterator} can be used +to instantiate \tcode{flat_map}, +as long as invocations of +member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. +In particular, \tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} +can be used. +\begin{note} +\tcode{vector} is not a sequence container. +\end{note} + +\pnum +The program is ill-formed if +\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or +\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. + +\pnum +The effect of calling a constructor +that takes +both \tcode{key_container_type} and \tcode{mapped_container_type} arguments with +containers of different sizes is undefined. + +\pnum +The effect of calling a constructor or member function +that takes a \tcode{sorted_unique_t} argument with +a container, containers, or range +that is not sorted with respect to \tcode{key_comp()}, or +that contains equal elements, +is undefined. + +\rSec3[flat.map.defn]{Definition} + +\begin{codeblock} +namespace std { + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = @\impdefx{type of \tcode{flat_map::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_map::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; + + class value_compare { + private: + key_compare comp; // \expos + value_compare(key_compare c) : comp(c) { } // \expos + public: + 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; + }; + + // \ref{flat.map.cons}, construct/copy/destroy + flat_map() : flat_map(key_compare()) { } + + flat_map(key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); + + flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); + + explicit flat_map(const key_compare& comp) + : c(), compare(comp) { } + template + flat_map(const key_compare& comp, const Allocator& a); + template + explicit flat_map(const Allocator& a); + + template + flat_map(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(first, last); } + template + flat_map(InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); + template + flat_map(InputIterator first, InputIterator last, const Allocator& a); + + template<@\exposconcept{container-compatible-range}@ R> + flat_map(from_range_t fr, R&& rg) + : flat_map(fr, std::forward(rg), key_compare()) { } + template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_map(from_range_t, R&& rg, const Allocator& a); + template<@\exposconcept{container-compatible-range}@ R> + flat_map(from_range_t, R&& rg, const key_compare& comp) + : flat_map(comp) { insert_range(std::forward(rg)); } + template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); + + template + flat_map(sorted_unique_t s, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(s, first, last); } + template + flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); + template + flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); + + flat_map(initializer_list il, const key_compare& comp = key_compare()) + : flat_map(il.begin(), il.end(), comp) { } + template + flat_map(initializer_list il, const key_compare& comp, const Allocator& a); + template + flat_map(initializer_list il, const Allocator& a); + + flat_map(sorted_unique_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_map(s, il.begin(), il.end(), comp) { } + template + flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp, const Allocator& a); + template + flat_map(sorted_unique_t, initializer_list il, const Allocator& a); + + flat_map& operator=(initializer_list il); + + // iterators + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + reverse_iterator rbegin() noexcept; + const_reverse_iterator rbegin() const noexcept; + reverse_iterator rend() noexcept; + const_reverse_iterator rend() const noexcept; + + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + // \ref{flat.map.capacity}, capacity + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + // \ref{flat.map.access}, element access + mapped_type& operator[](const key_type& x); + mapped_type& operator[](key_type&& x); + template mapped_type& operator[](K&& x); + mapped_type& at(const key_type& x); + const mapped_type& at(const key_type& x) const; + template mapped_type& at(const K& x); + template const mapped_type& at(const K& x) const; + + // \ref{flat.map.modifiers}, modifiers + template pair emplace(Args&&... args); + template + iterator emplace_hint(const_iterator position, Args&&... args); + + pair insert(const value_type& x) + { return emplace(x); } + pair insert(value_type&& x) + { return emplace(std::move(x)); } + iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template pair insert(P&& x); + template + iterator insert(const_iterator position, P&&); + template + void insert(InputIterator first, InputIterator last); + template + void insert(sorted_unique_t, InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(R&& rg); + + void insert(initializer_list il) + { insert(il.begin(), il.end()); } + void insert(sorted_unique_t s, initializer_list il) + { insert(s, il.begin(), il.end()); } + + containers extract() &&; + void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + template + pair try_emplace(const key_type& k, Args&&... args); + template + pair try_emplace(key_type&& k, Args&&... args); + template + pair try_emplace(K&& k, Args&&... args); + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + template + pair insert_or_assign(const key_type& k, M&& obj); + template + pair insert_or_assign(key_type&& k, M&& obj); + template + pair insert_or_assign(K&& k, M&& obj); + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + + iterator erase(iterator position); + iterator erase(const_iterator position); + size_type erase(const key_type& x); + template size_type erase(K&& x); + iterator erase(const_iterator first, const_iterator last); + + void swap(flat_map& y) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + value_compare value_comp() const; + + const key_container_type& keys() const noexcept { return c.keys; } + const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + iterator find(const key_type& x); + const_iterator find(const key_type& x) const; + template iterator find(const K& x); + template const_iterator find(const K& x) const; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template bool contains(const K& x) const; + + iterator lower_bound(const key_type& x); + const_iterator lower_bound(const key_type& x) const; + template iterator lower_bound(const K& x); + template const_iterator lower_bound(const K& x) const; + + iterator upper_bound(const key_type& x); + const_iterator upper_bound(const key_type& x) const; + template iterator upper_bound(const K& x); + template const_iterator upper_bound(const K& x) const; + + pair equal_range(const key_type& x); + pair equal_range(const key_type& x) const; + template pair equal_range(const K& x); + template pair equal_range(const K& x) const; + + friend bool operator==(const flat_map& x, const flat_map& y); + + friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_map& x, const flat_map& y); + + friend void swap(flat_map& x, flat_map& y) noexcept + { x.swap(y); } + + private: + containers c; // \expos + key_compare compare; // \expos + + struct key_equiv { // \expos + key_equiv(key_compare c) : comp(c) { } + bool operator()(const_reference x, const_reference y) const { + return !comp(x.first, y.first) && !comp(y.first, x.first); + } + key_compare comp; + }; + }; + + template + flat_map(KeyContainer, MappedContainer) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + + template>> + flat_map(InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>> + flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>, + class Allocator> + flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare>; + + template + flat_map(from_range_t, R&&, Allocator) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@>; + + template> + flat_map(initializer_list>, Compare = Compare()) + -> flat_map; + + template> + flat_map(sorted_unique_t, initializer_list>, Compare = Compare()) + -> flat_map; + + template + struct uses_allocator, Allocator> + : bool_constant && + uses_allocator_v> { }; +} +\end{codeblock} + +\pnum +The member type \tcode{containers} has the data members and special members +specified above. +It has no base classes or members other than those specified. + +\rSec3[flat.map.cons]{Constructors} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +flat_map(key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}; +sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = ranges::zip_view(c.keys, c.values); +auto it = ranges::unique(zv, key_equiv(compare)).begin(); +auto dist = distance(zv.begin(), it); +c.keys.erase(c.keys.begin() + dist, c.keys.end()); +c.values.erase(c.values.begin() + dist, c.values.end()); +\end{codeblock} + +\pnum +\complexity +Linear in $N$ if the container arguments are already sorted with respect +to \tcode{value_comp()} and otherwise $N \log N$, +where $N$ is the value of \tcode{key_cont.size()} before this call. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +template + flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true} and +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_map(key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_map(key_cont, mapped_cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}. + +\pnum +\complexity +Constant. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +template + flat_map(sorted_unique_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true} and +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_map(s, key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +template + flat_map(const key_compare& comp, const Allocator& a); +template + explicit flat_map(const Allocator& a); +template + flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); +template + flat_map(InputIterator first, InputIterator last, const Allocator& a); +template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_map(from_range_t, R&& rg, const Allocator& a); +template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); +template + flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); +template + flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); +template + flat_map(initializer_list il, const key_compare& comp, const Allocator& a); +template + flat_map(initializer_list il, const Allocator& a); +template + flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp, const Allocator& a); +template + flat_map(sorted_unique_t, initializer_list il, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to the corresponding non-allocator constructors +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. +\end{itemdescr} + +\rSec3[flat.map.capacity]{Capacity} + +\indexlibrarymember{size}{flat_map}% +\begin{itemdecl} +size_type size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{c.keys.size()}. +\end{itemdescr} + +\indexlibrarymember{max_size}{flat_map}% +\begin{itemdecl} +size_type max_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{min(c.keys.max_size(), c.values.max_size())}. +\end{itemdescr} + +\rSec3[flat.map.access]{Access} + +\indexlibrarymember{operator[]}{flat_map}% +\begin{itemdecl} +mapped_type& operator[](const key_type& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return try_emplace(x).first->second;} +\end{itemdescr} + +\indexlibrarymember{operator[]}{flat_map}% +\begin{itemdecl} +mapped_type& operator[](key_type&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return try_emplace(std::move(x)).first->second;} +\end{itemdescr} + +\indexlibrarymember{operator[]}{flat_map}% +\begin{itemdecl} +template mapped_type& operator[](K&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} is valid and +denotes a type. + +\pnum +\effects +Equivalent to: \tcode{return try_emplace(std::forward(x)).first->second;} +\end{itemdescr} + +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +mapped_type& at(const key_type& x); +const mapped_type& at(const key_type& x) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reference to the \tcode{mapped_type} corresponding +to \tcode{x} in \tcode{*this}. + +\pnum +\throws +An exception object of type \tcode{out_of_range} if +no such element is present. + +\pnum +\complexity +Logarithmic. +\end{itemdescr} + +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +template mapped_type& at(const K& x); +template const mapped_type& at(const K& x) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. + +\pnum +\expects +The expression \tcode{find(x)} is well-formed and has well-defined behavior. + +\pnum +\returns +A reference to the \tcode{mapped_type} corresponding to +\tcode{x} in \tcode{*this}. + +\pnum +\throws +An exception object of type \tcode{out_of_range} +if no such element is present. + +\pnum +\complexity +Logarithmic. +\end{itemdescr} + +\rSec3[flat.map.modifiers]{Modifiers} + +\indexlibrarymember{emplace}{flat_map}% +\begin{itemdecl} +template pair emplace(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, Arg...>} is \tcode{true}. + +\pnum +\effects +Initializes an object \tcode{t} of type \tcode{pair} +with \tcode{std::forward(\linebreak args)...}; +if the map already contains an element +whose key is equivalent to \tcode{t.first}, +\tcode{*this} is unchanged. +Otherwise, equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(c.keys, t.first, compare); +auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); +c.keys.insert(key_it, std::move(t.first)); +c.values.insert(value_it, std::move(t.second)); +\end{codeblock} + +\pnum +\returns +The \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place, and +the iterator component of the pair points to +the element with key equivalent to \tcode{t.first}. +\end{itemdescr} + +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template pair insert(P&& x); +template iterator insert(const_iterator position, P&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, P>} is \tcode{true}. + +\pnum +\effects +The first form is equivalent to \tcode{return emplace(std::forward

(x));}. +The second form is equivalent to +\tcode{return emplace_hint(position, std::forward

(x));}. +\end{itemdescr} + +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template + void insert(InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Adds elements to \tcode{c} as if by: +\begin{codeblock} +for (; first != last; ++first) { + value_type value = *first; + c.keys.insert(c.keys.end(), std::move(value.first)); + c.values.insert(c.values.end(), std::move(value.second)); +} +\end{codeblock} +Then, sorts the range of newly inserted elements +with respect to \tcode{value_comp()}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = ranges::zip_view(c.keys, c.values); +auto it = ranges::unique(zv, key_equiv(compare)).begin(); +auto dist = distance(zv.begin(), it); +c.keys.erase(c.keys.begin() + dist, c.keys.end()); +c.values.erase(c.values.begin() + dist, c.values.end()); +\end{codeblock} + +\pnum +\complexity +$N$ + $M \log M$, +where $N$ is \tcode{size()} before the operation and +$M$ is \tcode{distance(first, last)}. + +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} + +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template + void insert(sorted_unique_t, InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Adds elements to \tcode{c} as if by: +\begin{codeblock} +for (; first != last; ++first) { + value_type value = *first; + c.keys.insert(c.keys.end(), std::move(value.first)); + c.values.insert(c.values.end(), std::move(value.second)); +} +\end{codeblock} +Then, merges the sorted range of newly added elements and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = ranges::zip_view(c.keys, c.values); +auto it = ranges::unique(zv, key_equiv(compare)).begin(); +auto dist = distance(zv.begin(), it); +c.keys.erase(c.keys.begin() + dist, c.keys.end()); +c.values.erase(c.values.begin() + dist, c.values.end()); +\end{codeblock} + +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. + +\pnum +\remarks +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(R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Adds elements to \tcode{c} as if by: +\begin{codeblock} +for (const auto& e : range) { + c.keys.insert(c.keys.end(), e.first); + c.values.insert(c.values.end(), e.second); +} +\end{codeblock} +Then, sorts the range of newly inserted elements +with respect to \tcode{value_comp()}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = ranges::zip_view(c.keys, c.values); +auto it = ranges::unique(zv, key_equiv(compare)).begin(); +auto dist = distance(zv.begin(), it); +c.keys.erase(c.keys.begin() + dist, c.keys.end()); +c.values.erase(c.values.begin() + dist, c.values.end()); +\end{codeblock} + +\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{try_emplace}{flat_map}% +\begin{itemdecl} +template + pair try_emplace(const key_type& k, Args&&... args); +template + pair try_emplace(key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +If the map already contains an element whose key is equivalent to \tcode{k}, +\tcode{*this} and \tcode{args...} are unchanged. +Otherwise equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(c.keys, k, compare); +auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); +c.keys.insert(key_it, std::forward(k)); +c.values.emplace(value_it, std::forward(args)...); +\end{codeblock} + +\pnum +\returns +In the first two overloads, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. + +\pnum +\complexity +The same as \tcode{emplace} for the first two overloads, and +the same as \tcode{emplace_hint} for the last two overloads. +\end{itemdescr} + +\indexlibrarymember{try_emplace}{flat_map}% +\begin{itemdecl} +template + pair try_emplace(K&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +For the first overload, +\tcode{is_convertible_v} and +\tcode{is_convertible_v} are both \tcode{false}. +\end{itemize} + +\pnum +\expects +The conversion from \tcode{k} into \tcode{key_type} constructs +an object \tcode{u}, +for which \tcode{find(k) == find(u)} is \tcode{true}. + +\pnum +\effects +If the map already contains an element whose key is equivalent to \tcode{k}, +\tcode{*this} and \tcode{args...} are unchanged. +Otherwise equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(c.keys, k, compare); +auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); +c.keys.emplace(key_it, std::forward(k)); +c.values.emplace(value_it, std::forward(args)...); +\end{codeblock} + +\pnum +\returns +In the first overload, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. + +\pnum +\complexity +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +\end{itemdescr} + +\indexlibrarymember{insert_or_assign}{flat_map}% +\begin{itemdecl} +template + pair insert_or_assign(const key_type& k, M&& obj); +template + pair insert_or_assign(key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_assignable_v} is \tcode{true} and +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +If the map already contains an element \tcode{e} +whose key is equivalent to \tcode{k}, +assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. +Otherwise, equivalent to +\begin{codeblock} +try_emplace(std::forward(k), std::forward(obj)) +\end{codeblock} +for the first two overloads or +\begin{codeblock} +try_emplace_hint(hint, std::forward(k), std::forward(obj)) +\end{codeblock} +for the last two overloads. + +\pnum +\returns +In the first two overloads, the \tcode{bool} component of the returned pair +is \tcode{true} if and only if the insertion took place. The returned +iterator points to the map element whose key is equivalent to \tcode{k}. + +\pnum +\complexity +The same as \tcode{emplace} for the first two overloads and +the same as \tcode{emplace_hint} for the last two overloads. +\end{itemdescr} + +\indexlibrarymember{insert_or_assign}{flat_map}% +\begin{itemdecl} +template + pair insert_or_assign(K&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +\tcode{is_assignable_v} is \tcode{true}. +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\expects +The conversion from \tcode{k} into \tcode{key_type} constructs +an object \tcode{u}, for which \tcode{find(k) == find(u)} is \tcode{true}. + +\pnum +\effects +If the map already contains an element \tcode{e} +whose key is equivalent to \tcode{k}, +assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. +Otherwise, equivalent to +\begin{codeblock} +try_emplace(std::forward(k), std::forward(obj)) +\end{codeblock} +for the first overload or +\begin{codeblock} +try_emplace_hint(hint, std::forward(k), std::forward(obj)) +\end{codeblock} +for the second overload. + +\pnum +\returns +In the first overload, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. + +\pnum +\complexity +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +\end{itemdescr} + +\indexlibrarymember{swap}{flat_map}% +\begin{itemdecl} +void swap(flat_map& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +ranges::swap(compare, y.compare); +ranges::swap(c.keys, y.c.keys); +ranges::swap(c.values, y.c.values); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{extract}{flat_map}% +\begin{itemdecl} +containers extract() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. + +\pnum +\returns +\tcode{std::move(c)}. +\end{itemdescr} + +\indexlibrarymember{replace}{flat_map}% +\begin{itemdecl} +void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{key_cont.size() == mapped_cont.size()} is \tcode{true}, +the elements of \tcode{key_cont} are sorted with respect to \tcode{compare}, and +\tcode{key_cont} contains no equal elements. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +c.keys = std::move(key_cont); +c.values = std::move(mapped_cont); +\end{codeblock} +\end{itemdescr} + +\rSec3[flat.map.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_map}% +\begin{itemdecl} +template + typename flat_map::size_type + erase_if(flat_map& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. + +\pnum +\effects +Let $E$ be \tcode{bool(pred(pair(e)))}. +Erases all elements \tcode{e} in \tcode{c} for which $E$ holds. + +\pnum +\returns +The number of elements erased. + +\pnum +\complexity +Exactly \tcode{c.size()} applications of the predicate. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +If an invocation of \tcode{erase_if} exits via an exception, +\tcode{c} is in a valid but unspecified state\iref{defns.valid}. +\begin{note} +\tcode{c} still meets its invariants, +but can be empty. +\end{note} +\end{itemdescr} + +\rSec2[flat.multimap]{Class template \tcode{flat_multimap}} + +\rSec3[flat.multimap.overview]{Overview} + +\pnum +\indexlibraryglobal{flat_multimap}% +A \tcode{flat_multimap} is a container adaptor +that provides an associative container interface +that supports equivalent keys +(i.e., possibly containing multiple copies of the same key value) and +provides for fast retrieval of values of another type \tcode{T} +based on the keys. +\tcode{flat_multimap} supports iterators that meet +the \oldconcept{InputIterator} requirements and +model the +\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. + +\pnum +A \tcode{flat_multimap} meets all of the requirements +for a container\iref{container.reqmts} and +for a reversible container\iref{container.rev.reqmts}, +plus the optional container requirements\iref{container.opt.reqmts}. +\tcode{flat_multimap} meets the requirements of +an associative container\iref{associative.reqmts}, except that: +\begin{itemize} +\item +it does not meet the requirements related to node handles\iref{container.node}, +\item +it does not meet the requirements related to iterator invalidation, and +\item +the time complexity of the operations +that insert or erase a single element from the map is linear, +including the ones that take an insertion position iterator. +\end{itemize} +\begin{note} +A \tcode{flat_multimap} does not meet the additional requirements of an +allocator-aware container\iref{container.alloc.reqmts}. +\end{note} + +\pnum +A \tcode{flat_multimap} also provides most operations described +in \ref{associative.reqmts} for equal keys. +This means that a \tcode{flat_multimap} supports the \tcode{a_eq} operations +in \ref{associative.reqmts} but not the \tcode{a_uniq} operations. +For a \tcode{flat_multimap} +the \tcode{key_type} is \tcode{Key} and +the \tcode{value_type} is \tcode{pair}. + +\pnum +Except as otherwise noted, +operations on \tcode{flat_multimap} are equivalent to those of \tcode{flat_map}, +except that \tcode{flat_multimap} operations +do not remove or replace elements with equal keys. +\begin{example} +\tcode{flat_multimap} constructors and emplace do not erase +non-unique elements after sorting them. +\end{example} + +\pnum +A \tcode{flat_multimap} maintains the following invariants: +\begin{itemize} +\item +it contains the same number of keys and values; +\item +the keys are sorted with respect to the comparison object; and +\item +the value at offset \tcode{off} within the value container is the value +associated with the key at offset \tcode{off} within the key container. +\end{itemize} + +\pnum +If any member function in \ref{flat.multimap.defn} exits via an exception, +the invariants are restored. +\begin{note} +This can result in the \tcode{flat_multimap} being emptied. +\end{note} + +\pnum +Any sequence container\iref{sequence.reqmts} \tcode{C} +supporting \oldconcept{RandomAccessIterator} can be used to +instantiate \tcode{flat_multimap}, +as long as invocations of +member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. +In particular, +\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. +\begin{note} +\tcode{vector} is not a sequence container. +\end{note} + +\pnum +The program is ill-formed if +\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or +\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. + +\pnum +The effect of calling a constructor +that takes both \tcode{key_container_type} and +\tcode{mapped_container_type} arguments +with containers of different sizes is undefined. + +\pnum +The effect of calling a constructor or member function +that takes a \tcode{sorted_equivalent_t} argument +with a container, containers, or range +that are not sorted with respect to \tcode{key_comp()} is undefined. + +\rSec3[flat.multimap.defn]{Definition} + +\begin{codeblock} +namespace std { + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_multimap { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = @\impdefx{type of \tcode{flat_multimap::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_multimap::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; + + class value_compare { + private: + key_compare comp; // \expos + value_compare(key_compare c) : comp(c) { } // \expos + public: + 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; + }; + + // \ref{flat.multimap.cons}, construct/copy/destroy + flat_multimap() : flat_multimap(key_compare()) { } + + flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); + + flat_multimap(sorted_equivalent_t, + key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); + + explicit flat_multimap(const key_compare& comp) + : c(), compare(comp) { } + template + flat_multimap(const key_compare& comp, const Allocator& a); + template + explicit flat_multimap(const Allocator& a); + + template + flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + template + flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); + template + flat_multimap(InputIterator first, InputIterator last, + const Allocator& a); + + template<@\exposconcept{container-compatible-range}@ R> + flat_mutlimap(from_range_t fr, R&& rg) + : flat_multimap(fr, std::forward(rg), key_compare()) { } + template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_mutlimap(from_range_t, R&& rg, const Allocator& a); + template<@\exposconcept{container-compatible-range}@ R> + flat_multimap(from_range_t, R&& rg, const key_compare& comp) + : flat_multimap(comp) { insert_range(std::forward(rg)); } + template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); + + template + flat_multimap(sorted_equivalent_t s, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(s, first, last); } + template + flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); + template + flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Allocator& a); + + flat_multimap(initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(il.begin(), il.end(), comp) { } + template + flat_multimap(initializer_list il, + const key_compare& comp, const Allocator& a); + template + flat_multimap(initializer_list il, const Allocator& a); + + flat_multimap(sorted_equivalent_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(s, il.begin(), il.end(), comp) { } + template + flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Allocator& a); + template + flat_multimap(sorted_equivalent_t, initializer_list il, const Allocator& a); + + flat_multimap& operator=(initializer_list il); + + // iterators + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + reverse_iterator rbegin() noexcept; + const_reverse_iterator rbegin() const noexcept; + reverse_iterator rend() noexcept; + const_reverse_iterator rend() const noexcept; + + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + // capacity + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + // modifiers + template iterator emplace(Args&&... args); + template + iterator emplace_hint(const_iterator position, Args&&... args); + + iterator insert(const value_type& x) + { return emplace(x); } + iterator insert(value_type&& x) + { return emplace(std::move(x)); } + iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template iterator insert(P&& x); + template + iterator insert(const_iterator position, P&&); + template + void insert(InputIterator first, InputIterator last); + template + void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + void insert_range(R&& rg); + + void insert(initializer_list il) + { insert(il.begin(), il.end()); } + void insert(sorted_equivalent_t s, initializer_list il) + { insert(s, il.begin(), il.end()); } + + containers extract() &&; + void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + iterator erase(iterator position); + iterator erase(const_iterator position); + size_type erase(const key_type& x); + template size_type erase(K&& x); + iterator erase(const_iterator first, const_iterator last); + + void swap(flat_multimap&) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + value_compare value_comp() const; + + const key_container_type& keys() const noexcept { return c.keys; } + const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + iterator find(const key_type& x); + const_iterator find(const key_type& x) const; + template iterator find(const K& x); + template const_iterator find(const K& x) const; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template bool contains(const K& x) const; + + iterator lower_bound(const key_type& x); + const_iterator lower_bound(const key_type& x) const; + template iterator lower_bound(const K& x); + template const_iterator lower_bound(const K& x) const; + + iterator upper_bound(const key_type& x); + const_iterator upper_bound(const key_type& x) const; + template iterator upper_bound(const K& x); + template const_iterator upper_bound(const K& x) const; + + pair equal_range(const key_type& x); + pair equal_range(const key_type& x) const; + template + pair equal_range(const K& x); + template + pair equal_range(const K& x) const; + + friend bool operator==(const flat_multimap& x, const flat_multimap& y); + + friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_multimap& x, const flat_multimap& y); + + friend void swap(flat_multimap& x, flat_multimap& y) noexcept + { x.swap(y); } + + private: + containers c; // \expos + key_compare compare; // \expos + }; + + template + flat_multimap(KeyContainer, MappedContainer) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + + template>> + flat_multimap(InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>> + flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>, + class Allocator> + flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare>; + + template + flat_multimap(from_range_t, R&&, Allocator) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@>; + + template> + flat_multimap(initializer_list>, Compare = Compare()) + -> flat_multimap; + + template> + flat_multimap(sorted_equivalent_t, initializer_list>, Compare = Compare()) + -> flat_multimap; + + template + struct uses_allocator, + Allocator> + : bool_constant && + uses_allocator_v> { }; +} +\end{codeblock} + +\pnum +The member type \tcode{containers} has the data members and special members +specified above. It has no base classes or members other than those +specified. + +\rSec3[flat.multimap.cons]{Constructors} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}; and +sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}. + +\pnum +\complexity +Linear in $N$ if the container arguments are already sorted +with respect to \tcode{value_comp()} and +otherwise $N \log N$, +where $N$ is \tcode{key_cont.size()}. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true} and +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_multimap(key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_multimap(key_cont, mapped_cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +flat_multimap(sorted_equivalent_t, key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}. + +\pnum +\complexity +Constant. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true} and +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_multimap(s, key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.val\-ues} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + flat_multimap(const key_compare& comp, const Allocator& a); +template + explicit flat_multimap(const Allocator& a); +template + flat_multimap(InputIterator first, InputIterator last, const key_compare& comp, + const Allocator& a); +template + flat_multimap(InputIterator first, InputIterator last, const Allocator& a); +template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_mutlimap(from_range_t, R&& rg, const Allocator& a); +template<@\exposconcept{container-compatible-range}@ R, class Allocator> + flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); +template + flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Allocator& a); +template + flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Allocator& a); +template + flat_multimap(initializer_list il, const key_compare& comp, const Allocator& a); +template + flat_multimap(initializer_list il, const Allocator& a); +template + flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Allocator& a); +template + flat_multimap(sorted_equivalent_t, initializer_list il, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true} and +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to the corresponding non-allocator constructors +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. +\end{itemdescr} + +\rSec3[flat.multimap.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_multimap}% +\begin{itemdecl} +template + typename flat_multimap::size_type + erase_if(flat_multimap& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. + +\pnum +\effects +Let $E$ be \tcode{bool(pred(pair(e)))}. +Erases all elements \tcode{e} in \tcode{c} for which $E$ holds. + +\pnum +\returns +The number of elements erased. + +\pnum +\complexity +Exactly \tcode{c.size()} applications of the predicate. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +If an invocation of \tcode{erase_if} exits via an exception, +\tcode{c} is in a valid but unspecified state\iref{defns.valid}. +\begin{note} +\tcode{c} still meets its invariants, +but can be empty. +\end{note} +\end{itemdescr} + \rSec1[views]{Views} \rSec2[views.general]{General} diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 291a48d786..208b8cd8c4 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -1034,6 +1034,7 @@ \tcode{} \\ \tcode{} \\ \columnbreak +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ diff --git a/source/support.tex b/source/support.tex index 2e34b6f0f3..cdcdaf1bbe 100644 --- a/source/support.tex +++ b/source/support.tex @@ -616,6 +616,7 @@ #define @\defnlibxname{cpp_lib_execution}@ 201902L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_expected}@ 202202L // 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_format}@ 202110L // also in \libheader{format} #define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric} #define @\defnlibxname{cpp_lib_generic_associative_lookup}@ 201304L // also in \libheader{map}, \libheader{set}