diff --git a/source/containers.tex b/source/containers.tex index 09d642b600..f01375a063 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -19778,6 +19778,10 @@ template class default_accessor; + // \ref{mdspan.accessor.aligned}, class template \tcode{aligned_accessor} + template + class aligned_accessor; + // \ref{mdspan.mdspan}, class template \tcode{mdspan} template> @@ -23150,6 +23154,194 @@ Equivalent to: \tcode{return p + i;} \end{itemdescr} +\rSec4[mdspan.accessor.aligned]{Class template \tcode{aligned_accessor}} + +\rSec5[mdspan.accessor.aligned.overview]{Overview} + +\begin{codeblock} +namespace std { + template + struct @\libglobal{aligned_accessor}@ { + using offset_policy = default_accessor; + using element_type = ElementType; + using reference = ElementType&; + using data_handle_type = ElementType*; + + static constexpr size_t byte_alignment = ByteAlignment; + + constexpr aligned_accessor() noexcept = default; + template + constexpr aligned_accessor( + aligned_accessor) noexcept; + template + constexpr explicit aligned_accessor(default_accessor) noexcept; + + template + constexpr operator default_accessor() const noexcept; + + constexpr reference access(data_handle_type p, size_t i) const noexcept; + + constexpr typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const noexcept; + }; +} +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item \tcode{byte_alignment} is a power of two and +\item \tcode{byte_alignment >= alignof(ElementType)} is \tcode{true}. +\end{itemize} + +\pnum +\tcode{aligned_accessor} meets the accessor policy requirements. + +\pnum +\tcode{ElementType} is required to be a complete object type +that is neither an abstract class type nor an array type. + +\pnum +Each specialization of \tcode{aligned_accessor} is +a trivially copyable type that models \libconcept{semiregular}. + +\pnum +\range{0}{$n$} is an accessible range +for an object \tcode{p} of type \tcode{data_handle_type} and +an object of type \tcode{aligned_accessor} if and only if +\begin{itemize} +\item +\range{p}{p + $n$} is a valid range and +\item +if $n$ is greater than zero, +then \tcode{is_sufficiently_aligned(p)} is \tcode{true}. +\end{itemize} + +\pnum +\begin{example} +The following function \tcode{compute} +uses \tcode{is_sufficiently_aligned} to check +whether a given \tcode{mdspan} with \tcode{default_accessor} has +a data handle with sufficient alignment +to be used with \tcode{aligned_accessor}. +If so, the function dispatches to +a function \tcode{compute_using_fourfold_overalignment} +that requires fourfold over-alignment of arrays, +but can therefore use hardware-specific instructions, +such as four-wide SIMD (Single Instruction Multiple Data) instructions. +Otherwise, \tcode{compute} dispatches to a +possibly less optimized function \tcode{compute_without_requiring_overalignment} +that has no over-alignment requirement. +\begin{codeblock} +void compute_using_fourfold_overalignment( + std::mdspan, std::layout_right, + std::aligned_accessor> x); + +void compute_without_requiring_overalignment( + std::mdspan, std::layout_right> x); + +void compute(std::mdspan> x) { + constexpr auto byte_alignment = 4 * sizeof(float); + auto accessor = std::aligned_accessor{}; + auto x_handle = x.data_handle(); + + if (std::is_sufficiently_aligned(x_handle)) + compute_using_fourfold_overalignment(std::mdspan{x_handle, x.mapping(), accessor}); + else + compute_without_requiring_overalignment(x); +} +\end{codeblock} +\end{example} + +\rSec5[mdspan.accessor.aligned.members]{Members} + +\indexlibraryctor{aligned_accessor}% +\begin{itemdecl} +template + constexpr aligned_accessor(aligned_accessor) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} +is \tcode{true}. +\item +\tcode{OtherByteAlignment >= byte_alignment} is \tcode{true}. +\end{itemize} + +\pnum +\effects +None. +\end{itemdescr} + +\indexlibraryctor{aligned_accessor}% +\begin{itemdecl} +template + constexpr explicit aligned_accessor(default_accessor) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_convertible_v} +is \tcode{true}. + +\pnum +\effects +None. +\end{itemdescr} + +\indexlibrarymember{access}{aligned_accessor}% +\begin{itemdecl} +constexpr reference access(data_handle_type p, size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}. + +\pnum +\effects +Equivalent to: \tcode{return assume_aligned(p)[i];} +\end{itemdescr} + +\indexlibrarymember{operator default_accessor}{aligned_accessor}% +\begin{itemdecl} +template + constexpr operator default_accessor() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_convertible_v} +is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \{\};} +\end{itemdescr} + +\indexlibrarymember{offset}{aligned_accessor}% +\begin{itemdecl} +constexpr typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}. + +\pnum +\effects +Equivalent to: \tcode{return assume_aligned(p) + i;} +\end{itemdescr} + \rSec3[mdspan.mdspan]{Class template \tcode{mdspan}} \rSec4[mdspan.mdspan.overview]{Overview} diff --git a/source/memory.tex b/source/memory.tex index 1260365953..cb24d9afac 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -83,6 +83,8 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); // freestanding template constexpr T* assume_aligned(T* ptr); // freestanding + template + bool is_sufficiently_aligned(T* ptr); // \ref{obj.lifetime}, explicit lifetime management template @@ -864,6 +866,28 @@ \end{note} \end{itemdescr} +\indexlibraryglobal{assume_aligned}% +\begin{itemdecl} +template + bool is_sufficiently_aligned(T* ptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{p} points to +an object \tcode{X} of a type similar\iref{conv.qual} to \tcode{T}. + +\pnum +\returns +\tcode{true} if \tcode{X} has alignment at least \tcode{Alignment}, +otherwise \tcode{false}. + +\pnum +\throws +Nothing. +\end{itemdescr} + \rSec2[obj.lifetime]{Explicit lifetime management} \indexlibraryglobal{start_lifetime_as}% diff --git a/source/support.tex b/source/support.tex index 28c15ac913..cf670f8dc3 100644 --- a/source/support.tex +++ b/source/support.tex @@ -557,6 +557,7 @@ // also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector} #define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L // also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory} +#define @\defnlibxname{cpp_lib_aligned_accessor}@ 202411L // also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_allocate_at_least}@ 202302L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L // freestanding, also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list}, @@ -700,6 +701,7 @@ #define @\defnlibxname{cpp_lib_is_null_pointer}@ 201309L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_pointer_interconvertible}@ 201907L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_scoped_enum}@ 202011L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_sufficiently_aligned}@ 202411L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_is_swappable}@ 201603L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_virtual_base_of}@ 202406L // also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // also in \libheader{type_traits}