Skip to content

P3480R6 std::simd is a range #7998

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 340 additions & 0 deletions source/numerics.tex
Original file line number Diff line number Diff line change
Expand Up @@ -17187,6 +17187,262 @@
specialization \tcode{\exposid{overaligned-flag}<std::min(N1, N2)>}.
\end{itemdescr}

\rSec2[simd.iterator]{Class \exposid{simd-iterator}}
\begin{codeblock}
namespace std::datapar {
template<class V>
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}@<remove_const_t<V>>&) requires is_const_v<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}@<remove_const_t<V>>& i) requires is_const_v<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}
Expand All @@ -17198,6 +17454,14 @@
using value_type = T;
using mask_type = basic_simd_mask<sizeof(T), Abi>;
using abi_type = Abi;
using iterator = \exposid{simd-iterator}<basic_simd>;
using const_iterator = \exposid{simd-iterator}<const basic_simd>;

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 {}; }
Comment on lines +17457 to +17464
Copy link
Member

@Eisenwave Eisenwave Jun 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing that these are entirely defined within the synopsis, we should have some \indexlibrarymember macros above.

Same for basic_simd_mask.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have \libmember for inline indexing inside codeblocks. "grep" for examples.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The members of simd-iterator do not get indexed, right? (because it's an exposition-only type? OTOH its members are public API.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, looking at some more examples of indexing, there's a lot of index macros missing for [simd]. I guess I should add all those as editorial commit after the motions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at ranges.tex, the exposition-only iterators are fully indexed. So I guess I could do that as well.
I'll close this PR in favor of a single PR that includes all 4 simd motions ASAP.


static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@<T, Abi>> size {};

Expand Down Expand Up @@ -19084,6 +19348,14 @@
public:
using value_type = bool;
using abi_type = Abi;
using iterator = \exposid{simd-iterator}<basic_simd_mask>;
using const_iterator = \exposid{simd-iterator}<const basic_simd_mask>;

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}@<Bytes>, Abi>>
size {};
Expand All @@ -19095,6 +19367,8 @@
template<size_t UBytes, class UAbi>
constexpr explicit basic_simd_mask(const basic_simd_mask<UBytes, UAbi>&) noexcept;
template<class G> constexpr explicit basic_simd_mask(G&& gen) noexcept;
constexpr basic_simd_mask(const bitset<size()>& 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;
Expand All @@ -19109,6 +19383,10 @@
template<class U, class A>
constexpr explicit(sizeof(U) != Bytes) operator basic_simd<U, A>() const noexcept;

// \ref{simd.mask.namedconv}, \tcode{basic_simd_mask} named type convertors
constexpr bitset<size()> 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;
Expand Down Expand Up @@ -19241,6 +19519,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<size()>& 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}
Expand Down Expand Up @@ -19299,6 +19602,43 @@
\tcode{static_cast<U>(operator[]($i$))}.
\end{itemdescr}

\rSec3[simd.mask.namedconv]{\tcode{basic_simd_mask} named conversion operators}

\begin{itemdecl}
constexpr bitset<size()> to_bitset() const noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A \tcode{bitset<size()>} 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}
Expand Down
2 changes: 1 addition & 1 deletion source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@
#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_smart_ptr_for_overwrite}@ 202002L // also in \libheader{memory}
#define @\defnlibxname{cpp_lib_smart_ptr_owner_equality}@ 202306L // also in \libheader{memory}
Expand Down