Skip to content

Commit 380edca

Browse files
jensmaurertkoeppe
authored andcommitted
P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment
1 parent a73c71e commit 380edca

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

source/containers.tex

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19779,6 +19779,10 @@
1977919779
template<class ElementType>
1978019780
class default_accessor;
1978119781

19782+
// \ref{mdspan.accessor.aligned}, class template \tcode{aligned_accessor}
19783+
template<class ElementType, size_t ByteAlignment>
19784+
class aligned_accessor;
19785+
1978219786
// \ref{mdspan.mdspan}, class template \tcode{mdspan}
1978319787
template<class ElementType, class Extents, class LayoutPolicy = layout_right,
1978419788
class AccessorPolicy = default_accessor<ElementType>>
@@ -23151,6 +23155,194 @@
2315123155
Equivalent to: \tcode{return p + i;}
2315223156
\end{itemdescr}
2315323157

23158+
\rSec4[mdspan.accessor.aligned]{Class template \tcode{aligned_accessor}}
23159+
23160+
\rSec5[mdspan.accessor.aligned.overview]{Overview}
23161+
23162+
\begin{codeblock}
23163+
namespace std {
23164+
template<class ElementType, size_t ByteAlignment>
23165+
struct @\libglobal{aligned_accessor}@ {
23166+
using offset_policy = default_accessor<ElementType>;
23167+
using element_type = ElementType;
23168+
using reference = ElementType&;
23169+
using data_handle_type = ElementType*;
23170+
23171+
static constexpr size_t byte_alignment = ByteAlignment;
23172+
23173+
constexpr aligned_accessor() noexcept = default;
23174+
template<class OtherElementType, size_t OtherByteAlignment>
23175+
constexpr aligned_accessor(
23176+
aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
23177+
template<class OtherElementType>
23178+
constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
23179+
23180+
template<class OtherElementType>
23181+
constexpr operator default_accessor<OtherElementType>() const noexcept;
23182+
23183+
constexpr reference access(data_handle_type p, size_t i) const noexcept;
23184+
23185+
constexpr typename offset_policy::data_handle_type
23186+
offset(data_handle_type p, size_t i) const noexcept;
23187+
};
23188+
}
23189+
\end{codeblock}
23190+
23191+
\pnum
23192+
\mandates
23193+
\begin{itemize}
23194+
\item \tcode{byte_alignment} is a power of two and
23195+
\item \tcode{byte_alignment >= alignof(ElementType)} is \tcode{true}.
23196+
\end{itemize}
23197+
23198+
\pnum
23199+
\tcode{aligned_accessor} meets the accessor policy requirements.
23200+
23201+
\pnum
23202+
\tcode{ElementType} is required to be a complete object type
23203+
that is neither an abstract class type nor an array type.
23204+
23205+
\pnum
23206+
Each specialization of \tcode{aligned_accessor} is
23207+
a trivially copyable type that models \libconcept{semiregular}.
23208+
23209+
\pnum
23210+
\range{0}{$n$} is an accessible range
23211+
for an object \tcode{p} of type \tcode{data_handle_type} and
23212+
an object of type \tcode{aligned_accessor} if and only if
23213+
\begin{itemize}
23214+
\item
23215+
\range{p}{p + $n$} is a valid range and
23216+
\item
23217+
if $n$ is greater than zero,
23218+
then \tcode{is_sufficiently_aligned<byte_alignment>(p)} is \tcode{true}.
23219+
\end{itemize}
23220+
23221+
\pnum
23222+
\begin{example}
23223+
The following function \tcode{compute}
23224+
uses \tcode{is_sufficiently_aligned} to check
23225+
whether a given \tcode{mdspan} with \tcode{default_accessor} has
23226+
a data handle with sufficient alignment
23227+
to be used with \tcode{aligned_accessor<float, 4 * sizeof(float)>}.
23228+
If so, the function dispatches to
23229+
a function \tcode{compute_using_fourfold_overalignment}
23230+
that requires fourfold over-alignment of arrays,
23231+
but can therefore use hardware-specific instructions,
23232+
such as four-wide SIMD (Single Instruction Multiple Data) instructions.
23233+
Otherwise, \tcode{compute} dispatches to a
23234+
possibly less optimized function \tcode{compute_without_requiring_overalignment}
23235+
that has no over-alignment requirement.
23236+
\begin{codeblock}
23237+
void compute_using_fourfold_overalignment(
23238+
std::mdspan<float, std::dims<1>, std::layout_right,
23239+
std::aligned_accessor<float, 4 * alignof(float)>> x);
23240+
23241+
void compute_without_requiring_overalignment(
23242+
std::mdspan<float, std::dims<1>, std::layout_right> x);
23243+
23244+
void compute(std::mdspan<float, std::dims<1>> x) {
23245+
constexpr auto byte_alignment = 4 * sizeof(float);
23246+
auto accessor = std::aligned_accessor<float, byte_alignment>{};
23247+
auto x_handle = x.data_handle();
23248+
23249+
if (std::is_sufficiently_aligned<byte_alignment>(x_handle))
23250+
compute_using_fourfold_overalignment(std::mdspan{x_handle, x.mapping(), accessor});
23251+
else
23252+
compute_without_requiring_overalignment(x);
23253+
}
23254+
\end{codeblock}
23255+
\end{example}
23256+
23257+
\rSec5[mdspan.accessor.aligned.members]{Members}
23258+
23259+
\indexlibraryctor{aligned_accessor}%
23260+
\begin{itemdecl}
23261+
template<class OtherElementType, size_t OtherByteAlignment>
23262+
constexpr aligned_accessor(aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
23263+
\end{itemdecl}
23264+
23265+
\begin{itemdescr}
23266+
\pnum
23267+
\constraints
23268+
\begin{itemize}
23269+
\item
23270+
\tcode{is_convertible_v<OtherElementType(*)[], element_type(*)[]>}
23271+
is \tcode{true}.
23272+
\item
23273+
\tcode{OtherByteAlignment >= byte_alignment} is \tcode{true}.
23274+
\end{itemize}
23275+
23276+
\pnum
23277+
\effects
23278+
None.
23279+
\end{itemdescr}
23280+
23281+
\indexlibraryctor{aligned_accessor}%
23282+
\begin{itemdecl}
23283+
template<class OtherElementType>
23284+
constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
23285+
\end{itemdecl}
23286+
23287+
\begin{itemdescr}
23288+
\pnum
23289+
\constraints
23290+
\tcode{is_convertible_v<OtherElementType(*)[], element_type(*)[]>}
23291+
is \tcode{true}.
23292+
23293+
\pnum
23294+
\effects
23295+
None.
23296+
\end{itemdescr}
23297+
23298+
\indexlibrarymember{access}{aligned_accessor}%
23299+
\begin{itemdecl}
23300+
constexpr reference access(data_handle_type p, size_t i) const noexcept;
23301+
\end{itemdecl}
23302+
23303+
\begin{itemdescr}
23304+
\pnum
23305+
\expects
23306+
\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}.
23307+
23308+
\pnum
23309+
\effects
23310+
Equivalent to: \tcode{return assume_aligned<byte_alignment>(p)[i];}
23311+
\end{itemdescr}
23312+
23313+
\indexlibrarymember{operator default_accessor}{aligned_accessor}%
23314+
\begin{itemdecl}
23315+
template<class OtherElementType>
23316+
constexpr operator default_accessor<OtherElementType>() const noexcept;
23317+
\end{itemdecl}
23318+
23319+
\begin{itemdescr}
23320+
\pnum
23321+
\constraints
23322+
\tcode{is_convertible_v<element_type(*)[], OtherElementType(*)[]>}
23323+
is \tcode{true}.
23324+
23325+
\pnum
23326+
\effects
23327+
Equivalent to: \tcode{return \{\};}
23328+
\end{itemdescr}
23329+
23330+
\indexlibrarymember{offset}{aligned_accessor}%
23331+
\begin{itemdecl}
23332+
constexpr typename offset_policy::data_handle_type
23333+
offset(data_handle_type p, size_t i) const noexcept;
23334+
\end{itemdecl}
23335+
23336+
\begin{itemdescr}
23337+
\pnum
23338+
\expects
23339+
\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}.
23340+
23341+
\pnum
23342+
\effects
23343+
Equivalent to: \tcode{return assume_aligned<byte_alignment>(p) + i;}
23344+
\end{itemdescr}
23345+
2315423346
\rSec3[mdspan.mdspan]{Class template \tcode{mdspan}}
2315523347

2315623348
\rSec4[mdspan.mdspan.overview]{Overview}

source/memory.tex

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
void* align(size_t alignment, size_t size, void*& ptr, size_t& space); // freestanding
8484
template<size_t N, class T>
8585
constexpr T* assume_aligned(T* ptr); // freestanding
86+
template<size_t Alignment, class T>
87+
bool is_sufficiently_aligned(T* ptr);
8688

8789
// \ref{obj.lifetime}, explicit lifetime management
8890
template<class T>
@@ -864,6 +866,28 @@
864866
\end{note}
865867
\end{itemdescr}
866868

869+
\indexlibraryglobal{assume_aligned}%
870+
\begin{itemdecl}
871+
template<size_t Alignment, class T>
872+
bool is_sufficiently_aligned(T* ptr);
873+
\end{itemdecl}
874+
875+
\begin{itemdescr}
876+
\pnum
877+
\expects
878+
\tcode{p} points to
879+
an object \tcode{X} of a type similar\iref{conv.qual} to \tcode{T}.
880+
881+
\pnum
882+
\returns
883+
\tcode{true} if \tcode{X} has alignment at least \tcode{Alignment},
884+
otherwise \tcode{false}.
885+
886+
\pnum
887+
\throws
888+
Nothing.
889+
\end{itemdescr}
890+
867891
\rSec2[obj.lifetime]{Explicit lifetime management}
868892

869893
\indexlibraryglobal{start_lifetime_as}%

source/support.tex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@
558558
// also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector}
559559
#define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L
560560
// also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory}
561+
#define @\defnlibxname{cpp_lib_aligned_accessor}@ 202411L // also in \libheader{mdspan}
561562
#define @\defnlibxname{cpp_lib_allocate_at_least}@ 202302L // also in \libheader{memory}
562563
#define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L
563564
// freestanding, also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list},
@@ -702,6 +703,7 @@
702703
#define @\defnlibxname{cpp_lib_is_null_pointer}@ 201309L // freestanding, also in \libheader{type_traits}
703704
#define @\defnlibxname{cpp_lib_is_pointer_interconvertible}@ 201907L // freestanding, also in \libheader{type_traits}
704705
#define @\defnlibxname{cpp_lib_is_scoped_enum}@ 202011L // freestanding, also in \libheader{type_traits}
706+
#define @\defnlibxname{cpp_lib_is_sufficiently_aligned}@ 202411L // also in \libheader{memory}
705707
#define @\defnlibxname{cpp_lib_is_swappable}@ 201603L // freestanding, also in \libheader{type_traits}
706708
#define @\defnlibxname{cpp_lib_is_virtual_base_of}@ 202406L // freestanding, also in \libheader{type_traits}
707709
#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // freestanding, also in \libheader{type_traits}

0 commit comments

Comments
 (0)