Skip to content

Commit 80c3f95

Browse files
committed
P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment
1 parent 219b959 commit 80c3f95

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

source/containers.tex

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

19781+
// \ref{mdspan.accessor.aligned}, class template \tcode{aligned_accessor}
19782+
template<class ElementType, size_t ByteAlignment>
19783+
class aligned_accessor;
19784+
1978119785
// \ref{mdspan.mdspan}, class template \tcode{mdspan}
1978219786
template<class ElementType, class Extents, class LayoutPolicy = layout_right,
1978319787
class AccessorPolicy = default_accessor<ElementType>>
@@ -23150,6 +23154,193 @@
2315023154
Equivalent to: \tcode{return p + i;}
2315123155
\end{itemdescr}
2315223156

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

2315523346
\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
@@ -557,6 +557,7 @@
557557
// also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector}
558558
#define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L
559559
// also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory}
560+
#define @\defnlibxname{cpp_lib_aligned_accessor}@ 202411L // also in \libheader{mdspan}
560561
#define @\defnlibxname{cpp_lib_allocate_at_least}@ 202302L // also in \libheader{memory}
561562
#define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L
562563
// freestanding, also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list},
@@ -700,6 +701,7 @@
700701
#define @\defnlibxname{cpp_lib_is_null_pointer}@ 201309L // freestanding, also in \libheader{type_traits}
701702
#define @\defnlibxname{cpp_lib_is_pointer_interconvertible}@ 201907L // freestanding, also in \libheader{type_traits}
702703
#define @\defnlibxname{cpp_lib_is_scoped_enum}@ 202011L // freestanding, also in \libheader{type_traits}
704+
#define @\defnlibxname{cpp_lib_is_sufficiently_aligned}@ 202411L // also in \libheader{memory}
703705
#define @\defnlibxname{cpp_lib_is_swappable}@ 201603L // freestanding, also in \libheader{type_traits}
704706
#define @\defnlibxname{cpp_lib_is_virtual_base_of}@ 202406L // also in \libheader{type_traits}
705707
#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // also in \libheader{type_traits}

0 commit comments

Comments
 (0)