29 Numerics library [numerics]

29.10 Data-parallel types [simd]

29.10.1 General [simd.general]

Subclause [simd] defines data-parallel types and operations on these types.
[Note 1: 
The intent is to support acceleration through data-parallel execution resources where available, such as SIMD registers and instructions or execution units driven by a common instruction decoder.
SIMD stands for “Single Instruction Stream – Multiple Data Stream”; it is defined in Flynn 1966[bib].
— end note]
The set of vectorizable types comprises
  • all standard integer types, character types, and the types float and double ([basic.fundamental]);
  • std​::​float16_t, std​::​float32_t, and std​::​float64_t if defined ([basic.extended.fp]); and
  • complex<T> where T is a vectorizable floating-point type.
The term data-parallel type refers to all enabled specializations of the basic_vec and basic_mask class templates.
A data-parallel object is an object of data-parallel type.
Each specialization of basic_vec or basic_mask is either enabled or disabled, as described in [simd.overview] and [simd.mask.overview].
A data-parallel type consists of one or more elements of an underlying vectorizable type, called the element type.
The number of elements is a constant for each data-parallel type and called the width of that type.
The elements in a data-parallel type are indexed from 0 to .
An element-wise operation applies a specified operation to the elements of one or more data-parallel objects.
Each such application is unsequenced with respect to the others.
A unary element-wise operation is an element-wise operation that applies a unary operation to each element of a data-parallel object.
A binary element-wise operation is an element-wise operation that applies a binary operation to corresponding elements of two data-parallel objects.
Given a basic_mask<Bytes, Abi> object mask, the selected indices signify the integers i in the range [0, mask.size()) for which mask[i] is true.
Given a data-parallel object data, the selected elements signify the elements data[i] for all selected indices i.
The conversion from an arithmetic type U to a vectorizable type T is value-preserving if all possible values of U can be represented with type T.

29.10.2 Exposition-only types, variables, and concepts [simd.expos]

using simd-size-type = see below; // exposition only template<size_t Bytes> using integer-from = see below; // exposition only template<class T, class Abi> constexpr simd-size-type simd-size-v = see below; // exposition only template<class T> constexpr size_t mask-element-size = see below; // exposition only template<class T> concept constexpr-wrapper-like = // exposition only convertible_to<T, decltype(T::value)> && equality_comparable_with<T, decltype(T::value)> && bool_constant<T() == T::value>::value && bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value; template<class T> using deduced-vec-t = see below; // exposition only template<class V, class T> using make-compatible-simd-t = see below; // exposition only template<class V> concept simd-vec-type = // exposition only same_as<V, basic_vec<typename V::value_type, typename V::abi_type>> && is_default_constructible_v<V>; template<class V> concept simd-mask-type = // exposition only same_as<V, basic_mask<mask-element-size<V>, typename V::abi_type>> && is_default_constructible_v<V>; template<class V> concept simd-floating-point = // exposition only simd-vec-type<V> && floating_point<typename V::value_type>; template<class V> concept simd-integral = // exposition only simd-vec-type<V> && integral<typename V::value_type>; template<class V> using simd-complex-value-type = typename V::value_type::value_type; // exposition only template<class V> concept simd-complex = // exposition only simd-vec-type<V> && same_as<typename V::value_type, complex<simd-complex-value-type<V>>>; template<class... Ts> concept math-floating-point = // exposition only (simd-floating-point<deduced-vec-t<Ts>> || ...); template<class... Ts> requires math-floating-point<Ts...> using math-common-simd-t = see below; // exposition only template<class BinaryOperation, class T> concept reduction-binary-operation = see below; // exposition only // [simd.expos.abi], simd ABI tags template<class T> using native-abi = see below; // exposition only template<class T, simd-size-type N> using deduce-abi-t = see below; // exposition only // [simd.flags], Load and store flags struct convert-flag; // exposition only struct aligned-flag; // exposition only template<size_t N> struct overaligned-flag; // exposition only

29.10.2.1 Exposition-only helpers [simd.expos.defn]

using simd-size-type = see below;
simd-size-type is an alias for a signed integer type.
template<size_t Bytes> using integer-from = see below;
integer-from<Bytes> is an alias for a signed integer type T such that sizeof(T) equals Bytes.
template<class T, class Abi> constexpr simd-size-type simd-size-v = see below;
simd-size-v<T, Abi> denotes the width of basic_vec<T, Abi> if the specialization basic_vec<T, Abi> is enabled, or 0 otherwise.
template<class T> constexpr size_t mask-element-size = see below;
mask-element-size<basic_mask<Bytes, Abi>> has the value Bytes.
template<class T> using deduced-vec-t = see below;
Let x denote an lvalue of type const T.
deduced-vec-t<T> is an alias for
  • decltype(x + x), if the type of x + x is an enabled specialization of basic_vec; otherwise
  • void.
template<class V, class T> using make-compatible-simd-t = see below;
Let x denote an lvalue of type const T.
make-compatible-simd-t<V, T> is an alias for
  • deduced-vec-t<T>, if that type is not void, otherwise
  • vec<decltype(x + x), V​::​size()>.
template<class... Ts> requires math-floating-point<Ts...> using math-common-simd-t = see below;
Let T0 denote Ts...[0].
Let T1 denote Ts...[1].
Let TRest denote a pack such that T0, T1, TRest... is equivalent to Ts....
Let math-common-simd-t<Ts...> be an alias for
  • deduced-vec-t<T0>, if sizeof...(Ts) equals 1; otherwise
  • common_type_t<deduced-vec-t<T0>, deduced-vec-t<T1>>, if sizeof...(Ts) equals 2 and math-floating-point<T0> && math-floating-point<T1> is true; otherwise
  • common_type_t<deduced-vec-t<T0>, T1>, if sizeof...(Ts) equals 2 and math-floating-​point<​T0> is true; otherwise
  • common_type_t<T0, deduced-vec-t<T1>>, if sizeof...(Ts) equals 2; otherwise
  • common_type_t<math-common-simd-t<T0, T1>, TRest...>, if math-common-simd-t<T0, T1> is valid and denotes a type; otherwise
  • common_type_t<math-common-simd-t<TRest...>, T0, T1>.
template<class BinaryOperation, class T> concept reduction-binary-operation = requires (const BinaryOperation binary_op, const vec<T, 1> v) { { binary_op(v, v) } -> same_as<vec<T, 1>>; };
Types BinaryOperation and T model reduction-binary-operation<BinaryOperation, T> only if:
  • BinaryOperation is a binary element-wise operation and the operation is commutative.
  • An object of type BinaryOperation can be invoked with two arguments of type basic_vec<T, Abi>, with unspecified ABI tag Abi, returning a basic_vec<T, Abi>.

29.10.2.2 simd ABI tags [simd.expos.abi]

template<class T> using native-abi = see below; template<class T, simd-size-type N> using deduce-abi-t = see below;
An ABI tag is a type that indicates a choice of size and binary representation for objects of data-parallel type.
[Note 1: 
The intent is for the size and binary representation to depend on the target architecture and compiler flags.
The ABI tag, together with a given element type, implies the width.
— end note]
[Note 2: 
The ABI tag is orthogonal to selecting the machine instruction set.
The selected machine instruction set limits the usable ABI tag types, though (see [simd.overview]).
The ABI tags enable users to safely pass objects of data-parallel type between translation unit boundaries (e.g., function calls or I/O).
— end note]
An implementation defines ABI tag types as necessary for the following aliases.
deduce-abi-t<T, N> is defined if
  • T is a vectorizable type,
  • N is greater than zero, and
  • N is not larger than an implementation-defined maximum.
The implementation-defined maximum for N is not smaller than 64 and can differ depending on T.
Where present, deduce-abi-t<T, N> names an ABI tag type such that
  • simd-size-v<T, deduce-abi-t<T, N>> equals N,
  • basic_vec<T, deduce-abi-t<T, N>> is enabled ([simd.overview]), and
  • basic_mask<sizeof(T), deduce-abi-t<integer-from<sizeof(T)>, N>> is enabled.
native-abi<T> is an implementation-defined alias for an ABI tag.
basic_vec<T, native-abi<T>> is an enabled specialization.
[Note 3: 
The intent is to use the ABI tag producing the most efficient data-parallel execution for the element type T on the currently targeted system.
For target architectures with ISA extensions, compiler flags can change the type of the native-abi<T> alias.
— end note]
[Example 1: 
Consider a target architecture supporting the ABI tags __simd128 and __simd256, where hardware support for __simd256 exists only for floating-point types.
The implementation therefore defines native-abi<T> as an alias for
  • __simd256 if T is a floating-point type, and
  • __simd128 otherwise.
— end example]

29.10.3 Header <simd> synopsis [simd.syn]

namespace std::simd { // [simd.traits], simd type traits template<class T, class U = typename T::value_type> struct alignment; template<class T, class U = typename T::value_type> constexpr size_t alignment_v = alignment<T, U>::value; template<class T, class V> struct rebind { using type = see below; }; template<class T, class V> using rebind_t = typename rebind<T, V>::type; template<simd-size-type N, class V> struct resize { using type = see below; }; template<simd-size-type N, class V> using resize_t = typename resize<N, V>::type; // [simd.flags], load and store flags template<class... Flags> struct flags; inline constexpr flags<> flag_default{}; inline constexpr flags<convert-flag> flag_convert{}; inline constexpr flags<aligned-flag> flag_aligned{}; template<size_t N> requires (has_single_bit(N)) constexpr flags<overaligned-flag<N>> flag_overaligned{}; // [simd.iterator], class template simd-iterator template<class V> class simd-iterator; // exposition only // [simd.class], class template basic_vec template<class T, class Abi = native-abi<T>> class basic_vec; template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>> using vec = basic_vec<T, deduce-abi-t<T, N>>; // [simd.mask.class], class template basic_mask template<size_t Bytes, class Abi = native-abi<integer-from<Bytes>>> class basic_mask; template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>> using mask = basic_mask<sizeof(T), deduce-abi-t<T, N>>; // [simd.loadstore], basic_vec load and store functions template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_load(R&& r, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_load(R&& r, const typename V::mask_type& k, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V unchecked_load(I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V unchecked_load(I first, iter_difference_t<I> n, const typename V::mask_type& k, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V unchecked_load(I first, S last, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V unchecked_load(I first, S last, const typename V::mask_type& k, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V partial_load(R&& r, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V partial_load(R&& r, const typename V::mask_type& k, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V partial_load(I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V partial_load(I first, iter_difference_t<I> n, const typename V::mask_type& k, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V partial_load(I first, S last, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V partial_load(I first, S last, const typename V::mask_type& k, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store( const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store( const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); // [simd.permute.static], permute by static index generator static constexpr simd-size-type zero_element = implementation-defined; static constexpr simd-size-type uninit_element = implementation-defined; template<simd-size-type N = see below, simd-vec-type V, class IdxMap> constexpr resize_t<N, V> permute(const V& v, IdxMap&& idxmap); template<simd-size-type N = see below, simd-mask-type M, class IdxMap> constexpr resize_t<N, M> permute(const M& v, IdxMap&& idxmap); // [simd.permute.dynamic], permute by dynamic index template<simd-vec-type V, simd-integral I> constexpr resize_t<I::size(), V> permute(const V& v, const I& indices); template<simd-mask-type M, simd-integral I> constexpr resize_t<I::size(), M> permute(const M& v, const I& indices); // [simd.permute.mask], permute by active mask bits template<simd-vec-type V> constexpr V compress(const V& v, const typename V::mask_type& selector); template<simd-mask-type M> constexpr M compress(const M& v, const type_identity_t<M>& selector); template<simd-vec-type V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); template<simd-mask-type M> constexpr M compress(const M& v, const type_identity_t<M>& selector, const typename V::value_type& fill_value); template<simd-vec-type V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); template<simd-mask-type M> constexpr M expand(const M& v, const type_identity_t<M>& selector, const M& original = {}); // [simd.permute.memory], permute to and from memory template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_gather_from(R&& in, const I& indices, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_gather_from(R&& in, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V partial_gather_from(R&& in, const I& indices, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V partial_gather_from(R&& in, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void unchecked_scatter_to(const V& v, R&& out, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void unchecked_scatter_to(const V& v, R&& out, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void partial_scatter_to(const V& v, R&& out, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void partial_scatter_to(const V& v, R&& out, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {}); // [simd.creation], basic_vec and basic_mask creation template<class T, class Abi> constexpr auto chunk(const basic_vec<typename T::value_type, Abi>& x) noexcept; template<class T, class Abi> constexpr auto chunk(const basic_mask<mask-element-size<T>, Abi>& x) noexcept; template<simd-size-type N, class T, class Abi> constexpr auto chunk(const basic_vec<T, Abi>& x) noexcept; template<simd-size-type N, size_t Bytes, class Abi> constexpr auto chunk(const basic_mask<Bytes, Abi>& x) noexcept; template<class T, class... Abis> constexpr basic_vec<T, deduce-abi-t<T, (basic_vec<T, Abis>::size() + ...)>> cat(const basic_vec<T, Abis>&...) noexcept; template<size_t Bytes, class... Abis> constexpr basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_mask<Bytes, Abis>::size() + ...)>> cat(const basic_mask<Bytes, Abis>&...) noexcept; // [simd.mask.reductions], basic_mask reductions template<size_t Bytes, class Abi> constexpr bool all_of(const basic_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr bool any_of(const basic_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr bool none_of(const basic_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr simd-size-type reduce_count(const basic_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr simd-size-type reduce_min_index(const basic_mask<Bytes, Abi>&); template<size_t Bytes, class Abi> constexpr simd-size-type reduce_max_index(const basic_mask<Bytes, Abi>&); constexpr bool all_of(same_as<bool> auto) noexcept; constexpr bool any_of(same_as<bool> auto) noexcept; constexpr bool none_of(same_as<bool> auto) noexcept; constexpr simd-size-type reduce_count(same_as<bool> auto) noexcept; constexpr simd-size-type reduce_min_index(same_as<bool> auto); constexpr simd-size-type reduce_max_index(same_as<bool> auto); // [simd.reductions], basic_vec reductions template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce(const basic_vec<T, Abi>&, BinaryOperation = {}); template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce( const basic_vec<T, Abi>& x, const typename basic_vec<T, Abi>::mask_type& mask, BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below); template<class T, class Abi> constexpr T reduce_min(const basic_vec<T, Abi>&) noexcept; template<class T, class Abi> constexpr T reduce_min(const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept; template<class T, class Abi> constexpr T reduce_max(const basic_vec<T, Abi>&) noexcept; template<class T, class Abi> constexpr T reduce_max(const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept; // [simd.alg], algorithms template<class T, class Abi> constexpr basic_vec<T, Abi> min(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept; template<class T, class Abi> constexpr basic_vec<T, Abi> max(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept; template<class T, class Abi> constexpr pair<basic_vec<T, Abi>, basic_vec<T, Abi>> minmax(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept; template<class T, class Abi> constexpr basic_vec<T, Abi> clamp(const basic_vec<T, Abi>& v, const basic_vec<T, Abi>& lo, const basic_vec<T, Abi>& hi); template<class T, class U> constexpr auto select(bool c, const T& a, const U& b) -> remove_cvref_t<decltype(c ? a : b)>; template<size_t Bytes, class Abi, class T, class U> constexpr auto select(const basic_mask<Bytes, Abi>& c, const T& a, const U& b) noexcept -> decltype(simd-select-impl(c, a, b)); // [simd.math], mathematical functions template<math-floating-point V> constexpr deduced-vec-t<V> acos(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> asin(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> atan(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x); template<math-floating-point V> constexpr deduced-vec-t<V> cos(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> sin(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tan(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> acosh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> asinh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> atanh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> cosh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> sinh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tanh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> exp(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> exp2(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> expm1(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> frexp(const V& value, rebind_t<int, deduced-vec-t<V>>* exp); template<math-floating-point V> constexpr rebind_t<int, deduced-vec-t<V>> ilogb(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> ldexp(const V& x, const rebind_t<int, deduced-vec-t<V>>& exp); template<math-floating-point V> constexpr deduced-vec-t<V> log(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log10(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log1p(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log2(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> logb(const V& x); template<class T, class Abi> constexpr basic_vec<T, Abi> modf(const type_identity_t<basic_vec<T, Abi>>& value, basic_vec<T, Abi>* iptr); template<math-floating-point V> constexpr deduced-vec-t<V> scalbn(const V& x, const rebind_t<int, deduced-vec-t<V>>& n); template<math-floating-point V> constexpr deduced-vec-t<V> scalbln( const V& x, const rebind_t<long int, deduced-vec-t<V>>& n); template<math-floating-point V> constexpr deduced-vec-t<V> cbrt(const V& x); template<signed_integral T, class Abi> constexpr basic_vec<T, Abi> abs(const basic_vec<T, Abi>& j); template<math-floating-point V> constexpr deduced-vec-t<V> abs(const V& j); template<math-floating-point V> constexpr deduced-vec-t<V> fabs(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-vec-t<V> sqrt(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> erf(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> erfc(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> lgamma(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tgamma(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> ceil(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> floor(const V& x); template<math-floating-point V> deduced-vec-t<V> nearbyint(const V& x); template<math-floating-point V> deduced-vec-t<V> rint(const V& x); template<math-floating-point V> rebind_t<long int, deduced-vec-t<V>> lrint(const V& x); template<math-floating-point V> rebind_t<long long int, V> llrint(const deduced-vec-t<V>& x); template<math-floating-point V> constexpr deduced-vec-t<V> round(const V& x); template<math-floating-point V> constexpr rebind_t<long int, deduced-vec-t<V>> lround(const V& x); template<math-floating-point V> constexpr rebind_t<long long int, deduced-vec-t<V>> llround(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> trunc(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remquo(const V0& x, const V1& y, rebind_t<int, math-common-simd-t<V0, V1>>* quo); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> lerp(const V0& a, const V1& b, const V2& t) noexcept; template<math-floating-point V> constexpr rebind_t<int, deduced-vec-t<V>> fpclassify(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isfinite(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isinf(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isnan(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isnormal(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type signbit(const V& x); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreaterequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isless(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isunordered(const V0& x, const V1& y); template<math-floating-point V> deduced-vec-t<V> assoc_laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x); template<math-floating-point V> deduced-vec-t<V> assoc_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x); template<class V0, class V1> math-common-simd-t<V0, V1> beta(const V0& x, const V1& y); template<math-floating-point V> deduced-vec-t<V> comp_ellint_1(const V& k); template<math-floating-point V> deduced-vec-t<V> comp_ellint_2(const V& k); template<class V0, class V1> math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi); template<class V0, class V1, class V2> math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi); template<math-floating-point V> deduced-vec-t<V> expint(const V& x); template<math-floating-point V> deduced-vec-t<V> hermite(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const V& x); template<math-floating-point V> deduced-vec-t<V> riemann_zeta(const V& x); template<math-floating-point V> deduced-vec-t<V> sph_bessel( const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> sph_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& theta); template<math-floating-point V> deduced-vec-t<V> sph_neumann(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); // [simd.bit], bit manipulation template<simd-vec-type V> constexpr V byteswap(const V& v) noexcept; template<simd-vec-type V> constexpr V bit_ceil(const V& v) noexcept; template<simd-vec-type V> constexpr V bit_floor(const V& v) noexcept; template<simd-vec-type V> constexpr typename V::mask_type has_single_bit(const V& v) noexcept; template<simd-vec-type V0, simd-vec-type V1> constexpr V0 rotl(const V0& v, const V1& s) noexcept; template<simd-vec-type V> constexpr V rotl(const V& v, int s) noexcept; template<simd-vec-type V0, simd-vec-type V1> constexpr V0 rotr(const V0& v, const V1& s) noexcept; template<simd-vec-type V> constexpr V rotr(const V& v, int s) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> bit_width(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_zero(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_one(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_zero(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_one(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> popcount(const V& v) noexcept; // [simd.complex.math], vec complex math template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> real(const V&) noexcept; template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> imag(const V&) noexcept; template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> abs(const V&); template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> arg(const V&); template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> norm(const V&); template<simd-complex V> constexpr V conj(const V&); template<simd-complex V> constexpr V proj(const V&); template<simd-complex V> constexpr V exp(const V& v); template<simd-complex V> constexpr V log(const V& v); template<simd-complex V> constexpr V log10(const V& v); template<simd-complex V> constexpr V sqrt(const V& v); template<simd-complex V> constexpr V sin(const V& v); template<simd-complex V> constexpr V asin(const V& v); template<simd-complex V> constexpr V cos(const V& v); template<simd-complex V> constexpr V acos(const V& v); template<simd-complex V> constexpr V tan(const V& v); template<simd-complex V> constexpr V atan(const V& v); template<simd-complex V> constexpr V sinh(const V& v); template<simd-complex V> constexpr V asinh(const V& v); template<simd-complex V> constexpr V cosh(const V& v); template<simd-complex V> constexpr V acosh(const V& v); template<simd-complex V> constexpr V tanh(const V& v); template<simd-complex V> constexpr V atanh(const V& v); template<simd-floating-point V> rebind_t<complex<typename V::value_type>, V> polar(const V& x, const V& y = {}); template<simd-complex V> constexpr V pow(const V& x, const V& y); } namespace std { // See [simd.alg], algorithms using simd::min; using simd::max; using simd::minmax; using simd::clamp; // See [simd.math], mathematical functions using simd::acos; using simd::asin; using simd::atan; using simd::atan2; using simd::cos; using simd::sin; using simd::tan; using simd::acosh; using simd::asinh; using simd::atanh; using simd::cosh; using simd::sinh; using simd::tanh; using simd::exp; using simd::exp2; using simd::expm1; using simd::frexp; using simd::ilogb; using simd::ldexp; using simd::log; using simd::log10; using simd::log1p; using simd::log2; using simd::logb; using simd::modf; using simd::scalbn; using simd::scalbln; using simd::cbrt; using simd::abs; using simd::abs; using simd::fabs; using simd::hypot; using simd::pow; using simd::sqrt; using simd::erf; using simd::erfc; using simd::lgamma; using simd::tgamma; using simd::ceil; using simd::floor; using simd::nearbyint; using simd::rint; using simd::lrint; using simd::llrint; using simd::round; using simd::lround; using simd::llround; using simd::trunc; using simd::fmod; using simd::remainder; using simd::remquo; using simd::copysign; using simd::nextafter; using simd::fdim; using simd::fmax; using simd::fmin; using simd::fma; using simd::lerp; using simd::fpclassify; using simd::isfinite; using simd::isinf; using simd::isnan; using simd::isnormal; using simd::signbit; using simd::isgreater; using simd::isgreaterequal; using simd::isless; using simd::islessequal; using simd::islessgreater; using simd::isunordered; using simd::assoc_laguerre; using simd::assoc_legendre; using simd::beta; using simd::comp_ellint_1; using simd::comp_ellint_2; using simd::comp_ellint_3; using simd::cyl_bessel_i; using simd::cyl_bessel_j; using simd::cyl_bessel_k; using simd::cyl_neumann; using simd::ellint_1; using simd::ellint_2; using simd::ellint_3; using simd::expint; using simd::hermite; using simd::laguerre; using simd::legendre; using simd::riemann_zeta; using simd::sph_bessel; using simd::sph_legendre; using simd::sph_neumann; // See [simd.bit], bit manipulation using simd::byteswap; using simd::bit_ceil; using simd::bit_floor; using simd::has_single_bit; using simd::rotl; using simd::rotr; using simd::bit_width; using simd::countl_zero; using simd::countl_one; using simd::countr_zero; using simd::countr_one; using simd::popcount; // See [simd.complex.math], vec complex math using simd::real; using simd::imag; using simd::arg; using simd::norm; using simd::conj; using simd::proj; using simd::polar; }

29.10.4 vec type traits [simd.traits]

template<class T, class U = typename T::value_type> struct alignment { see below };
alignment<T, U> has a member value if and only if
  • T is a specialization of basic_mask and U is bool, or
  • T is a specialization of basic_vec and U is a vectorizable type.
If value is present, the type alignment<T, U> is a BinaryTypeTrait with a base characteristic of integral_constant<size_t, N> for some unspecified N ([simd.ctor], [simd.loadstore]).
[Note 1: 
value identifies the alignment restrictions on pointers used for (converting) loads and stores for the given type T on arrays of type U.
— end note]
The behavior of a program that adds specializations for alignment is undefined.
template<class T, class V> struct rebind { using type = see below; };
The member type is present if and only if
  • V is a data-parallel type,
  • T is a vectorizable type, and
  • deduce-abi-t<T, V​::​size()> has a member type type.
If V is a specialization of basic_vec, let Abi1 denote an ABI tag such that basic_vec<T, Abi1>​::​​size() equals V​::​size().
If V is a specialization of basic_mask, let Abi1 denote an ABI tag such that basic_mask<sizeof(T), Abi1>​::​​size() equals V​::​size().
Where present, the member typedef type names basic_vec<T, Abi1> if V is a specialization of basic_vec or basic_mask<sizeof(T), Abi1> if V is a specialization of basic_mask.
template<simd-size-type N, class V> struct resize { using type = see below; };
Let T denote
  • typename V​::​value_type if V is a specialization of basic_vec,
  • otherwise integer-from<mask-element-size<V>> if V is a specialization of basic_mask.
The member type is present if and only if
  • V is a data-parallel type, and
  • deduce-abi-t<T, N> has a member type type.
If V is a specialization of basic_vec, let Abi1 denote an ABI tag such that basic_vec<T, Abi1>​::​​size() equals N.
If V is a specialization of basic_mask, let Abi1 denote an ABI tag such that basic_mask<sizeof(T), Abi1>​::​size() equals N.
Where present, the member typedef type names basic_vec<T, Abi1> if V is a specialization of basic_vec or basic_mask<sizeof(T), Abi1> if V is a specialization of basic_mask.

29.10.5 Load and store flags [simd.flags]

29.10.5.1 Class template flags overview [simd.flags.overview]

namespace std::simd { template<class... Flags> struct flags { // [simd.flags.oper], flags operators template<class... Other> friend consteval auto operator|(flags, flags<Other...>); }; }
[Note 1: 
The class template flags acts like an integer bit-flag for types.
— end note]
Constraints: Every type in the parameter pack Flags is one of convert-flag, aligned-flag, or overaligned-​flag<N>.

29.10.5.2 flags operators [simd.flags.oper]

template<class... Other> friend consteval auto operator|(flags a, flags<Other...> b);
Returns: A default-initialized object of type flags<Flags2...> for some Flags2 where every type in Flags2 is present either in template parameter pack Flags or in template parameter pack Other, and every type in template parameter packs Flags and Other is present in Flags2.
If the packs Flags and Other contain two different specializations overaligned-flag<N1> and overaligned-flag<N2>, Flags2 is not required to contain the specialization overaligned-flag<std​::​min(N1, N2)>.

29.10.6 Class template simd-iterator [simd.iterator]

namespace std::simd { template<class V> class simd-iterator { // exposition only V* data_ = nullptr; // exposition only simd-size-type offset_ = 0; // exposition only constexpr simd-iterator(V& d, simd-size-type off) noexcept; // exposition only public: using value_type = typename V::value_type; using iterator_category = input_iterator_tag; using iterator_concept = random_access_iterator_tag; using difference_type = simd-size-type; constexpr simd-iterator() = default; constexpr simd-iterator(const simd-iterator&) = default; constexpr simd-iterator& operator=(const simd-iterator&) = default; constexpr simd-iterator(const simd-iterator<remove_const_t<V>>&) requires is_const_v<V>; constexpr value_type operator*() const; constexpr simd-iterator& operator++(); constexpr simd-iterator operator++(int); constexpr simd-iterator& operator--(); constexpr simd-iterator operator--(int); constexpr simd-iterator& operator+=(difference_type n); constexpr simd-iterator& operator-=(difference_type n); constexpr value_type operator[](difference_type n) const; friend constexpr bool operator==(simd-iterator a, simd-iterator b) = default; friend constexpr bool operator==(simd-iterator a, default_sentinel_t) noexcept; friend constexpr auto operator<=>(simd-iterator a, simd-iterator b); friend constexpr simd-iterator operator+(simd-iterator i, difference_type n); friend constexpr simd-iterator operator+(difference_type n, simd-iterator i); friend constexpr simd-iterator operator-(simd-iterator i, difference_type n); friend constexpr difference_type operator-(simd-iterator a, simd-iterator b); friend constexpr difference_type operator-(simd-iterator i, default_sentinel_t) noexcept; friend constexpr difference_type operator-(default_sentinel_t, simd-iterator i) noexcept; }; }
constexpr simd-iterator(V& d, simd-size-type off) noexcept;
Effects: Initializes data_ with addressof(d) and offset_ with off.
constexpr simd-iterator(const simd-iterator<remove_const_t<V>>& i) requires is_const_v<V>;
Effects: Initializes data_ with i.data_ and offset_ with i.offset_.
constexpr value_type operator*() const;
Effects: Equivalent to: return (*data_)[offset_];
constexpr simd-iterator& operator++();
Effects: Equivalent to: return *this += 1;
constexpr simd-iterator operator++(int);
Effects: Equivalent to: simd-iterator tmp = *this; *this += 1; return tmp;
constexpr simd-iterator& operator--();
Effects: Equivalent to: return *this -= 1;
constexpr simd-iterator operator--(int);
Effects: Equivalent to: simd-iterator tmp = *this; *this -= 1; return tmp;
constexpr simd-iterator& operator+=(difference_type n);
Preconditions: offset_ + n is in the range [0, V​::​size()].
Effects: Equivalent to: offset_ += n; return *this;
constexpr simd-iterator& operator-=(difference_type n);
Preconditions: offset_ - n is in the range [0, V​::​size()].
Effects: Equivalent to: offset_ -= n; return *this;
constexpr value_type operator[](difference_type n) const;
Effects: Equivalent to: return (*data_)[offset_ + n];
friend constexpr bool operator==(simd-iterator i, default_sentinel_t) noexcept;
Effects: Equivalent to: return i.offset_ == V​::​size();
friend constexpr auto operator<=>(simd-iterator a, simd-iterator b);
Preconditions: a.data_ == b.data_ is true.
Effects: Equivalent to: return a.offset_ <=> b.offset_;
friend constexpr simd-iterator operator+(simd-iterator i, difference_type n); friend constexpr simd-iterator operator+(difference_type n, simd-iterator i);
Effects: Equivalent to: return i += n;
friend constexpr simd-iterator operator-(simd-iterator i, difference_type n);
Effects: Equivalent to: return i -= n;
friend constexpr difference_type operator-(simd-iterator a, simd-iterator b);
Preconditions: a.data_ == b.data_ is true.
Effects: Equivalent to: return a.offset_ - b.offset_;
friend constexpr difference_type operator-(simd-iterator i, default_sentinel_t) noexcept;
Effects: Equivalent to: return i.offset_ - V​::​size();
friend constexpr difference_type operator-(default_sentinel_t, simd-iterator i) noexcept;
Effects: Equivalent to: return V​::​size() - i.offset_;

29.10.7 Class template basic_vec [simd.class]

29.10.7.1 Class template basic_vec overview [simd.overview]

namespace std::simd { template<class T, class Abi> class basic_vec { public: using value_type = T; using mask_type = basic_mask<sizeof(T), Abi>; using abi_type = Abi; using iterator = simd-iterator<basic_vec>; using const_iterator = simd-iterator<const basic_vec>; 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<simd-size-type, simd-size-v<T, Abi>> size {}; constexpr basic_vec() noexcept = default; // [simd.ctor], basic_vec constructors template<class U> constexpr explicit(see below) basic_vec(U&& value) noexcept; template<class U, class UAbi> constexpr explicit(see below) basic_vec(const basic_vec<U, UAbi>&) noexcept; template<class G> constexpr explicit basic_vec(G&& gen) noexcept; template<class R, class... Flags> constexpr basic_vec(R&& range, flags<Flags...> = {}); template<class R, class... Flags> constexpr basic_vec(R&& range, const mask_type& mask, flags<Flags...> = {}); template<simd-floating-point V> constexpr explicit(see below) basic_vec(const V& reals, const V& imags = {}) noexcept; // [simd.subscr], basic_vec subscript operators constexpr value_type operator[](simd-size-type) const; template<simd-integral I> constexpr resize_t<I::size(), basic_vec> operator[](const I& indices) const; // [simd.unary], basic_vec unary operators constexpr basic_vec& operator++() noexcept; constexpr basic_vec operator++(int) noexcept; constexpr basic_vec& operator--() noexcept; constexpr basic_vec operator--(int) noexcept; constexpr mask_type operator!() const noexcept; constexpr basic_vec operator~() const noexcept; constexpr basic_vec operator+() const noexcept; constexpr basic_vec operator-() const noexcept; // [simd.binary], basic_vec binary operators friend constexpr basic_vec operator+(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator-(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator*(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator/(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator%(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator&(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator|(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator^(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator<<(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator>>(const basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec operator<<(const basic_vec&, simd-size-type) noexcept; friend constexpr basic_vec operator>>(const basic_vec&, simd-size-type) noexcept; // [simd.cassign], basic_vec compound assignment friend constexpr basic_vec& operator+=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator-=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator*=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator/=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator%=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator&=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator|=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator^=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator<<=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator>>=(basic_vec&, const basic_vec&) noexcept; friend constexpr basic_vec& operator<<=(basic_vec&, simd-size-type) noexcept; friend constexpr basic_vec& operator>>=(basic_vec&, simd-size-type) noexcept; // [simd.comparison], basic_vec compare operators friend constexpr mask_type operator==(const basic_vec&, const basic_vec&) noexcept; friend constexpr mask_type operator!=(const basic_vec&, const basic_vec&) noexcept; friend constexpr mask_type operator>=(const basic_vec&, const basic_vec&) noexcept; friend constexpr mask_type operator<=(const basic_vec&, const basic_vec&) noexcept; friend constexpr mask_type operator>(const basic_vec&, const basic_vec&) noexcept; friend constexpr mask_type operator<(const basic_vec&, const basic_vec&) noexcept; // [simd.complex.access], basic_vec complex-value accessors constexpr auto real() const noexcept; constexpr auto imag() const noexcept; template<simd-floating-point V> constexpr void real(const V& v) noexcept; template<simd-floating-point V> constexpr void imag(const V& v) noexcept; // [simd.cond], basic_vec exposition only conditional operators friend constexpr basic_vec simd-select-impl( // exposition only const mask_type&, const basic_vec&, const basic_vec&) noexcept; }; template<class R, class... Ts> basic_vec(R&& r, Ts...) -> see below; }
Every specialization of basic_vec is a complete type.
The specialization of basic_vec<T, Abi> is
  • enabled, if T is a vectorizable type, and there exists value N in the range [1, 64], such that Abi is deduce-abi-t<T, N>,
  • otherwise, disabled, if T is not a vectorizable type,
  • otherwise, it is implementation-defined if such a specialization is enabled.
If basic_vec<T, Abi> is disabled, then the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment.
In addition only the value_type, abi_type, and mask_type members are present.
If basic_vec<T, Abi> is enabled, then basic_vec<T, Abi> is trivially copyable, default-initialization of an object of such a type default-initializes all elements, and value-initialization value-initializes all elements ([dcl.init.general]).
Recommended practice: Implementations should support implicit conversions between specializations of basic_vec and appropriate implementation-defined types.
[Note 1: 
Appropriate types are non-standard vector types which are available in the implementation.
— end note]

29.10.7.2 basic_vec constructors [simd.ctor]

template<class U> constexpr explicit(see below) basic_vec(U&& value) noexcept;
Let From denote the type remove_cvref_t<U>.
Constraints: value_type satisfies constructible_from<U>.
Effects: Initializes each element to the value of the argument after conversion to value_type.
Remarks: The expression inside explicit evaluates to false if and only if U satisfies convertible_to<value_type>, and either
template<class U, class UAbi> constexpr explicit(see below) basic_vec(const basic_vec<U, UAbi>& x) noexcept;
Constraints: simd-size-v<U, UAbi> == size() is true.
Effects: Initializes the element with static_cast<T>(x[i]) for all i in the range of [0, size()).
Remarks: The expression inside explicit evaluates to true if either
  • the conversion from U to value_type is not value-preserving, or
  • both U and value_type are integral types and the integer conversion rank ([conv.rank]) of U is greater than the integer conversion rank of value_type, or
  • both U and value_type are floating-point types and the floating-point conversion rank ([conv.rank]) of U is greater than the floating-point conversion rank of value_type.
template<class G> constexpr explicit basic_vec(G&& gen);
Let From denote the type decltype(gen(integral_constant<simd-size-type, i>())).
Constraints: From satisfies convertible_to<value_type> for all i in the range of [0, size()).
In addition, for all i in the range of [0, size()), if From is an arithmetic type, conversion from From to value_type is value-preserving.
Effects: Initializes the element with static_cast<value_type>(gen(integral_constant<simd-​size-​type, i>())) for all i in the range of [0, size()).
Remarks: gen is invoked exactly once for each i, in increasing order of i.
template<class R, class... Flags> constexpr basic_vec(R&& r, flags<Flags...> = {}); template<class R, class... Flags> constexpr basic_vec(R&& r, const mask_type& mask, flags<Flags...> = {});
Let mask be mask_type(true) for the overload with no mask parameter.
Constraints:
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from ranges​::​range_value_t<R> to value_type is value-preserving.
Preconditions:
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(r) points to storage aligned by alignment_v<basic_vec, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(r) points to storage aligned by N.
Effects: Initializes the element with mask[i] ? static_cast<T>(​ranges​::​​data(r)[i]) : T() for all i in the range of [0, size()).
template<class R, class... Ts> basic_vec(R&& r, Ts...) -> see below;
Constraints:
Remarks: The deduced type is equivalent to vec<ranges​::​range_value_t<R>, ranges​::​size(r)>.
template<simd-floating-point V> constexpr explicit(see below) basic_vec(const V& reals, const V& imags = {}) noexcept;
Constraints:
Effects: Initializes the element with value_type(reals[i], imags[i]) for all i in the range [0, size()).
Remarks: The expression inside explicit evaluates to false if and only if the floating-point conversion rank of T​::​value_type is greater than or equal to the floating-point conversion rank of V​::​value_type.

29.10.7.3 basic_vec subscript operator [simd.subscr]

constexpr value_type operator[](simd-size-type i) const;
Preconditions: i >= 0 && i < size() is true.
Returns: The value of the element.
Throws: Nothing.
template<simd-integral I> constexpr resize_t<I::size(), basic_vec> operator[](const I& indices) const;
Effects: Equivalent to: return permute(*this, indices);

29.10.7.4 basic_vec unary operators [simd.unary]

Effects in [simd.unary] are applied as unary element-wise operations.
constexpr basic_vec& operator++() noexcept;
Constraints: requires (value_type a) { ++a; } is true.
Effects: Increments every element by one.
Returns: *this.
constexpr basic_vec operator++(int) noexcept;
Constraints: requires (value_type a) { a++; } is true.
Effects: Increments every element by one.
Returns: A copy of *this before incrementing.
constexpr basic_vec& operator--() noexcept;
Constraints: requires (value_type a) { --a; } is true.
Effects: Decrements every element by one.
Returns: *this.
constexpr basic_vec operator--(int) noexcept;
Constraints: requires (value_type a) { a--; } is true.
Effects: Decrements every element by one.
Returns: A copy of *this before decrementing.
constexpr mask_type operator!() const noexcept;
Constraints: requires (const value_type a) { !a; } is true.
Returns: A basic_mask object with the element set to !operator[](i) for all i in the range of [0, size()).
constexpr basic_vec operator~() const noexcept;
Constraints: requires (const value_type a) { ~a; } is true.
Returns: A basic_vec object with the element set to ~operator[](i) for all i in the range of [0, size()).
constexpr basic_vec operator+() const noexcept;
Constraints: requires (const value_type a) { +a; } is true.
Returns: *this.
constexpr basic_vec operator-() const noexcept;
Constraints: requires (const value_type a) { -a; } is true.
Returns: A basic_vec object where the element is initialized to -operator[](i) for all i in the range of [0, size()).

29.10.8 basic_vec non-member operations [simd.nonmembers]

29.10.8.1 basic_vec binary operators [simd.binary]

friend constexpr basic_vec operator+(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator-(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator*(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator/(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator%(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator&(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator|(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator^(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator<<(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec operator>>(const basic_vec& lhs, const basic_vec& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Returns: A basic_vec object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.
friend constexpr basic_vec operator<<(const basic_vec& v, simd-size-type n) noexcept; friend constexpr basic_vec operator>>(const basic_vec& v, simd-size-type n) noexcept;
Let op be the operator.
Constraints: requires (value_type a, simd-size-type b) { a op b; } is true.
Returns: A basic_vec object where the element is initialized to the result of applying op to v[i] and n for all i in the range of [0, size()).

29.10.8.2 basic_vec compound assignment [simd.cassign]

friend constexpr basic_vec& operator+=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator-=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator*=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator/=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator%=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator&=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator|=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator^=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator<<=(basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr basic_vec& operator>>=(basic_vec& lhs, const basic_vec& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Effects: These operators apply the indicated operator to lhs and rhs as an element-wise operation.
Returns: lhs.
friend constexpr basic_vec& operator<<=(basic_vec& lhs, simd-size-type n) noexcept; friend constexpr basic_vec& operator>>=(basic_vec& lhs, simd-size-type n) noexcept;
Let op be the operator.
Constraints: requires (value_type a, simd-size-type b) { a op b; } is true.
Effects: Equivalent to: return operator op (lhs, basic_vec(n));

29.10.8.3 basic_vec compare operators [simd.comparison]

friend constexpr mask_type operator==(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr mask_type operator!=(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr mask_type operator>=(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr mask_type operator<=(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr mask_type operator>(const basic_vec& lhs, const basic_vec& rhs) noexcept; friend constexpr mask_type operator<(const basic_vec& lhs, const basic_vec& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Returns: A basic_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.8.4 vec complex accessors [simd.complex.access]

constexpr auto real() const noexcept; constexpr auto imag() const noexcept;
Constraints: simd-complex<basic_vec> is modeled.
Returns: An object of type rebind_t<typename T​::​value_type, basic_vec> where the element is initialized to the result of cmplx-func(operator[](i)) for all i in the range [0, size()), where cmplx-func is the corresponding function from <complex>.
template<simd-floating-point V> constexpr void real(const V& v) noexcept; template<simd-floating-point V> constexpr void imag(const V& v) noexcept;
Constraints:
Effects: Replaces each element of the basic_vec object such that the element is replaced with value_type(v[i], operator[](i).imag()) or value_type(operator[](i).real(), v[i]) for real and imag respectively, for all i in the range [0, size()).

29.10.8.5 basic_vec exposition only conditional operators [simd.cond]

friend constexpr basic_vec simd-select-impl(const mask_type& mask, const basic_vec& a, const basic_vec& b) noexcept;
Returns: A basic_vec object where the element equals mask[i] ? a[i] : b[i] for all i in the range of [0, size()).

29.10.8.6 basic_vec reductions [simd.reductions]

template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce(const basic_vec<T, Abi>& x, BinaryOperation binary_op = {});
Constraints: BinaryOperation models reduction-binary-operation<T>.
Preconditions: binary_op does not modify x.
Returns: GENERALIZED_SUM(binary_op, vec<T, 1>(x[0]), , vec<T, 1>(x[x.size() - 1]))[0] ([numerics.defns]).
Throws: Any exception thrown from binary_op.
template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce( const basic_vec<T, Abi>& x, const typename basic_vec<T, Abi>::mask_type& mask, BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below);
Constraints:
  • BinaryOperation models reduction-binary-operation<T>.
  • An argument for identity_element is provided for the invocation, unless BinaryOperation is one of plus<>, multiplies<>, bit_and<>, bit_or<>, or bit_xor<>.
Preconditions:
  • binary_op does not modify x.
  • For all finite values y representable by T, the results of y == binary_op(vec<T, 1>(identity_element), vec<T, 1>(y))[0] and y == binary_op(vec<T, 1>(y), vec<T, 1>(identity_element))[0] are true.
Returns: If none_of(mask) is true, returns identity_element.
Otherwise, returns GENERALIZED_SUM(binary_op, vec<T, 1>(x[]), , vec<T, 1>(x[]))[0] where are the selected indices of mask.
Throws: Any exception thrown from binary_op.
Remarks: The default argument for identity_element is equal to
  • T() if BinaryOperation is plus<>,
  • T(1) if BinaryOperation is multiplies<>,
  • T(~T()) if BinaryOperation is bit_and<>,
  • T() if BinaryOperation is bit_or<>, or
  • T() if BinaryOperation is bit_xor<>.
template<class T, class Abi> constexpr T reduce_min(const basic_vec<T, Abi>& x) noexcept;
Constraints: T models totally_ordered.
Returns: The value of an element x[j] for which x[i] < x[j] is false for all i in the range of [0, basic_vec<T, Abi>​::​size()).
template<class T, class Abi> constexpr T reduce_min( const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept;
Constraints: T models totally_ordered.
Returns: If none_of(mask) is true, returns numeric_limits<T>​::​max().
Otherwise, returns the value of a selected element x[j] for which x[i] < x[j] is false for all selected indices i of mask.
template<class T, class Abi> constexpr T reduce_max(const basic_vec<T, Abi>& x) noexcept;
Constraints: T models totally_ordered.
Returns: The value of an element x[j] for which x[j] < x[i] is false for all i in the range of [0, basic_vec<T, Abi>​::​size()).
template<class T, class Abi> constexpr T reduce_max( const basic_vec<T, Abi>&, const typename basic_vec<T, Abi>::mask_type&) noexcept;
Constraints: T models totally_ordered.
Returns: If none_of(mask) is true, returns numeric_limits<V​::​value_type>​::​lowest().
Otherwise, returns the value of a selected element x[j] for which x[j] < x[i] is false for all selected indices i of mask.

29.10.8.7 basic_vec load and store functions [simd.loadstore]

template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_load(R&& r, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_load(R&& r, const typename V::mask_type& mask, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V unchecked_load(I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V unchecked_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V unchecked_load(I first, S last, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V unchecked_load(I first, S last, const typename V::mask_type& mask, flags<Flags...> f = {});
Let
  • mask be V​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<const iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates: If ranges​::​size(r) is a constant expression then ranges​::​size(r)  ≥  V​::​size().
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • ranges​::​size(r)  ≥  V​::​size()
Effects: Equivalent to: return partial_load<V>(r, mask, f);
Remarks: The default argument for template parameter V is basic_vec<ranges​::​range_value_t<R>>.
template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V partial_load(R&& r, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V partial_load(R&& r, const typename V::mask_type& mask, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V partial_load(I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V partial_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V partial_load(I first, S last, flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V partial_load(I first, S last, const typename V::mask_type& mask, flags<Flags...> f = {});
Let
  • mask be V​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<const iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type,
  • same_as<remove_cvref_t<V>, V> is true,
  • V is an enabled specialization of basic_vec, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from ranges​::​range_value_t<R> to V​::​value_type is value-preserving.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(r) points to storage aligned by alignment_v<V, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(r) points to storage aligned by N.
Effects: Initializes the element with
mask[i] && i < ranges​::​size(r) ? static_cast<T>(​ranges​::​data(r)[i]) : T() for all i in the range of [0, V​::​size()).
Remarks: The default argument for template parameter V is basic_vec<ranges​::​range_value_t<R>>.
template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, R&& r, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void unchecked_store(const basic_vec<T, Abi>& v, I first, S last, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
Let
  • mask be basic_vec<T, Abi>​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates: If ranges​::​size(r) is a constant expression then ranges​::​size(r)  ≥  simd-size-v<T, Abi>.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • ranges​::​size(r)  ≥  simd-size-v<T, Abi>
Effects: Equivalent to: partial_store(v, r, mask, f).
template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r, flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void partial_store(const basic_vec<T, Abi>& v, R&& r, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last, flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void partial_store(const basic_vec<T, Abi>& v, I first, S last, const typename basic_vec<T, Abi>::mask_type& mask, flags<Flags...> f = {});
Let
  • mask be basic_vec<T, Abi>​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from T to ranges​::​range_value_t<R> is value-preserving.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(r) points to storage aligned by alignment_v<basic_vec<T, Abi>, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(r) points to storage aligned by N.
Effects: For all i in the range of [0, basic_vec<T, Abi>​::​size()), if mask[i] && i < ranges​::​​size(r) is true, evaluates ranges​::​data(r)[i] = v[i].

29.10.8.8 vec static permute [simd.permute.static]

template<simd-size-type N = see below, simd-vec-type V, class IdxMap> constexpr resize_t<N, V> permute(const V& v, IdxMap&& idxmap); template<simd-size-type N = see below, simd-mask-type M, class IdxMap> constexpr resize_t<N, M> permute(const M& v, IdxMap&& idxmap);
Let:
  • gen-fn(i) be idxmap(i, V​::​size()) if that expression is well-formed, and idxmap(i) otherwise.
  • perm-fn be the following exposition-only function template: template<simd-size-type I> typename V::value_type perm-fn() { constexpr auto src_index = gen-fn(I); if constexpr (src_index == zero_element) { return typename V::value_type(); } else if constexpr (src_index == uninit_element) { return unspecified-value; } else { return v[src_index]; } }
Constraints: integral<invoke_result_t<IdxMap&, simd-size-type>> || integral<invoke_result_t<IdxMap&, simd-size-type, simd-size-type>> is true.
Mandates: gen-fn(i) is a constant expression whose value is zero_element, uninit_element, or in the range [0, V​::​size()), for all i in the range [0, N).
Returns: A data-parallel object where the element is initialized to the result of perm-fn<i>() for all i in the range [0, N).
Remarks: The default argument for template parameter N is V​::​size().

29.10.8.9 vec dynamic permute [simd.permute.dynamic]

template<simd-vec-type V, simd-integral I> constexpr resize_t<I::size(), V> permute(const V& v, const I& indices); template<simd-mask-type M, simd-integral I> constexpr resize_t<I::size(), M> permute(const M& v, const I& indices);
Preconditions: All values in indices are in the range [0, V​::​size()).
Returns: A data-parallel object where the element is initialized to the result of v[indices[i]] for all i in the range [0, I​::​size()).

29.10.8.10 vec mask permute [simd.permute.mask]

template<simd-vec-type V> constexpr V compress(const V& v, const typename V::mask_type& selector); template<simd-mask-type M> constexpr M compress(const M& v, const type_identity_t<M>& selector);
Let:
  • bit-index(i) be a function which returns the index of the element of selector that is true.
  • select-value(i) be a function which returns v[bit-index(i)] for i in the range [0, reduce_count(selector)) and a valid but unspecified value otherwise.
    [Note 1: 
    Different calls to select-value can return different unspecified values.
    — end note]
Returns: A data-parallel object where the element is initialized to the result of select-value(i) for all i in the range [0, V​::​size()).
template<simd-vec-type V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); template<simd-mask-type M> constexpr M compress(const M& v, const type_identity_t<M>& selector, const typename V::value_type& fill_value);
Let:
  • bit-index(i) be a function which returns the index of the element of selector that is true.
  • select-value(i) be a function which returns v[bit-index(i)] for i in the range [0, reduce_count(selector)) and fill_value otherwise.
Returns: A data-parallel object where the element is initialized to the result of select-value(i) for all i in the range [0, V​::​size()).
template<simd-vec-type V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); template<simd-mask-type M> constexpr M expand(const M& v, const type_identity_t<M>& selector, const M& original = {});
Let:
  • set-indices be a list of the index positions of true elements in selector.
  • bit-lookup(b) be a function which returns the index where b appears in set-indices.
  • select-value(i) be a function which returns v[bit-lookup(i)] if selector[i] is true, otherwise returns original[i].
Returns: A data-parallel object where the element is initialized to the result of select-value(i) for all i in the range [0, V​::​size()).

29.10.8.11 simd memory permute [simd.permute.memory]

template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_gather_from(R&& in, const I& indices, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V unchecked_gather_from(R&& in, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {});
Let mask be typename I​::​mask_type(true) for the overload with no mask parameter.
Preconditions: All values in select(mask, indices, typename I​::​value_type()) are in the range [0, ranges​::​size(in)).
Effects: Equivalent to: return partial_gather_from<V>(in, mask, indices, f);
Remarks: The default argument for template parameter V is vec<ranges​::​range_value_t<R>, I​::​​size()>.
template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V partial_gather_from(R&& in, const I& indices, flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr V partial_gather_from(R&& in, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {});
Let:
  • mask be typename I​::​mask_type(true) for the overload with no mask parameter;
  • T be typename V​::​value_type.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type,
  • same_as<remove_cvref_t<V>, V> is true,
  • V is an enabled specialization of basic_vec,
  • V​::​size() == I​::​size() is true, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from ranges​::​range_value_t<R> to T is value-preserving.
Preconditions:
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(in) points to storage aligned by alignment_v<V, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(in) points to storage aligned by N.
Returns: A basic_vec object where the element is initialized to the result of mask[i] && indices[i] < ranges::size(in) ? static_cast<T>(ranges::data(in)[indices[i]]) : T() for all i in the range [0, I​::​size()).
Remarks: The default argument for template parameter V is vec<ranges​::​range_value_t<R>, I​::​​size()>.
template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void unchecked_scatter_to(const V& v, R&& out, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void unchecked_scatter_to(const V& v, R&& out, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {});
Let mask be typename I​::​mask_type(true) for the overload with no mask parameter.
Preconditions: All values in select(mask, indices, typename I​::​value_type()) are in the range [0, ranges​::​size(out)).
Effects: Equivalent to: partial_scatter_to(v, out, mask, indices, f);
template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void partial_scatter_to(const V& v, R&& out, const I& indices, flags<Flags...> f = {}); template<simd-vec-type V, ranges::contiguous_range R, simd-integral I, class... Flags> requires ranges::sized_range<R> constexpr void partial_scatter_to(const V& v, R&& out, const typename I::mask_type& mask, const I& indices, flags<Flags...> f = {});
Let mask be typename I​::​mask_type(true) for the overload with no mask parameter.
Constraints: V​::​size() == I​::​size() is true.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from typename V​::​value_type to ranges​::​range_value_t<R> is value-preserving.
Preconditions:
  • For all selected indices i the values indices[i] are unique.
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(out) points to storage aligned by alignment_v<V, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(out) points to storage aligned by N.
Effects: For all i in the range [0, I​::​size()), if mask[i] && (indices[i] < ranges​::​size(out)) is true, evaluates ranges​::​data(out)[indices[i]] = v[i].

29.10.8.12 basic_vec and basic_mask creation [simd.creation]

template<class T, class Abi> constexpr auto chunk(const basic_vec<typename T::value_type, Abi>& x) noexcept; template<class T, class Abi> constexpr auto chunk(const basic_mask<mask-element-size<T>, Abi>& x) noexcept;
Constraints:
  • For the first overload, T is an enabled specialization of basic_vec.
    If basic_vec<typename T​::​​value_type, Abi>​::​size() % T​::​size() is not 0, then resize_t<basic_vec<typename T​::​​value_type, Abi>​::​size() % T​::​size(), T> is valid and denotes a type.
  • For the second overload, T is an enabled specialization of basic_mask.
    If basic_mask<mask-element-size<T>, Abi>​::​size() % T​::​size() is not 0, then resize_t<​basic_mask<mask-element-size<T>, Abi>​::​size() % T​::​size(), T> is valid and denotes a type.
Let N be x.size() / T​::​size().
Returns:
  • If x.size() % T​::​size() == 0 is true, an array<T, N> with the basic_vec or basic_mask element of the array element initialized to the value of the element in x with index i + j * T​::​size().
  • Otherwise, a tuple of N objects of type T and one object of type resize_t<x.size() % T​::​size(), T>.
    The basic_vec or basic_mask element of the tuple element of type T is initialized to the value of the element in x with index i + j * T​::​size().
    The basic_vec or basic_mask element of the tuple element is initialized to the value of the element in x with index i + N * T​::​size().
template<simd-size-type N, class T, class Abi> constexpr auto chunk(const basic_vec<T, Abi>& x) noexcept;
Effects: Equivalent to: return chunk<resize_t<N, basic_vec<T, Abi>>>(x);
template<simd-size-type N, size_t Bytes, class Abi> constexpr auto chunk(const basic_mask<Bytes, Abi>& x) noexcept;
Effects: Equivalent to: return chunk<resize_t<N, basic_mask<Bytes, Abi>>>(x);
template<class T, class... Abis> constexpr vec<T, (basic_vec<T, Abis>::size() + ...)> cat(const basic_vec<T, Abis>&... xs) noexcept; template<size_t Bytes, class... Abis> constexpr basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_mask<Bytes, Abis>::size() + ...)>> cat(const basic_mask<Bytes, Abis>&... xs) noexcept;
Constraints:
  • For the first overload vec<T, (basic_vec<T, Abis>​::​size() + ...)> is enabled.
  • For the second overload basic_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_mask<Bytes, Abis>​::​size() + ...)>> is enabled.
Returns: A data-parallel object initialized with the concatenated values in the xs pack of data-parallel objects: The basic_vec/basic_mask element of the parameter in the xs pack is copied to the return value's element with index i + the sum of the width of the first j parameters in the xs pack.

29.10.8.13 Algorithms [simd.alg]

template<class T, class Abi> constexpr basic_vec<T, Abi> min(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
Constraints: T models totally_ordered.
Returns: The result of the element-wise application of min(a[i], b[i]) for all i in the range of [0, basic_vec<T, Abi>​::​size()).
template<class T, class Abi> constexpr basic_vec<T, Abi> max(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
Constraints: T models totally_ordered.
Returns: The result of the element-wise application of max(a[i], b[i]) for all i in the range of [0, basic_vec<T, Abi>​::​size()).
template<class T, class Abi> constexpr pair<basic_vec<T, Abi>, basic_vec<T, Abi>> minmax(const basic_vec<T, Abi>& a, const basic_vec<T, Abi>& b) noexcept;
Effects: Equivalent to: return pair{min(a, b), max(a, b)};
template<class T, class Abi> constexpr basic_vec<T, Abi> clamp( const basic_vec<T, Abi>& v, const basic_vec<T, Abi>& lo, const basic_vec<T, Abi>& hi);
Constraints: T models totally_ordered.
Preconditions: No element in lo shall be greater than the corresponding element in hi.
Returns: The result of element-wise application of clamp(v[i], lo[i], hi[i]) for all i in the range of [0, basic_vec<T, Abi>​::​size()).
template<class T, class U> constexpr auto select(bool c, const T& a, const U& b) -> remove_cvref_t<decltype(c ? a : b)>;
Effects: Equivalent to: return c ? a : b;
template<size_t Bytes, class Abi, class T, class U> constexpr auto select(const basic_mask<Bytes, Abi>& c, const T& a, const U& b) noexcept -> decltype(simd-select-impl(c, a, b));
Effects: Equivalent to: return simd-select-impl(c, a, b); where simd-select-impl is found by argument-dependent lookup ([basic.lookup.argdep]) contrary to [contents].

29.10.8.14 Mathematical functions [simd.math]

template<math-floating-point V> constexpr rebind_t<int, deduced-vec-t<V>> ilogb(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> ldexp(const V& x, const rebind_t<int, deduced-vec-t<V>>& exp); template<math-floating-point V> constexpr deduced-vec-t<V> scalbn(const V& x, const rebind_t<int, deduced-vec-t<V>>& n); template<math-floating-point V> constexpr deduced-vec-t<V> scalbln(const V& x, const rebind_t<long int, deduced-vec-t<V>>& n); template<signed_integral T, class Abi> constexpr basic_vec<T, Abi> abs(const basic_vec<T, Abi>& j); template<math-floating-point V> constexpr deduced-vec-t<V> abs(const V& j); template<math-floating-point V> constexpr deduced-vec-t<V> fabs(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> ceil(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> floor(const V& x); template<math-floating-point V> deduced-vec-t<V> nearbyint(const V& x); template<math-floating-point V> deduced-vec-t<V> rint(const V& x); template<math-floating-point V> rebind_t<long int, deduced-vec-t<V>> lrint(const V& x); template<math-floating-point V> rebind_t<long long int, deduced-vec-t<V>> llrint(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> round(const V& x); template<math-floating-point V> constexpr rebind_t<long int, deduced-vec-t<V>> lround(const V& x); template<math-floating-point V> constexpr rebind_t<long long int, deduced-vec-t<V>> llround(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-vec-t<V> trunc(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z); template<math-floating-point V> constexpr rebind_t<int, deduced-vec-t<V>> fpclassify(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isfinite(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isinf(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isnan(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type isnormal(const V& x); template<math-floating-point V> constexpr typename deduced-vec-t<V>::mask_type signbit(const V& x); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreaterequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isless(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isunordered(const V0& x, const V1& y);
Let Ret denote the return type of the specialization of a function template with the name math-func.
Let math-func-vec denote: template<class... Args> Ret math-func-vec(Args... args) { return Ret([&](simd-size-type i) { math-func(make-compatible-simd-t<Ret, Args>(args)[i]...); }); }
Returns: A value ret of type Ret, that is element-wise equal to the result of calling math-func-vec with the arguments of the above functions.
If in an invocation of a scalar overload of math-func for index i in math-func-vec a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<math-floating-point V> constexpr deduced-vec-t<V> acos(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> asin(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> atan(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x); template<math-floating-point V> constexpr deduced-vec-t<V> cos(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> sin(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tan(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> acosh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> asinh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> atanh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> cosh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> sinh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tanh(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> exp(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> exp2(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> expm1(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log10(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log1p(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> log2(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> logb(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> cbrt(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-vec-t<V> sqrt(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> erf(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> erfc(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> lgamma(const V& x); template<math-floating-point V> constexpr deduced-vec-t<V> tgamma(const V& x); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> lerp(const V0& a, const V1& b, const V2& t) noexcept; template<math-floating-point V> deduced-vec-t<V> assoc_laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x); template<math-floating-point V> deduced-vec-t<V> assoc_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& x); template<class V0, class V1> math-common-simd-t<V0, V1> beta(const V0& x, const V1& y); template<math-floating-point V> deduced-vec-t<V> comp_ellint_1(const V& k); template<math-floating-point V> deduced-vec-t<V> comp_ellint_2(const V& k); template<class V0, class V1> math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi); template<class V0, class V1, class V2> math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi); template<math-floating-point V> deduced-vec-t<V> expint(const V& x); template<math-floating-point V> deduced-vec-t<V> hermite(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> laguerre(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const V& x); template<math-floating-point V> deduced-vec-t<V> riemann_zeta(const V& x); template<math-floating-point V> deduced-vec-t<V> sph_bessel(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x); template<math-floating-point V> deduced-vec-t<V> sph_legendre(const rebind_t<unsigned, deduced-vec-t<V>>& l, const rebind_t<unsigned, deduced-vec-t<V>>& m, const V& theta); template<math-floating-point V> deduced-vec-t<V> sph_neumann(const rebind_t<unsigned, deduced-vec-t<V>>& n, const V& x);
Let Ret denote the return type of the specialization of a function template with the name math-func.
Let math-func-vec denote: template<class... Args> Ret math-func-vec(Args... args) { return Ret([&](simd-size-type i) { math-func(make-compatible-simd-t<Ret, Args>(args)[i]...); }); }
Returns: A value ret of type Ret, that is element-wise approximately equal to the result of calling math-func-vec with the arguments of the above functions.
If in an invocation of a scalar overload of math-func for index i in math-func-vec a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<math-floating-point V> constexpr deduced-vec-t<V> frexp(const V& value, rebind_t<int, deduced-vec-t<V>>* exp);
Let Ret be deduced-vec-t<V>.
Let frexp-vec denote: template<class V> pair<Ret, rebind_t<int, Ret>> frexp-vec(const V& x) { int r1[Ret::size()]; Ret r0([&](simd-size-type i) { frexp(make-compatible-simd-t<Ret, V>(x)[i], &r1[i]); }); return {r0, rebind_t<int, Ret>(r1)}; }
Let ret be a value of type pair<Ret, rebind_t<int, Ret>> that is the same value as the result of calling frexp-vec(x).
Effects: Sets *exp to ret.second.
Returns: ret.first.
template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remquo(const V0& x, const V1& y, rebind_t<int, math-common-simd-t<V0, V1>>* quo);
Let Ret be math-common-simd-t<V0, V1>.
Let remquo-vec denote: template<class V0, class V1> pair<Ret, rebind_t<int, Ret>> remquo-vec(const V0& x, const V1& y) { int r1[Ret::size()]; Ret r0([&](simd-size-type i) { remquo(make-compatible-simd-t<Ret, V0>(x)[i], make-compatible-simd-t<Ret, V1>(y)[i], &r1[i]); }); return {r0, rebind_t<int, Ret>(r1)}; }
Let ret be a value of type pair<Ret, rebind_t<int, Ret>> that is the same value as the result of calling remquo-vec(x, y).
If in an invocation of a scalar overload of remquo for index i in remquo-vec a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Effects: Sets *quo to ret.second.
Returns: ret.first.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<class T, class Abi> constexpr basic_vec<T, Abi> modf(const type_identity_t<basic_vec<T, Abi>>& value, basic_vec<T, Abi>* iptr);
Let V be basic_vec<T, Abi>.
Let modf-vec denote: pair<V, V> modf-vec(const V& x) { T r1[Ret::size()]; V r0([&](simd-size-type i) { modf(V(x)[i], &r1[i]); }); return {r0, V(r1)}; }
Let ret be a value of type pair<V, V> that is the same value as the result of calling modf-vec(value).
Effects: Sets *iptr to ret.second.
Returns: ret.first.

29.10.8.15 basic_vec bit library [simd.bit]

template<simd-vec-type V> constexpr V byteswap(const V& v) noexcept;
Constraints: The type V​::​value_type models integral.
Returns: A basic_vec object where the element is initialized to the result of std​::​byteswap(v[i]) for all i in the range [0, V​::​size()).
template<simd-vec-type V> constexpr V bit_ceil(const V& v) noexcept;
Constraints: The type V​::​value_type is an unsigned integer type ([basic.fundamental]).
Preconditions: For every i in the range [0, V​::​size()), the smallest power of 2 greater than or equal to v[i] is representable as a value of type V​::​value_type.
Returns: A basic_vec object where the element is initialized to the result of std​::​bit_ceil(v[i]) for all i in the range [0, V​::​size()).
Remarks: A function call expression that violates the precondition in the Preconditions: element is not a core constant expression ([expr.const]).
template<simd-vec-type V> constexpr V bit_floor(const V& v) noexcept;
Constraints: The type V​::​value_type is an unsigned integer type ([basic.fundamental]).
Returns: A basic_vec object where the element is initialized to the result of std​::​bit_floor(v[i]) for all i in the range [0, V​::​size()).
template<simd-vec-type V> constexpr typename V::mask_type has_single_bit(const V& v) noexcept;
Constraints: The type V​::​value_type is an unsigned integer type ([basic.fundamental]).
Returns: A basic_mask object where the element is initialized to the result of std​::​has_single_bit(v[i]) for all i in the range [0, V​::​size()).
template<simd-vec-type V0, simd-vec-type V1> constexpr V0 rotl(const V0& v0, const V1& v1) noexcept; template<simd-vec-type V0, simd-vec-type V1> constexpr V0 rotr(const V0& v0, const V1& v1) noexcept;
Constraints:
  • The type V0​::​value_type is an unsigned integer type ([basic.fundamental]),
  • the type V1​::​value_type models integral,
  • V0​::​size() == V1​::​size() is true, and
  • sizeof(typename V0​::​value_type) == sizeof(typename V1​::​value_type) is true.
Returns: A basic_vec object where the element is initialized to the result of bit-func(v0[i], static_cast<int>(v1[i])) for all i in the range [0, V0​::​size()), where bit-func is the corresponding scalar function from <bit>.
template<simd-vec-type V> constexpr V rotl(const V& v, int s) noexcept; template<simd-vec-type V> constexpr V rotr(const V& v, int s) noexcept;
Constraints: The type V​::​value_type is an unsigned integer type ([basic.fundamental]).
Returns: A basic_vec object where the element is initialized to the result of bit-func(v[i], s) for all i in the range [0, V​::​size()), where bit-func is the corresponding scalar function from <bit>.
template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> bit_width(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_zero(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countl_one(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_zero(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> countr_one(const V& v) noexcept; template<simd-vec-type V> constexpr rebind_t<make_signed_t<typename V::value_type>, V> popcount(const V& v) noexcept;
Constraints: The type V​::​value_type is an unsigned integer type ([basic.fundamental]).
Returns: A basic_vec object where the element is initialized to the result of bit-func(v[i]) for all i in the range [0, V​::​size()), where bit-func is the corresponding scalar function from <bit>.

29.10.8.16 vec complex math [simd.complex.math]

template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> real(const V&) noexcept; template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> imag(const V&) noexcept; template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> abs(const V&); template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> arg(const V&); template<simd-complex V> constexpr rebind_t<simd-complex-value-type<V>, V> norm(const V&); template<simd-complex V> constexpr V conj(const V&); template<simd-complex V> constexpr V proj(const V&); template<simd-complex V> constexpr V exp(const V& v); template<simd-complex V> constexpr V log(const V& v); template<simd-complex V> constexpr V log10(const V& v); template<simd-complex V> constexpr V sqrt(const V& v); template<simd-complex V> constexpr V sin(const V& v); template<simd-complex V> constexpr V asin(const V& v); template<simd-complex V> constexpr V cos(const V& v); template<simd-complex V> constexpr V acos(const V& v); template<simd-complex V> constexpr V tan(const V& v); template<simd-complex V> constexpr V atan(const V& v); template<simd-complex V> constexpr V sinh(const V& v); template<simd-complex V> constexpr V asinh(const V& v); template<simd-complex V> constexpr V cosh(const V& v); template<simd-complex V> constexpr V acosh(const V& v); template<simd-complex V> constexpr V tanh(const V& v); template<simd-complex V> constexpr V atanh(const V& v);
Returns: A basic_vec object ret where the element is initialized to the result of cmplx-func(v[i]) for all i in the range [0, V​::​size()), where cmplx-func is the corresponding function from <complex>.
If in an invocation of cmplx-func for index i a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<simd-floating-point V> rebind_t<complex<typename V::value_type>, V> polar(const V& x, const V& y = {}); template<simd-complex V> constexpr V pow(const V& x, const V& y);
Returns: A basic_vec object ret where the element is initialized to the result of cmplx-func(x[i], y[i]) for all i in the range [0, V​::​size()), where cmplx-func is the corresponding function from <complex>.
If in an invocation of cmplx-func for index i a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.

29.10.9 Class template basic_mask [simd.mask.class]

29.10.9.1 Class template basic_mask overview [simd.mask.overview]

namespace std::simd { template<size_t Bytes, class Abi> class basic_mask { public: using value_type = bool; using \libmember{abi_type}{basic_mask} = Abi; using iterator = simd-iterator<basic_mask>; using const_iterator = simd-iterator<const basic_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<simd-size-type, simd-size-v<integer-from<Bytes>, Abi>> size {}; constexpr basic_mask() noexcept = default; // [simd.mask.ctor], basic_mask constructors constexpr explicit basic_mask(value_type) noexcept; template<size_t UBytes, class UAbi> constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>&) noexcept; template<class G> constexpr explicit basic_mask(G&& gen) noexcept; constexpr basic_mask(const bitset<size()>& b) noexcept; constexpr explicit basic_mask(unsigned_integral auto val) noexcept; // [simd.mask.subscr], basic_mask subscript operators constexpr value_type operator[](simd-size-type) const; template<simd-integral I> constexpr resize_t<I::size(), basic_mask> operator[](const I& indices) const; // [simd.mask.unary], basic_mask unary operators constexpr basic_mask operator!() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator+() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator-() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator~() const noexcept; // [simd.mask.conv], basic_mask conversion operators template<class U, class A> constexpr explicit(sizeof(U) != Bytes) operator basic_vec<U, A>() const noexcept; // [simd.mask.namedconv], basic_mask named type convertors constexpr bitset<size()> to_bitset() const noexcept; constexpr unsigned long long to_ullong() const; // [simd.mask.binary], basic_mask binary operators friend constexpr basic_mask operator&&(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator||(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator&(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator|(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator^(const basic_mask&, const basic_mask&) noexcept; // [simd.mask.cassign], basic_mask compound assignment friend constexpr basic_mask& operator&=(basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask& operator|=(basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask& operator^=(basic_mask&, const basic_mask&) noexcept; // [simd.mask.comparison], basic_mask comparisons friend constexpr basic_mask operator==(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator!=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator>=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator<=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator>(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator<(const basic_mask&, const basic_mask&) noexcept; // [simd.mask.cond], basic_mask exposition only conditional operators friend constexpr basic_mask simd-select-impl( // exposition only const basic_mask&, const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask simd-select-impl( // exposition only const basic_mask&, same_as<bool> auto, same_as<bool> auto) noexcept; template<class T0, class T1> friend constexpr vec<see below, size()> simd-select-impl(const basic_mask&, const T0&, const T1&) noexcept; // exposition only }; }
Every specialization of basic_mask is a complete type.
The specialization of basic_mask<Bytes, Abi> is:
  • disabled, if there is no vectorizable type T such that Bytes is equal to sizeof(T),
  • otherwise, enabled, if there exists a vectorizable type T and a value N in the range [1, 64] such that Bytes is equal to sizeof(T) and Abi is deduce-abi-t<T, N>,
  • otherwise, it is implementation-defined if such a specialization is enabled.
If basic_mask<Bytes, Abi> is disabled, the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment.
In addition only the value_type and abi_type members are present.
If basic_mask<Bytes, Abi> is enabled, basic_mask<Bytes, Abi> is trivially copyable.
Recommended practice: Implementations should support implicit conversions between specializations of basic_mask and appropriate implementation-defined types.
[Note 1: 
Appropriate types are non-standard vector types which are available in the implementation.
— end note]

29.10.9.2 basic_mask constructors [simd.mask.ctor]

constexpr explicit basic_mask(value_type x) noexcept;
Effects: Initializes each element with x.
template<size_t UBytes, class UAbi> constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>& x) noexcept;
Constraints: basic_mask<UBytes, UAbi>​::​size() == size() is true.
Effects: Initializes the element with x[i] for all i in the range of [0, size()).
template<class G> constexpr explicit basic_mask(G&& gen);
Constraints: The expression gen(integral_constant<simd-size-type, i>()) is well-formed and its type is bool for all i in the range of [0, size()).
Effects: Initializes the element with gen(integral_constant<simd-size-type, i>()) for all i in the range of [0, size()).
Remarks: gen is invoked exactly once for each i, in increasing order of i.
constexpr basic_mask(const bitset<size()>& b) noexcept;
Effects: Initializes the element with b[i] for all i in the range [0, size()).
constexpr explicit basic_mask(unsigned_integral auto val) noexcept;
Effects: Initializes the first M elements to the corresponding bit values in val, where M is the smaller of size() and the number of bits in the value representation ([basic.types.general]) of the type of val.
If M is less than size(), the remaining elements are initialized to zero.

29.10.9.3 basic_mask subscript operator [simd.mask.subscr]

constexpr value_type operator[](simd-size-type i) const;
Preconditions: i >= 0 && i < size() is true.
Returns: The value of the element.
Throws: Nothing.
template<simd-integral I> constexpr resize_t<I::size(), basic_mask> operator[](const I& indices) const;
Effects: Equivalent to: return permute(*this, indices);

29.10.9.4 basic_mask unary operators [simd.mask.unary]

constexpr basic_mask operator!() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator+() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator-() const noexcept; constexpr basic_vec<integer-from<Bytes>, Abi> operator~() const noexcept;
Let op be the operator.
Returns: A data-parallel object where the element is initialized to the results of applying op to operator[](i) for all i in the range of [0, size()).

29.10.9.5 basic_mask conversion operators [simd.mask.conv]

template<class U, class A> constexpr explicit(sizeof(U) != Bytes) operator basic_vec<U, A>() const noexcept;
Constraints: simd-size-v<U, A> == simd-size-v<T, Abi>.
Returns: A data-parallel object where the element is initialized to static_cast<U>(operator[](i)).

29.10.9.6 basic_mask named conversion operators [simd.mask.namedconv]

constexpr bitset<size()> to_bitset() const noexcept;
Returns: A bitset<size()> object where the element is initialized to operator[](i) for all i in the range [0, size()).
constexpr unsigned long long to_ullong() const;
Let N be the width of unsigned long long.
Preconditions:
  • size() <= N is true, or
  • for all i in the range [N, size()), operator[](i) returns false.
Returns: The integral value corresponding to the bits in *this.
Throws: Nothing.

29.10.10 Non-member operations [simd.mask.nonmembers]

29.10.10.1 basic_mask binary operators [simd.mask.binary]

friend constexpr basic_mask operator&&(const basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask operator||(const basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask operator& (const basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask operator| (const basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask operator^ (const basic_mask& lhs, const basic_mask& rhs) noexcept;
Let op be the operator.
Returns: A basic_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.10.2 basic_mask compound assignment [simd.mask.cassign]

friend constexpr basic_mask& operator&=(basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask& operator|=(basic_mask& lhs, const basic_mask& rhs) noexcept; friend constexpr basic_mask& operator^=(basic_mask& lhs, const basic_mask& rhs) noexcept;
Let op be the operator.
Effects: These operators apply op to lhs and rhs as a binary element-wise operation.
Returns: lhs.

29.10.10.3 basic_mask comparisons [simd.mask.comparison]

friend constexpr basic_mask operator==(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator!=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator>=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator<=(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator>(const basic_mask&, const basic_mask&) noexcept; friend constexpr basic_mask operator<(const basic_mask&, const basic_mask&) noexcept;
Let op be the operator.
Returns: A basic_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.10.4 basic_mask exposition only conditional operators [simd.mask.cond]

friend constexpr basic_mask simd-select-impl( const basic_mask& mask, const basic_mask& a, const basic_mask& b) noexcept;
Returns: A basic_mask object where the element equals mask[i] ? a[i] : b[i] for all i in the range of [0, size()).
friend constexpr basic_mask simd-select-impl(const basic_mask& mask, same_as<bool> auto a, same_as<bool> auto b) noexcept;
Returns: A basic_mask object where the element equals mask[i] ? a : b for all i in the range of [0, size()).
template<class T0, class T1> friend constexpr vec<see below, size()> simd-select-impl(const basic_mask& mask, const T0& a, const T1& b) noexcept;
Constraints:
  • same_as<T0, T1> is true,
  • T0 is a vectorizable type, and
  • sizeof(T0) == Bytes.
Returns: A vec<T0, size()> object where the element equals mask[i] ? a : b for all i in the range of [0, size()).

29.10.10.5 basic_mask reductions [simd.mask.reductions]

template<size_t Bytes, class Abi> constexpr bool all_of(const basic_mask<Bytes, Abi>& k) noexcept;
Returns: true if all boolean elements in k are true, otherwise false.
template<size_t Bytes, class Abi> constexpr bool any_of(const basic_mask<Bytes, Abi>& k) noexcept;
Returns: true if at least one boolean element in k is true, otherwise false.
template<size_t Bytes, class Abi> constexpr bool none_of(const basic_mask<Bytes, Abi>& k) noexcept;
Returns: !any_of(k).
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_count(const basic_mask<Bytes, Abi>& k) noexcept;
Returns: The number of boolean elements in k that are true.
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_min_index(const basic_mask<Bytes, Abi>& k);
Preconditions: any_of(k) is true.
Returns: The lowest element index i where k[i] is true.
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_max_index(const basic_mask<Bytes, Abi>& k);
Preconditions: any_of(k) is true.
Returns: The greatest element index i where k[i] is true.
constexpr bool all_of(same_as<bool> auto x) noexcept; constexpr bool any_of(same_as<bool> auto x) noexcept; constexpr simd-size-type reduce_count(same_as<bool> auto x) noexcept;
Returns: x.
constexpr bool none_of(same_as<bool> auto x) noexcept;
Returns: !x.
constexpr simd-size-type reduce_min_index(same_as<bool> auto x); constexpr simd-size-type reduce_max_index(same_as<bool> auto x);
Preconditions: x is true.
Returns: 0.