Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Implement P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment #122603

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

dalg24
Copy link
Member

@dalg24 dalg24 commented Jan 11, 2025

Closes #118372

@dalg24 dalg24 requested a review from a team as a code owner January 11, 2025 18:26
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jan 11, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 11, 2025

@llvm/pr-subscribers-libcxx

Author: Damien L-G (dalg24)

Changes

Closes #118372


Patch is 40.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122603.diff

21 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+4)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+2)
  • (added) libcxx/include/__mdspan/aligned_accessor.h (+86)
  • (modified) libcxx/include/__mdspan/mdspan.h (+5-4)
  • (added) libcxx/include/__memory/is_sufficiently_aligned.h (+34)
  • (modified) libcxx/include/mdspan (+37-1)
  • (modified) libcxx/include/memory (+4)
  • (modified) libcxx/include/module.modulemap (+2)
  • (modified) libcxx/modules/std/mdspan.inc (+5)
  • (modified) libcxx/modules/std/memory.inc (+3)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/access.pass.cpp (+61)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/byte_alignment.verify.cpp (+29)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.conversion.from.default_accessor.pass.cpp (+81)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.conversion.pass.cpp (+104)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.default.pass.cpp (+56)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/element_type.verify.cpp (+32)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/offset.pass.cpp (+61)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/operator.conversion.to.default_accessor.pass.cpp (+80)
  • (added) libcxx/test/std/containers/views/mdspan/aligned_accessor/types.pass.cpp (+70)
  • (added) libcxx/test/std/utilities/memory/ptr.align/is_sufficiently_aligned.pass.cpp (+105)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index cfb0e5cfb129ce..ae8cbe61fd7d17 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -406,6 +406,8 @@ Status
     ----------------------------------------------------------------------------
     ``__cpp_lib_associative_heterogeneous_insertion``          *unimplemented*
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_aligned_accessor``                             ``202411L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_atomic_min_max``                               *unimplemented*
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_bind_front``                                   ``202306L``
@@ -450,6 +452,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_inplace_vector``                               *unimplemented*
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_is_sufficiently_aligned``                      ``202411L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_is_virtual_base_of``                           ``202406L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_is_within_lifetime``                           *unimplemented*
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index aa896e85fcb1fe..ae1f887947fe06 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -81,7 +81,7 @@
 "`P3379R0 <https://wg21.link/P3379R0>`__","Constrain ``std::expected`` equality operators","2024-11 (Wrocław)","","",""
 "`P0472R2 <https://wg21.link/P0472R2>`__","Put ``std::monostate`` in ``<utility>``","2024-11 (Wrocław)","","",""
 "`P2862R1 <https://wg21.link/P2862R1>`__","``text_encoding::name()`` should never return null values","2024-11 (Wrocław)","","",""
-"`P2897R7 <https://wg21.link/P2897R7>`__","``aligned_accessor``: An ``mdspan`` accessor expressing pointer over-alignment","2024-11 (Wrocław)","","",""
+"`P2897R7 <https://wg21.link/P2897R7>`__","``aligned_accessor``: An ``mdspan`` accessor expressing pointer over-alignment","2024-11 (Wrocław)","|Complete|","20",""
 "`P3355R1 <https://wg21.link/P3355R1>`__","Fix ``submdspan`` for C++26","2024-11 (Wrocław)","","",""
 "`P3222R0 <https://wg21.link/P3222R0>`__","Fix C++26 by adding transposed special cases for P2642 layouts","2024-11 (Wrocław)","","",""
 "`P3050R2 <https://wg21.link/P3050R2>`__","Fix C++26 by optimizing ``linalg::conjugated`` for noncomplex value types","2024-11 (Wrocław)","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index f7721b1047b81e..ad7574b8993d08 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -529,6 +529,7 @@ set(files
   __math/traits.h
   __math/trigonometric_functions.h
   __mbstate_t.h
+  __mdspan/aligned_accessor.h
   __mdspan/default_accessor.h
   __mdspan/extents.h
   __mdspan/layout_left.h
@@ -553,6 +554,7 @@ set(files
   __memory/construct_at.h
   __memory/destruct_n.h
   __memory/inout_ptr.h
+  __memory/is_sufficiently_aligned.h
   __memory/noexcept_move_assign_container.h
   __memory/out_ptr.h
   __memory/pointer_traits.h
diff --git a/libcxx/include/__mdspan/aligned_accessor.h b/libcxx/include/__mdspan/aligned_accessor.h
new file mode 100644
index 00000000000000..441c144c11aebb
--- /dev/null
+++ b/libcxx/include/__mdspan/aligned_accessor.h
@@ -0,0 +1,86 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H
+#define _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__memory/assume_aligned.h>
+#include <__type_traits/is_abstract.h>
+#include <__type_traits/is_array.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/remove_const.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class _ElementType, size_t _ByteAlignment>
+struct aligned_accessor {
+  static_assert(_ByteAlignment != 0 && (_ByteAlignment & (_ByteAlignment - 1)) == 0,
+                "aligned_accessor: byte alignment must be a power of two");
+  static_assert(_ByteAlignment >= alignof(_ElementType), "aligned_accessor: insufficient byte alignment");
+  static_assert(!is_array_v<_ElementType>, "aligned_accessor: template argument may not be an array type");
+  static_assert(!is_abstract_v<_ElementType>, "aligned_accessor: template argument may not be an abstract class");
+
+  using offset_policy    = default_accessor<_ElementType>;
+  using element_type     = _ElementType;
+  using reference        = _ElementType&;
+  using data_handle_type = _ElementType*;
+
+  static constexpr size_t byte_alignment = _ByteAlignment;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr aligned_accessor() noexcept = default;
+
+  template <class _OtherElementType, size_t _OtherByteAlignment>
+    requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]> && _OtherByteAlignment >= byte_alignment)
+  _LIBCPP_HIDE_FROM_ABI constexpr aligned_accessor(aligned_accessor<_OtherElementType, _OtherByteAlignment>) noexcept {}
+
+  template <class _OtherElementType>
+    requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>)
+  _LIBCPP_HIDE_FROM_ABI explicit constexpr aligned_accessor(default_accessor<_OtherElementType>) noexcept {}
+
+  template <class _OtherElementType>
+    requires(is_convertible_v<element_type (*)[], _OtherElementType (*)[]>)
+  _LIBCPP_HIDE_FROM_ABI constexpr operator default_accessor<_OtherElementType>() const noexcept {
+    return {};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept {
+    return std::assume_aligned<byte_alignment>(__p)[__i];
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr typename offset_policy::data_handle_type
+  offset(data_handle_type __p, size_t __i) const noexcept {
+    return std::assume_aligned<byte_alignment>(__p) + __i;
+  }
+};
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H
diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h
index 3f9b35b185b167..ef8db9f1f9789a 100644
--- a/libcxx/include/__mdspan/mdspan.h
+++ b/libcxx/include/__mdspan/mdspan.h
@@ -20,6 +20,7 @@
 #include <__assert>
 #include <__config>
 #include <__fwd/mdspan.h>
+#include <__mdspan/aligned_accessor.h>
 #include <__mdspan/default_accessor.h>
 #include <__mdspan/extents.h>
 #include <__type_traits/extent.h>
@@ -266,13 +267,13 @@ class mdspan {
 #  if _LIBCPP_STD_VER >= 26
 template <class _ElementType, class... _OtherIndexTypes>
   requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0))
-explicit mdspan(_ElementType*,
-                _OtherIndexTypes...) -> mdspan<_ElementType, extents<size_t, __maybe_static_ext<_OtherIndexTypes>...>>;
+explicit mdspan(_ElementType*, _OtherIndexTypes...)
+    -> mdspan<_ElementType, extents<size_t, __maybe_static_ext<_OtherIndexTypes>...>>;
 #  else
 template <class _ElementType, class... _OtherIndexTypes>
   requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0))
-explicit mdspan(_ElementType*,
-                _OtherIndexTypes...) -> mdspan<_ElementType, dextents<size_t, sizeof...(_OtherIndexTypes)>>;
+explicit mdspan(_ElementType*, _OtherIndexTypes...)
+    -> mdspan<_ElementType, dextents<size_t, sizeof...(_OtherIndexTypes)>>;
 #  endif
 
 template <class _Pointer>
diff --git a/libcxx/include/__memory/is_sufficiently_aligned.h b/libcxx/include/__memory/is_sufficiently_aligned.h
new file mode 100644
index 00000000000000..4280920cabb4bc
--- /dev/null
+++ b/libcxx/include/__memory/is_sufficiently_aligned.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H
+#define _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <size_t _Alignment, class _Tp>
+_LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) {
+  return reinterpret_cast<uintptr_t>(__ptr) % _Alignment == 0;
+}
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index a67ed1834e3bde..61f1b210dd03af 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -33,10 +33,14 @@ namespace std {
   template<class ElementType>
     class default_accessor;
 
+  // [mdspan.accessor.aligned], class template aligned_accessor
+  template<class ElementType, size_t ByteAlignment>
+    class aligned_accessor; // since C++26
+
   // [mdspan.mdspan], class template mdspan
   template<class ElementType, class Extents, class LayoutPolicy = layout_right,
            class AccessorPolicy = default_accessor<ElementType>>
-    class mdspan; // not implemented yet
+    class mdspan;
 }
 
 // extents synopsis
@@ -269,6 +273,38 @@ namespace std {
   };
 }
 
+// aligned_accessor synopsis
+
+namespace std {
+  template<class ElementType, size_t ByteAlignment>
+  struct aligned_accessor {
+    using offset_policy = default_accessor<ElementType>;
+    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<class OtherElementType, size_t OtherByteAlignment>
+      constexpr aligned_accessor(
+        aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
+
+    template<class OtherElementType>
+      explicit constexpr aligned_accessor(
+        default_accessor<OtherElementType>) noexcept;
+
+    template<class OtherElementType>
+    constexpr operator default_accessor<OtherElementType>() 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;
+  };
+}
+
 // mdspan synopsis
 
 namespace std {
diff --git a/libcxx/include/memory b/libcxx/include/memory
index fc62606ea0fd33..a6400bd29f4437 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -912,6 +912,9 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
 template<size_t N, class T>
 [[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20
 
+template<size_t Alignment, class T>
+  bool is_sufficiently_aligned(T* ptr); // since C++26
+
 // [out.ptr.t], class template out_ptr_t
 template<class Smart, class Pointer, class... Args>
   class out_ptr_t;                                          // since c++23
@@ -945,6 +948,7 @@ template<class Pointer = void, class Smart, class... Args>
 #  include <__memory/allocator_traits.h>
 #  include <__memory/auto_ptr.h>
 #  include <__memory/inout_ptr.h>
+#  include <__memory/is_sufficiently_aligned.h>
 #  include <__memory/out_ptr.h>
 #  include <__memory/pointer_traits.h>
 #  include <__memory/raw_storage_iterator.h>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 07ab5649ae45cb..c4beb2dfa4f383 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1504,6 +1504,7 @@ module std [system] {
   }
 
   module mdspan {
+    module aligned_accessor   { header "__mdspan/aligned_accessor.h" }
     module default_accessor   { header "__mdspan/default_accessor.h" }
     module extents            { header "__mdspan/extents.h" }
     module fwd                { header "__fwd/mdspan.h" }
@@ -1539,6 +1540,7 @@ module std [system] {
     module destruct_n                         { header "__memory/destruct_n.h" }
     module fwd                                { header "__fwd/memory.h" }
     module inout_ptr                          { header "__memory/inout_ptr.h" }
+    module is_sufficiently_aligned            { header "__memory/is_sufficiently_aligned.h" }
     module noexcept_move_assign_container     { header "__memory/noexcept_move_assign_container.h" }
     module out_ptr                            { header "__memory/out_ptr.h" }
     module pointer_traits                     { header "__memory/pointer_traits.h" }
diff --git a/libcxx/modules/std/mdspan.inc b/libcxx/modules/std/mdspan.inc
index 5e65993383cdc0..c8cc78badb7d59 100644
--- a/libcxx/modules/std/mdspan.inc
+++ b/libcxx/modules/std/mdspan.inc
@@ -28,6 +28,11 @@ export namespace std {
   // [mdspan.accessor.default], class template default_accessor
   using std::default_accessor;
 
+#  if _LIBCPP_STD_VER >= 26
+  // [mdspan.accessor.aligned], class template aligned_accessor
+  using std::aligned_accessor;
+#  endif // _LIBCPP_STD_VER >= 26
+
   // [mdspan.mdspan], class template mdspan
   using std::mdspan;
 #endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc
index 82056e426d06c9..c25e9e3443e9cf 100644
--- a/libcxx/modules/std/memory.inc
+++ b/libcxx/modules/std/memory.inc
@@ -17,6 +17,9 @@ export namespace std {
   // [ptr.align], pointer alignment
   using std::align;
   using std::assume_aligned;
+#if _LIBCPP_STD_VER >= 26
+  using std::is_sufficiently_aligned;
+#endif
 
   // [obj.lifetime], explicit lifetime management
   //  using std::start_lifetime_as;
diff --git a/libcxx/test/std/containers/views/mdspan/aligned_accessor/access.pass.cpp b/libcxx/test/std/containers/views/mdspan/aligned_accessor/access.pass.cpp
new file mode 100644
index 00000000000000..145dc79eda73d4
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/aligned_accessor/access.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <mdspan>
+
+// constexpr reference access(data_handle_type p, size_t i) const noexcept;
+//
+// Effects: Equivalent to: return assume_aligned<byte_alignment>(p)[i];
+
+#include <mdspan>
+#include <cassert>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+template <class T, size_t N>
+constexpr void test_access() {
+  ElementPool<std::remove_const_t<T>, 10 + N> data;
+  T* ptr = data.get_ptr();
+  std::aligned_accessor<T, N> acc;
+  for (size_t i = 0; i < 10 + N; i++) {
+    if (reinterpret_cast<std::uintptr_t>(ptr + i) % N == 0) {
+      std::same_as<typename std::aligned_accessor<T, N>::reference> decltype(auto) x = acc.access(ptr, i);
+      ASSERT_NOEXCEPT(acc.access(ptr, i));
+      assert(&x == ptr + i);
+    }
+  }
+}
+
+template <class T>
+constexpr void test_it() {
+  constexpr size_t N = alignof(T);
+  test_access<T, N>();
+  test_access<T, 2 * N>();
+  test_access<T, 4 * N>();
+  test_access<T, 8 * N>();
+  test_access<T, 16 * N>();
+}
+
+constexpr bool test() {
+  test_it<int>();
+  test_it<const int>();
+  test_it<MinimalElementType>();
+  test_it<const MinimalElementType>();
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  //static_assert(test());
+  return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/aligned_accessor/byte_alignment.verify.cpp b/libcxx/test/std/containers/views/mdspan/aligned_accessor/byte_alignment.verify.cpp
new file mode 100644
index 00000000000000..fbc8386a72dede
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/aligned_accessor/byte_alignment.verify.cpp
@@ -0,0 +1,29 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <mdspan>
+
+// template<class ElementType, size_t ByteAlignment>
+// class aligned_accessor;
+
+// ByteAlignement is required to be a power of two and greater or equal to alignof(ElementType).
+
+#include <mdspan>
+
+void not_power_of_two() {
+  // expected-error-re@*:* {{static assertion failed {{.*}}aligned_accessor: byte alignment must be a power of two}}
+  [[maybe_unused]] std::aligned_accessor<int, 12> acc;
+}
+
+struct alignas(8) S {};
+
+void insufficiently_aligned() {
+  // expected-error-re@*:* {{static assertion failed {{.*}}aligned_accessor: insufficient byte alignment}}
+  [[maybe_unused]] std::aligned_accessor<S, 4> acc;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.conversion.from.default_accessor.pass.cpp b/libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.conversion.from.default_accessor.pass.cpp
new file mode 100644
index 00000000000000..339c12bb7c6c54
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/aligned_accessor/ctor.conversion.from.default_accessor.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <mdspan>
+//
+// template<class OtherElementType>
+//   explicit constexpr aligned_accessor(
+//     default_accessor<OtherElementType>) noexcept {}
+//
+// Constraints: is_convertible_v<OtherElementType(*)[], element_type(*)[]> is true.
+
+#include <mdspan>
+#include <cassert>
+#include <cstdint>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+struct Base {};
+struct Derived : public Base {};
+
+template <class FromT, class ToT, size_t ToN>
+constexpr void test_conversion() {
+  std::default_accessor<FromT> from;
+  ASSERT_NOEXCEPT(std::aligned_accessor<ToT, ToN>(from));
+  [[maybe_unused]] std::aligned_accessor<ToT, ToN> to(from);
+  // check that the constructor is explicit
+  static_assert(std::is_nothrow_constructible_v<std::aligned_accessor<ToT, ToN>, std::default_accessor<ToT>>);
+  static_assert(!std::is_convertible_v<std::default_accessor<ToT>, std::aligned_accessor<ToT, ToN>>);
+}
+
+template <class From, class To>
+constexpr void test_it() {
+  constexpr size_t N = alignof(To);
+  test_conversion<From, To, N>();
+  test_conversion<From, To, 2 * N>();
+  test_conversion<From, To, 4 * N>();
+  test_conversion<From, To, 8 * N>();
+  test_conversion<From, To, 16 * N>();
+  test_conversion<From, To, 32 * N>(...
[truncated]

Copy link

github-actions bot commented Jan 13, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.


#if _LIBCPP_STD_VER >= 26

template <size_t _Alignment, class _Tp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just add this to assume_aligned.h. These two seem to be quite closely related.

Align the pointer and check 10 elements
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P2897R7: aligned_accessor: An mdspan accessor expressing pointer over-alignment
4 participants