diff --git a/source/numerics.tex b/source/numerics.tex index 529ed10969..cdac6bed50 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16220,10 +16220,19 @@ @\libconcept{same_as}@> && is_default_constructible_v; +template + concept @\defexposconceptnc{simd-mask-type}@ = // \expos + @\libconcept{same_as}@, typename V::abi_type>> && + is_default_constructible_v; + template concept @\defexposconceptnc{simd-floating-point}@ = // \expos @\exposconcept{simd-type}@ && @\libconcept{floating_point}@; +template + concept @\defexposconceptnc{simd-integral}@ = // \expos + @\exposconcept{simd-type}@ && @\libconcept{integral}@; + template using @\exposidnc{simd-complex-value-type}@ = typename V::value_type::value_type; // \expos @@ -16592,6 +16601,94 @@ constexpr void partial_store(const basic_simd& v, I first, S last, const typename basic_simd::mask_type& mask, flags f = {}); + // \ref{simd.permute.static}, Permute by static index generator + static constexpr @\exposid{simd-size-type}@ zero_element = @\impdefx{value of \tcode{simd::zero_element}}@; + static constexpr @\exposid{simd-size-type}@ uninit_element = @\impdefx{value of \tcode{simd::uninit_element}}@; + + template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); + template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> + constexpr resize_t permute(const M& v, IdxMap&& idxmap); + + // \ref{simd.permute.dynamic}, Permute by dynamic index + template<@\exposconcept{simd-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); + template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const M& v, const I& indices); + + // \ref{simd.permute.mask}, Permute by active mask bits + template<@\exposconcept{simd-type}@ V> + constexpr V compress(const V& v, const typename V::mask_type& selector); + template<@\exposconcept{simd-mask-type}@ M> + constexpr M compress(const M& v, const type_identity_t& selector); + template<@\exposconcept{simd-type}@ V> + constexpr V compress(const V& v, const typename V::mask_type& selector, + const typename V::value_type& fill_value); + template<@\exposconcept{simd-mask-type}@ M> + constexpr M compress(const M& v, const type_identity_t& selector, + const typename V::value_type& fill_value); + + template<@\exposconcept{simd-type}@ V> + constexpr V expand(const V& v, const typename V::mask_type& selector, + const V& original = {}); + template<@\exposconcept{simd-mask-type}@ M> + constexpr M expand(const M& v, const type_identity_t& selector, const M& original = {}); + + // \ref{simd.permute.memory}, Permute to and from memory + template + requires ranges::@\libconcept{sized_range}@ + constexpr V + unchecked_gather_from(R&& in, const I& indices, flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ + constexpr V + unchecked_gather_from(R&& in, const typename I::mask_type& mask, + const I& indices, flags f = {}); + + template + requires ranges::@\libconcept{sized_range}@ + constexpr V + partial_gather_from(R&& in, const I& indices, flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ + constexpr V + partial_gather_from(R&& in, const typename I::mask_type& mask, + const I& indices, flags f = {}); + + template<@\exposconcept{simd-type}@ V, + ranges::@\libconcept{contiguous_range}@ R, + @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + unchecked_scatter_to(const V& v, R&& out, const I& indices, flags f = {}); + template<@\exposconcept{simd-type}@ V, + ranges::@\libconcept{contiguous_range}@ R, + @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + unchecked_scatter_to(const V& v, R&& out, + const typename I::mask_type& mask, + const I& indices, flags f = {}); + + template<@\exposconcept{simd-type}@ V, + ranges::@\libconcept{contiguous_range}@ R, + @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + partial_scatter_to(const V& v, R&& out, const I& indices, flags f = {}); + template<@\exposconcept{simd-type}@ V, + ranges::@\libconcept{contiguous_range}@ R, + @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + partial_scatter_to(const V& v, R&& out, + const typename I::mask_type& mask, + const I& indices, flags f = {}); + // \ref{simd.creation}, \tcode{basic_simd} and \tcode{basic_simd_mask} creation template constexpr auto chunk(const basic_simd& x) noexcept; @@ -17187,6 +17284,262 @@ specialization \tcode{\exposid{overaligned-flag}}. \end{itemdescr} +\rSec2[simd.iterator]{Class \exposid{simd-iterator}} +\begin{codeblock} +namespace std::datapar { + template + class @\exposidnc{simd-iterator}@ { // \expos + V* @\exposidnc{data_}@ = nullptr; // \expos + @\exposidnc{simd-size-type} \exposidnc{offset_}@ = 0; // \expos + + constexpr @\exposid{simd-iterator}@(V& d, @\exposid{simd-size-type}@ off) noexcept; // \expos + + public: + using value_type = typename V::value_type; + using iterator_category = input_iterator_tag; + using iterator_concept = random_access_iterator_tag; + using difference_type = @\exposid{simd-size-type}@; + + constexpr @\exposid{simd-iterator}@() = default; + + constexpr @\exposid{simd-iterator}@(const @\exposid{simd-iterator}@&) = default; + constexpr @\exposid{simd-iterator}@& operator=(const @\exposid{simd-iterator}@&) = default; + + constexpr @\exposid{simd-iterator}@(const @\exposid{simd-iterator}@>&) requires is_const_v; + + constexpr value_type operator*() const; + + constexpr @\exposid{simd-iterator}@& operator++(); + constexpr @\exposid{simd-iterator}@ operator++(int); + constexpr @\exposid{simd-iterator}@& operator--(); + constexpr @\exposid{simd-iterator}@ operator--(int); + + constexpr @\exposid{simd-iterator}@& operator+=(difference_type n); + constexpr @\exposid{simd-iterator}@& operator-=(difference_type n); + + constexpr value_type operator[](difference_type n) const; + + friend constexpr bool operator==(@\exposid{simd-iterator}@ a, @\exposid{simd-iterator}@ b) = default; + friend constexpr bool operator==(@\exposid{simd-iterator}@ a, default_sentinel_t) noexcept; + friend constexpr auto operator<=>(@\exposid{simd-iterator}@ a, @\exposid{simd-iterator}@ b); + + friend constexpr @\exposid{simd-iterator}@ operator+(@\exposid{simd-iterator}@ i, difference_type n); + friend constexpr @\exposid{simd-iterator}@ operator+(difference_type n, @\exposid{simd-iterator}@ i); + friend constexpr @\exposid{simd-iterator}@ operator-(@\exposid{simd-iterator}@ i, difference_type n); + + friend constexpr difference_type operator-(@\exposid{simd-iterator}@ a, @\exposid{simd-iterator}@ b); + friend constexpr difference_type operator-(@\exposid{simd-iterator}@ i, default_sentinel_t) noexcept; + friend constexpr difference_type operator-(default_sentinel_t, @\exposid{simd-iterator}@ i) noexcept; + }; +} +\end{codeblock} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@(V& d, @\exposid{simd-size-type}@ off) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{data_} with \tcode{addressof(d)} and \exposid{offset_} with \tcode{off}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@(const @\exposid{simd-iterator}@>& i) requires is_const_v; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{data_} with \tcode{i.\exposid{data_}} and \exposid{offset_} with \tcode{i.\exposid{offset_}}. +\end{itemdescr} + +\begin{itemdecl} +constexpr value_type operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return (*\exposid{data_})[\exposid{offset_}];} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *this += 1;} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@ operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{simd-iterator}@ tmp = *this; +*this += 1; +return tmp; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@& operator--(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *this -= 1;} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@ operator--(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{simd-iterator}@ tmp = *this; +*this -= 1; +return tmp; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@& operator+=(difference_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{offset_} + n} is in the range \crange{0}{V::size()}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{offset_}@ += n; +return *this; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-iterator}@& operator-=(difference_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{offset_} - n} is in the range \crange{0}{V::size()}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{offset_}@ -= n; +return *this; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr value_type operator[](difference_type n) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return (*\exposid{data_})[\exposid{offset_} + n];} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator==(@\exposid{simd-iterator}@ i, default_sentinel_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return i.\exposid{offset_} == V::size();} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr auto operator<=>(@\exposid{simd-iterator}@ a, @\exposid{simd-iterator}@ b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{a.\exposid{data_} == b.\exposid{data_}} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return a.\exposid{offset_} <=> b.\exposid{offset_};} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr @\exposid{simd-iterator}@ operator+(@\exposid{simd-iterator}@ i, difference_type n); +friend constexpr @\exposid{simd-iterator}@ operator+(difference_type n, @\exposid{simd-iterator}@ i); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return i += n;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr @\exposid{simd-iterator}@ operator-(@\exposid{simd-iterator}@ i, difference_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return i -= n;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr difference_type operator-(@\exposid{simd-iterator}@ a, @\exposid{simd-iterator}@ b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{a.\exposid{data_} == b.\exposid{data_}} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return a.\exposid{offset_} - b.\exposid{offset_};} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr difference_type operator-(@\exposid{simd-iterator}@ i, default_sentinel_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return i.\exposid{offset_} - V::size();} +\end{itemdescr} + + +\begin{itemdecl} +friend constexpr difference_type operator-(default_sentinel_t, @\exposid{simd-iterator}@ i) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return V::size() - i.\exposid{offset_};} +\end{itemdescr} + \rSec2[simd.class]{Class template \tcode{basic_simd}} \rSec3[simd.overview]{Class template \tcode{basic_simd} overview} @@ -17198,6 +17551,14 @@ using value_type = T; using mask_type = basic_simd_mask; using abi_type = Abi; + using iterator = \exposid{simd-iterator}; + using const_iterator = \exposid{simd-iterator}; + + constexpr iterator begin() noexcept { return {*this, 0}; } + constexpr const_iterator begin() const noexcept { return {*this, 0}; } + constexpr const_iterator cbegin() const noexcept { return {*this, 0}; } + constexpr default_sentinel_t end() const noexcept { return {}; } + constexpr default_sentinel_t cend() const noexcept { return {}; } static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@> size {}; @@ -17217,6 +17578,8 @@ // \ref{simd.subscr}, \tcode{basic_simd} subscript operators constexpr value_type operator[](@\exposid{simd-size-type}@) const; + template<@\exposconcept{simd-integral}@ I> + constexpr resize_t operator[](const I& indices) const; // \ref{simd.unary}, \tcode{basic_simd} unary operators constexpr basic_simd& operator++() noexcept; @@ -17537,6 +17900,17 @@ Nothing. \end{itemdescr} +\begin{itemdecl} +template<@\exposconcept{simd-integral}@ I> + constexpr resize_t operator[](const I& indices) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return permute(*this, indices);} +\end{itemdescr} + \rSec3[simd.unary]{\tcode{basic_simd} unary operators} \pnum @@ -18314,6 +18688,323 @@ \tcode{ranges::data(r)[$i$] = v[$i$]}. \end{itemdescr} +\rSec3[simd.permute.static]{\tcode{simd} static permute} + +\begin{itemdecl} +template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); +template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> + constexpr resize_t permute(const M& v, IdxMap&& idxmap); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item \tcode{\exposid{gen-fn}($i$)} be \tcode{idxmap($i$, V::size())} + if that expression is well-formed, and \tcode{idxmap($i$)} otherwise. +\item \tcode{perm-fn} be the following exposition-only function template: +\begin{codeblock} +template<@\exposid{simd-size-type}@ I> +typename V::value_type @\exposid{perm-fn}@() { + constexpr auto src_index = @\exposid{gen-fn}@(I); + if constexpr (src_index == zero_element) return typename V::value_type(); + else if constexpr (src_index == uninit_element) return @\exposid{unspecified-value}@; + else return v[src_index]; +} +\end{codeblock} +\end{itemize} + +\pnum +\constraints +\tcode{integral> || +integral>} is \tcode{true}. + +\pnum +\mandates +\tcode{\exposid{gen-fn}($i$)} is a constant expression whose value is +\tcode{zero_element}, \tcode{uninit_element}, or in the range +\range{0}{V::size()}, for all $i$ in the range \range{0}{N}. + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the +$i^\text{th}$ element is initialized to the result of +\tcode{\exposid{perm-fn}<$i$>()} for all $i$ in the range \range{0}{N}. + +\pnum +\remarks +The default argument for template parameter \tcode{N} is \tcode{V::size()}. +\end{itemdescr} + +\rSec3[simd.permute.dynamic]{\tcode{simd} dynamic permute} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); +template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const M& v, const I& indices); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +All values in \tcode{indices} are in the range \range{0}{V::size()}. + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the $i^\text{th}$ +element is initialized to the result of \tcode{v[indices[$i$]]} for all $i$ in +the range \range{0}{I::size()}. +\end{itemdescr} + +\rSec3[simd.permute.mask]{\tcode{simd} mask permute} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> + constexpr V compress(const V& v, const typename V::mask_type& selector); +template<@\exposconcept{simd-mask-type}@ M> + constexpr M compress(const M& v, const type_identity_t& selector); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item \tcode{\exposid{bit-index}($i$)} be a function which returns the index + of the $i$'th element of \tcode{selector} that is \tcode{true}. +\item \tcode{\exposid{select-value}($i$)} be a function which returns + \tcode{v[\exposid{bit-index}($i$)]} for $i$ in the range + \range{0}{reduce_count(selector)} and a valid but unspecified value + otherwise. [*Note*: Different calls to \tcode{select-value} can return + different unspecified values. - *end note*] +\end{itemize} + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the $i^\text{th}$ +element is initialized to the result of \tcode{\exposid{select-value}($i$)} +for all $i$ in the range \range{0}{V::size()}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> + constexpr V compress(const V& v, const typename V::mask_type& selector, + const typename V::value_type& fill_value); +template<@\exposconcept{simd-mask-type}@ M> + constexpr M compress(const M& v, const type_identity_t& selector, + const typename M::value_type& fill_value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item \tcode{\exposid{bit-index}($i$)} be a function which returns the index + of the $i$'th element of \tcode{selector} that is \tcode{true}. +\item \tcode{\exposid{select-value}($i$)} be a function which returns + \tcode{v[\exposid{bit-index}($i$)]} for $i$ in the range + \range{0}{reduce_count(selector)} and \tcode{fill_value} otherwise. +\end{itemize} + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the $i^\text{th}$ +element is initialized to the result of \tcode{\exposid{select-value}($i$)} +for all $i$ in the range \range{0}{V::size()}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> + constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); +template<@\exposconcept{simd-mask-type}@ M> + constexpr M expand(const M& v, const type_identity_t& selector, const M& original = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item \tcode{set-indices} be a list of the index positions of \tcode{true} + elements in \tcode{selector}. +\item \tcode{\exposid{bit-lookup}(b)} be a function which returns the index + where \tcode{b} appears in \tcode{\exposid{set-indices}}. +\item \tcode{\exposid{select-value}($i$)} be a function which returns + \tcode{v[\exposid{bit-lookup}($i$)]} if \tcode{selector[$i$]} is + \tcode{true}, otherwise returns \tcode{original[$i$]}. +\end{itemize} + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the $i^\text{th}$ +element is initialized to the result of \tcode{\exposid{select-value}($i$)} +for all $i$ in the range \range{0}{V::size()}. +\end{itemdescr} + +\rSec3[simd.permute.memory]{\tcode{simd} memory permute} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_gather_from(R&& in, const I& indices, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_gather_from(R&& in, const typename I::mask_type& mask, + const I& indices, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{typename I::mask_type(true)} for the overload with +no \tcode{mask} parameter. + +\pnum +\expects +All values in \tcode{select(mask, indices, typename I::value_type())} are in +the range \range{0}{ranges::size(in)}. + +\pnum +\effects +Equivalent to: \tcode{return partial_gather_from(in, mask, indices, f);} + +\pnum +\remarks +The default argument for template parameter \tcode{V} is +\tcode{simd, I::size()>}. +\end{itemdescr} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_gather_from(R&& in, const I& indices, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_gather_from(R&& in, const typename I::mask_type& mask, + const I& indices, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{typename I::mask_type(true)} for the overload with +no \tcode{mask} parameter. + +\pnum +\mandates +\begin{itemize} +\item \tcode{ranges::range_value_t} is a vectorizable type, +\item \tcode{same_as, V>} is \tcode{true}, +\item \tcode{V} is an enabled specialization of \tcode{basic_simd}, +\item \tcode{V::size() == I::size()} is \tcode{true}, and +\item if the template parameter pack \tcode{Flags} does not contain + \tcode{convert-flag}, then the conversion from + \tcode{ranges::range_value_t} to \tcode{V::value_type} is + value-preserving. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item If the template parameter pack \tcode{Flags} contains + \tcode{aligned-flag}, \tcode{ranges::data(in)} points to storage aligned by + \tcode{alignment_v>}. +\item If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(in)} points to + storage aligned by \tcode{N}. +\end{itemize} + +\pnum +\returns +A \tcode{basic_simd} or \tcode{basic_simd_mask} object where the $i^\text{th}$ +element is initialized to the result of \tcode{mask[$i$] \&\& indices[$i$] < +ranges::size(in) ? static_cast(range::\brk{}data(in)[indices[$i$]]) : typename +V::value_type()} for all $i$ in the range \range{0}{I::size()}. +% FIXME: the above \tcode{...} is too long => Overfull \hbox. codeblock? + +\pnum +\remarks +The default argument for template parameter \tcode{V} is +\tcode{simd, I::size()>}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V, ranges::@\libconcept{contiguous_range}@ R, @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void unchecked_scatter_to(const V& v, R&& out, const I& indices, + flags f = {}); +template<@\exposconcept{simd-type}@ V, ranges::@\libconcept{contiguous_range}@ R, @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void unchecked_scatter_to(const V& v, R&& out, const typename I::mask_type& mask, + const I& indices, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{typename I::mask_type(true)} for the overload with +no \tcode{mask} parameter. + +\pnum +\expects +All values in \tcode{select(mask, indices, typename I::value_type())} are in +the range \range{0}{ranges::size(out)}. + +\pnum +\effects +Equivalent to: \tcode{partial_scatter_to(v, out, mask, indices, f);} +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V, ranges::@\libconcept{contiguous_range}@ R, @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + partial_scatter_to(const V& v, R&& out, const I& indices, flags f = {}); +template<@\exposconcept{simd-type}@ V, ranges::@\libconcept{contiguous_range}@ R, @\exposconcept{simd-integral}@ I, class... Flags> + requires ranges::@\libconcept{sized_range}@ + constexpr void + partial_scatter_to(const V& v, R&& out, + const typename I::mask_type& mask, + const I& indices, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{typename I::mask_type(true)} for the overload with +no \tcode{mask} parameter. + +\pnum +\constraints +\tcode{V::size() == I::size()} is \tcode{true}. + +\pnum +\mandates +\begin{itemize} +\item \tcode{ranges::range_value_t} is a vectorizable type, and +\item if the template parameter pack \tcode{Flags} does not contain + \tcode{convert-flag}, then the conversion from \tcode{V::value_type} to + \tcode{ranges::range_value_t} is value-preserving. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item For all selected indices *$i$* the values \tcode{indices[$i$]} are + unique. +\item If the template parameter pack \tcode{Flags} contains + \tcode{aligned-flag}, \tcode{ranges::data(out)} points to storage aligned by + \tcode{alignment_v>}. +\item If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(out)} points to + storage aligned by \tcode{N}. +\end{itemize} + +\pnum +\effects +For all $i$ in the range \range{0}{I::size()}, if \tcode{mask[$i$] \&\& +(indices[$i$] < ranges::size(out))} is \tcode{true}, evaluates +\tcode{ranges::data(out)[indices[$i$]] = v[$i$]}. +\end{itemdescr} + \rSec3[simd.creation]{\tcode{basic_simd} and \tcode{basic_simd_mask} creation} \begin{itemdecl} @@ -19084,6 +19775,14 @@ public: using value_type = bool; using abi_type = Abi; + using iterator = \exposid{simd-iterator}; + using const_iterator = \exposid{simd-iterator}; + + constexpr iterator begin() noexcept { return {*this, 0}; } + constexpr const_iterator begin() const noexcept { return {*this, 0}; } + constexpr const_iterator cbegin() const noexcept { return {*this, 0}; } + constexpr default_sentinel_t end() const noexcept { return {}; } + constexpr default_sentinel_t cend() const noexcept { return {}; } static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@<@\exposid{integer-from}@, Abi>> size {}; @@ -19095,9 +19794,13 @@ template constexpr explicit basic_simd_mask(const basic_simd_mask&) noexcept; template constexpr explicit basic_simd_mask(G&& gen) noexcept; + constexpr basic_simd_mask(const bitset& b) noexcept; + constexpr explicit basic_simd_mask(@\libconcept{unsigned_integral}@ auto val) noexcept; // \ref{simd.mask.subscr}, \tcode{basic_simd_mask} subscript operators constexpr value_type operator[](@\exposid{simd-size-type}@) const; + template<@\exposconcept{simd-integral}@ I> + constexpr resize_t operator[](const I& indices) const; // \ref{simd.mask.unary}, \tcode{basic_simd_mask} unary operators constexpr basic_simd_mask operator!() const noexcept; @@ -19109,6 +19812,10 @@ template constexpr explicit(sizeof(U) != Bytes) operator basic_simd() const noexcept; + // \ref{simd.mask.namedconv}, \tcode{basic_simd_mask} named type convertors + constexpr bitset to_bitset() const noexcept; + constexpr unsigned long long to_ullong() const; + // \ref{simd.mask.binary}, \tcode{basic_simd_mask} binary operators friend constexpr basic_simd_mask operator&&(const basic_simd_mask&, const basic_simd_mask&) noexcept; @@ -19241,6 +19948,31 @@ \tcode{gen} is invoked exactly once for each $i$, in increasing order of $i$. \end{itemdescr} +\begin{itemdecl} +constexpr basic_simd_mask(const bitset& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the $i^\text{th}$ element with \tcode{b[$i$]} for all $i$ in the +range \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +constexpr explicit basic_simd_mask(@\libconcept{unsigned_integral}@ auto val) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the first $M$ elements to the corresponding bit values in +\tcode{val}, where $M$ is the smaller of \tcode{size()} and the number of bits in +the value representation\iref{basic.types.general} of the type of \tcode{val}. If +$M$ is less than \tcode{size()}, the remaining elements are initialized to +zero. +\end{itemdescr} + \rSec3[simd.mask.subscr]{\tcode{basic_simd_mask} subscript operator} \begin{itemdecl} @@ -19261,6 +19993,17 @@ Nothing. \end{itemdescr} +\begin{itemdecl} +template<@\exposconcept{simd-integral}@ I> + constexpr resize_t operator[](const I& indices) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return permute(*this, indices);} +\end{itemdescr} + \rSec3[simd.mask.unary]{\tcode{basic_simd_mask} unary operators} \begin{itemdecl} @@ -19299,6 +20042,43 @@ \tcode{static_cast(operator[]($i$))}. \end{itemdescr} +\rSec3[simd.mask.namedconv]{\tcode{basic_simd_mask} named conversion operators} + +\begin{itemdecl} +constexpr bitset to_bitset() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{bitset} object where the $i^\text{th}$ element is initialized to +\tcode{operator[]($i$)} for all $i$ in the range \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +constexpr unsigned long long to_ullong() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $N$ be the width of \tcode{unsigned long long}. + +\pnum +\expects +\begin{itemize} +\item \tcode{size()} $\le N$, or +\item for all $i$ in the range \range{$N$}{size()}, \tcode{operator[]($i$)} returns \tcode{false}. +\end{itemize} + +\pnum +\returns +The integral value corresponding to the bits in \tcode{*this}. + +\pnum +\throws +Nothing. +\end{itemdescr} + \rSec2[simd.mask.nonmembers]{Non-member operations} \rSec3[simd.mask.binary]{\tcode{basic_simd_mask} binary operators} diff --git a/source/support.tex b/source/support.tex index 95d674aafb..4cbf9deb72 100644 --- a/source/support.tex +++ b/source/support.tex @@ -805,8 +805,9 @@ #define @\defnlibxname{cpp_lib_shared_ptr_weak_type}@ 201606L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_shared_timed_mutex}@ 201402L // also in \libheader{shared_mutex} #define @\defnlibxname{cpp_lib_shift}@ 202202L // also in \libheader{algorithm} -#define @\defnlibxname{cpp_lib_simd}@ 202502L // also in \libheader{simd} +#define @\defnlibxname{cpp_lib_simd}@ 202506L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_simd_complex}@ 202502L // also in \libheader{simd} +#define @\defnlibxname{cpp_lib_simd_permutations}@ 202506L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_smart_ptr_for_overwrite}@ 202002L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_smart_ptr_owner_equality}@ 202306L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_source_location}@ 201907L // freestanding, also in \libheader{source_location}