diff --git a/source/containers.tex b/source/containers.tex index cf448ecd3e..281224990f 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -2177,9 +2177,10 @@ \pnum \indextext{unordered associative containers!equality function}% -Two values \tcode{k1} and \tcode{k2} of type \tcode{Key} are +Two values \tcode{k1} and \tcode{k2} are considered equivalent if the container's -key equality predicate returns +key equality predicate +\tcode{pred(k1, k2)} is valid and returns \tcode{true} when passed those values. If \tcode{k1} and \tcode{k2} are equivalent, the container's hash function shall return the same value for both. @@ -2256,27 +2257,43 @@ \indextext{unordered associative containers!equivalent keys}% \indextext{requirements!container}% In \tref{HashRequirements}: -\tcode{X} denotes an unordered associative container class, -\tcode{a} denotes a value of type \tcode{X}, -\tcode{a2} denotes a value of a type with nodes compatible with type -\tcode{X} (\tref{containers.node.compat}), -\tcode{b} denotes a possibly const value of type \tcode{X}, -\tcode{a_uniq} denotes a value of type \tcode{X} when \tcode{X} supports unique keys, -\tcode{a_eq} denotes a value of type \tcode{X} when \tcode{X} supports equivalent keys, -\tcode{i} and \tcode{j} denote input iterators that refer to \tcode{value_type}, -\tcode{[i, j)} denotes a valid range, -\tcode{p} and \tcode{q2} denote valid constant iterators to \tcode{a}, -\tcode{q} and \tcode{q1} denote valid dereferenceable constant iterators to \tcode{a}, -\tcode{r} denotes a valid dereferenceable iterator to \tcode{a}, -\tcode{[q1, q2)} denotes a valid range in \tcode{a}, -\tcode{il} denotes a value of type \tcode{initializer_list}, -\tcode{t} denotes a value of type \tcode{X::value_type}, -\tcode{k} denotes a value of type \tcode{key_type}, -\tcode{hf} denotes a possibly const value of type \tcode{hasher}, -\tcode{eq} denotes a possibly const value of type \tcode{key_equal}, -\tcode{n} denotes a value of type \tcode{size_type}, -\tcode{z} denotes a value of type \tcode{float}, -and \tcode{nh} denotes a non-const rvalue of type \tcode{X::node_type}. +\begin{itemize} +\item \tcode{X} denotes an unordered associative container class, +\item \tcode{a} denotes a value of type \tcode{X}, +\item \tcode{a2} denotes a value of a type with nodes compatible + with type \tcode{X} (\tref{containers.node.compat}), +\item \tcode{b} denotes a possibly const value of type \tcode{X}, +\item \tcode{a_uniq} denotes a value of type \tcode{X} + when \tcode{X} supports unique keys, +\item \tcode{a_eq} denotes a value of type \tcode{X} + when \tcode{X} supports equivalent keys, +\item \tcode{a_tran} denotes a possibly const value of type \tcode{X} + when the \grammarterm{qualified-id} \tcode{X::hasher::transparent_key_equal} + is valid and denotes a type\iref{temp.deduct}, +\item \tcode{i} and \tcode{j} denote input iterators + that refer to \tcode{value_type}, +\item \tcode{[i, j)} denotes a valid range, +\item \tcode{p} and \tcode{q2} denote valid constant iterators to \tcode{a}, +\item \tcode{q} and \tcode{q1} denote + valid dereferenceable constant iterators to \tcode{a}, +\item \tcode{r} denotes a valid dereferenceable iterator to \tcode{a}, +\item \tcode{[q1, q2)} denotes a valid range in \tcode{a}, +\item \tcode{il} denotes a value of type \tcode{initializer_list}, +\item \tcode{t} denotes a value of type \tcode{X::value_type}, +\item \tcode{k} denotes a value of type \tcode{key_type}, +\item \tcode{hf} denotes a possibly const value of type \tcode{hasher}, +\item \tcode{eq} denotes a possibly const value of type \tcode{key_equal}, +\item \tcode{ke} is a value such that + \begin{itemize} + \item \tcode{eq(r1, ke) == eq(ke, r1)} + \item \tcode{hf(r1) == hf(ke)} if \tcode{eq(r1, ke)} is \tcode{true}, and + \item \tcode{(eq(r1, ke) \&\& eq(r1, r2)) == eq(r2, ke)} + \end{itemize} + where \tcode{r1} and \tcode{r2} are keys of elements in \tcode{a_tran}, +\item \tcode{n} denotes a value of type \tcode{size_type}, +\item \tcode{z} denotes a value of type \tcode{float}, and +\item \tcode{nh} denotes a non-const rvalue of type \tcode{X::node_type}. +\end{itemize} % Local command to index names as members of all unordered containers. \newcommand{\indexunordmem}[1]{% @@ -2302,7 +2319,10 @@ %% \indexunordmem{key_type}% \tcode{X::key_type} & - \tcode{Key} & + \tcode{Hash::transparent_key_equal} + if such a \grammarterm{qualified-id} + is valid and denotes a type\iref{temp.deduct}; + otherwise, \tcode{Pred}. & & compile time \\ \rowsep @@ -2333,7 +2353,9 @@ % \indexunordmem{key_equal}% \tcode{X::key_equal} -& \tcode{Pred} +& \tcode{Hash::transparent_key_equal} if such a \grammarterm{qualified-id} + is valid and denotes a type\iref{temp.deduct}; + otherwise, \tcode{Pred}. & \requires\ \tcode{Pred} is \oldconcept{CopyConstructible}.\br \tcode{Pred} shall be a binary predicate that takes two arguments of type \tcode{Key}. \tcode{Pred} is an equivalence relation.% @@ -2727,6 +2749,14 @@ & Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % +\tcode{a_tran.find(ke)} +& \tcode{iterator}; \br \tcode{const_iterator} for const \tcode{a_tran}. +& Returns an iterator pointing to an element with key equivalent to + \tcode{ke}, or \tcode{a_tran.end()} if no such element exists.% +& Average case \bigoh{1}, + worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid wverfull +\\ \rowsep +% \indexunordmem{count}% \tcode{b.count(k)} & \tcode{size_type} @@ -2734,6 +2764,14 @@ & Average case \bigoh{\tcode{b.count(k)}}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % +\tcode{a_tran.count(ke)} +& \tcode{size_type} +& Returns the number of elements with key equivalent to \tcode{ke}.% +& Average case + \bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}, % avoid overfull + worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull +\\ \rowsep +% \indexunordmem{contains}% \tcode{b.contains(k)} & \tcode{bool} @@ -2741,6 +2779,13 @@ & Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % +\tcode{a_tran.contains(ke)} +& \tcode{bool} +& Equivalent to \tcode{a_tran.find(ke) != a_tran.end()}% +& Average case \bigoh{1}, + worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull +\\ \rowsep +% \indexunordmem{equal_range}% \tcode{b.equal_range(k)} & \tcode{pair}; \br @@ -2752,6 +2797,16 @@ \bigoh{\tcode{b.size()}}. \\ \rowsep % +\tcode{a_tran.equal_range(ke)} +& \tcode{pair}; \br + \tcode{pair} for const \tcode{a_tran}. +& Returns a range containing all elements with keys equivalent to + \tcode{ke}. Returns \tcode{make_pair(a_tran.end(), a_tran.end())} if + no such elements exist.% +& Average case + \bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}. % avoid overfull + Worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull +\\ \rowsep \indexunordmem{bucket_count}% \tcode{b.bucket_count()} & \tcode{size_type} @@ -2930,6 +2985,24 @@ obtained while it is owned by a \tcode{node_type} are invalidated if the element is successfully inserted. +\pnum +If the \grammarterm{qualified-id} \tcode{Hash::transparent_key_equal} +is valid and denotes a type\iref{temp.deduct}, +then the program is ill-formed if either: +\begin{itemize} +\item + \grammarterm{qualified-id} \tcode{Hash::transparent_key_equal::is_transparent} + is not valid or does not denote a type, or +\item + \tcode{Pred} is a different type than \tcode{equal_to} or + \tcode{Hash::transparent_key_equal}. +\end{itemize} +The member function templates +\tcode{find}, \tcode{count}, \tcode{equal_range}, and \tcode{contains} +shall not participate in overload resolution unless +the \grammarterm{qualified-id} \tcode{Hash::transparent_key_equal} +is valid and denotes a type\iref{temp.deduct}. + \pnum A deduction guide for an unordered associative container shall not participate in overload resolution if any of the following are true: @@ -7492,7 +7565,7 @@ using mapped_type = T; using value_type = pair; using hasher = Hash; - using key_equal = Pred; + using key_equal = @\seeref{unord.req}@; using allocator_type = Allocator; using pointer = typename allocator_traits::pointer; using const_pointer = typename allocator_traits::const_pointer; @@ -7626,12 +7699,24 @@ key_equal key_eq() const; // map operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - bool contains(const key_type& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + template + iterator find(const K& k); + template + const_iterator find(const K& k) const; + size_type count(const key_type& k) const; + template + size_type count(const K& k) const; + bool contains(const key_type& k) const; + template + bool contains(const K& k) const; + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + template + pair equal_range(const K& k); + template + pair equal_range(const K& k) const; // \ref{unord.map.elem}, element access mapped_type& operator[](const key_type& k); @@ -8039,7 +8124,7 @@ using mapped_type = T; using value_type = pair; using hasher = Hash; - using key_equal = Pred; + using key_equal = @\seeref{unord.req}@; using allocator_type = Allocator; using pointer = typename allocator_traits::pointer; using const_pointer = typename allocator_traits::const_pointer; @@ -8155,12 +8240,24 @@ key_equal key_eq() const; // map operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - bool contains(const key_type& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + template + iterator find(const K& k); + template + const_iterator find(const K& k) const; + size_type count(const key_type& k) const; + template + size_type count(const K& k) const; + bool contains(const key_type& k) const; + template + bool contains(const K& k) const; + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + template + pair equal_range(const K& k); + template + pair equal_range(const K& k) const; // bucket interface size_type bucket_count() const noexcept; @@ -8367,7 +8464,7 @@ using key_type = Key; using value_type = Key; using hasher = Hash; - using key_equal = Pred; + using key_equal = @\seeref{unord.req}@; using allocator_type = Allocator; using pointer = typename allocator_traits::pointer; using const_pointer = typename allocator_traits::const_pointer; @@ -8482,12 +8579,24 @@ key_equal key_eq() const; // set operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - bool contains(const key_type& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + template + iterator find(const K& k); + template + const_iterator find(const K& k) const; + size_type count(const key_type& k) const; + template + size_type count(const K& k) const; + bool contains(const key_type& k) const; + template + bool contains(const K& k) const; + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + template + pair equal_range(const K& k); + template + pair equal_range(const K& k) const; // bucket interface size_type bucket_count() const noexcept; @@ -8657,7 +8766,7 @@ using key_type = Key; using value_type = Key; using hasher = Hash; - using key_equal = Pred; + using key_equal = @\seeref{unord.req}@; using allocator_type = Allocator; using pointer = typename allocator_traits::pointer; using const_pointer = typename allocator_traits::const_pointer; @@ -8771,12 +8880,24 @@ key_equal key_eq() const; // set operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - bool contains(const key_type& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + template + iterator find(const K& k); + template + const_iterator find(const K& k) const; + size_type count(const key_type& k) const; + template + size_type count(const K& k) const; + bool contains(const key_type& k) const; + template + bool contains(const K& k) const; + pair equal_range(const key_type& k); + pair equal_range(const key_type& k) const; + template + pair equal_range(const K& k); + template + pair equal_range(const K& k) const; // bucket interface size_type bucket_count() const noexcept; diff --git a/source/macros.tex b/source/macros.tex index 352163c088..5d61597fb6 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -296,6 +296,8 @@ \newcommand{\unspecbool}{\UNSP{unspecified-bool-type}} \newcommand{\seebelow}{\UNSP{see below}} \newcommand{\seebelownc}{\UNSPnc{see below}} +\newcommand{\seeref}[1]{\UNSP{see~\ref{#1}}} +\newcommand{\seerefnc}[1]{\UNSPnc{see~\ref{#1}}} \newcommand{\unspecuniqtype}{\UNSP{unspecified unique type}} \newcommand{\unspecalloctype}{\UNSP{unspecified allocator type}} diff --git a/source/support.tex b/source/support.tex index 1ef122b00d..66d03cbb30 100644 --- a/source/support.tex +++ b/source/support.tex @@ -596,6 +596,8 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_generic_associative_lookup} & \tcode{201304L} & \tcode{} \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_generic_unordered_lookup} & \tcode{201811L} & + \tcode{} \tcode{} \\ \rowsep \defnlibxname{cpp_lib_hardware_interference_size} & \tcode{201703L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_has_unique_object_representations} & \tcode{201606L} &