Skip to content

Commit 1dabdd3

Browse files
authored
Merge 2024-11 LWG Motion 7
P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment
2 parents 6c6bd99 + 8aa0ee9 commit 1dabdd3

File tree

3 files changed

+219
-0
lines changed

3 files changed

+219
-0
lines changed

source/containers.tex

+193
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,195 @@
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 offset(
23186+
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+
}
23255+
\end{codeblock}
23256+
\end{example}
23257+
23258+
\rSec5[mdspan.accessor.aligned.members]{Members}
23259+
23260+
\indexlibraryctor{aligned_accessor}%
23261+
\begin{itemdecl}
23262+
template<class OtherElementType, size_t OtherByteAlignment>
23263+
constexpr aligned_accessor(aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
23264+
\end{itemdecl}
23265+
23266+
\begin{itemdescr}
23267+
\pnum
23268+
\constraints
23269+
\begin{itemize}
23270+
\item
23271+
\tcode{is_convertible_v<OtherElementType(*)[], element_type(*)[]>}
23272+
is \tcode{true}.
23273+
\item
23274+
\tcode{OtherByteAlignment >= byte_alignment} is \tcode{true}.
23275+
\end{itemize}
23276+
23277+
\pnum
23278+
\effects
23279+
None.
23280+
\end{itemdescr}
23281+
23282+
\indexlibraryctor{aligned_accessor}%
23283+
\begin{itemdecl}
23284+
template<class OtherElementType>
23285+
constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
23286+
\end{itemdecl}
23287+
23288+
\begin{itemdescr}
23289+
\pnum
23290+
\constraints
23291+
\tcode{is_convertible_v<OtherElementType(*)[], element_type(*)[]>}
23292+
is \tcode{true}.
23293+
23294+
\pnum
23295+
\effects
23296+
None.
23297+
\end{itemdescr}
23298+
23299+
\indexlibrarymember{access}{aligned_accessor}%
23300+
\begin{itemdecl}
23301+
constexpr reference access(data_handle_type p, size_t i) const noexcept;
23302+
\end{itemdecl}
23303+
23304+
\begin{itemdescr}
23305+
\pnum
23306+
\expects
23307+
\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}.
23308+
23309+
\pnum
23310+
\effects
23311+
Equivalent to: \tcode{return assume_aligned<byte_alignment>(p)[i];}
23312+
\end{itemdescr}
23313+
23314+
\indexlibrarymember{operator default_accessor}{aligned_accessor}%
23315+
\begin{itemdecl}
23316+
template<class OtherElementType>
23317+
constexpr operator default_accessor<OtherElementType>() const noexcept;
23318+
\end{itemdecl}
23319+
23320+
\begin{itemdescr}
23321+
\pnum
23322+
\constraints
23323+
\tcode{is_convertible_v<element_type(*)[], OtherElementType(*)[]>}
23324+
is \tcode{true}.
23325+
23326+
\pnum
23327+
\effects
23328+
Equivalent to: \tcode{return \{\};}
23329+
\end{itemdescr}
23330+
23331+
\indexlibrarymember{offset}{aligned_accessor}%
23332+
\begin{itemdecl}
23333+
constexpr typename offset_policy::data_handle_type
23334+
offset(data_handle_type p, size_t i) const noexcept;
23335+
\end{itemdecl}
23336+
23337+
\begin{itemdescr}
23338+
\pnum
23339+
\expects
23340+
\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}.
23341+
23342+
\pnum
23343+
\effects
23344+
Equivalent to: \tcode{return assume_aligned<byte_alignment>(p) + i;}
23345+
\end{itemdescr}
23346+
2315423347
\rSec3[mdspan.mdspan]{Class template \tcode{mdspan}}
2315523348

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

source/memory.tex

+24
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{is_sufficiently_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

+2
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)