[libcxx-commits] [libcxx] 20c6b9d - [libc++][mdspan] Implement default_accessor
Christian Trott via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jul 14 10:53:12 PDT 2023
Author: Christian Trott
Date: 2023-07-14T11:52:40-06:00
New Revision: 20c6b9d451ca9af8d23fa7bfa5e18565e761450a
URL: https://github.com/llvm/llvm-project/commit/20c6b9d451ca9af8d23fa7bfa5e18565e761450a
DIFF: https://github.com/llvm/llvm-project/commit/20c6b9d451ca9af8d23fa7bfa5e18565e761450a.diff
LOG: [libc++][mdspan] Implement default_accessor
This commit implements default_accessor in support of C++23 mdspan
(https://wg21.link/p0009). default_accessor is the trivial accessor
using plain pointers and reference to element types.
Co-authored-by: Damien L-G <dalg24 at gmail.com>
Differential Revision: https://reviews.llvm.org/D153935
Added:
libcxx/include/__mdspan/default_accessor.h
libcxx/test/std/containers/views/mdspan/MinimalElementType.h
libcxx/test/std/containers/views/mdspan/default_accessor/access.pass.cpp
libcxx/test/std/containers/views/mdspan/default_accessor/ctor.conversion.pass.cpp
libcxx/test/std/containers/views/mdspan/default_accessor/ctor.default.pass.cpp
libcxx/test/std/containers/views/mdspan/default_accessor/element_type.verify.cpp
libcxx/test/std/containers/views/mdspan/default_accessor/offset.pass.cpp
libcxx/test/std/containers/views/mdspan/default_accessor/types.pass.cpp
Modified:
libcxx/docs/Status/Cxx23.rst
libcxx/include/CMakeLists.txt
libcxx/include/mdspan
libcxx/include/module.modulemap.in
libcxx/modules/std/mdspan.cppm
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst
index c1c8170c117e9b..6e6027354b6095 100644
--- a/libcxx/docs/Status/Cxx23.rst
+++ b/libcxx/docs/Status/Cxx23.rst
@@ -40,7 +40,7 @@ Paper Status
.. note::
- .. [#note-P0009R18] P0009R18: ``extents``, ``dextents``, ``layout_left``, and ``layout_right`` are implemented.
+ .. [#note-P0009R18] P0009R18: ``extents``, ``dextents``, ``layout_left``, ``layout_right``, and ``default_accessor`` are implemented.
.. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented.
.. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but
clang doesn't issue a diagnostic for deprecated using template declarations.
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 12cb12259e110a..640de9a8235c46 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -478,6 +478,7 @@ set(files
__locale_dir/locale_base_api/bsd_locale_fallbacks.h
__locale_dir/locale_base_api/locale_guard.h
__mbstate_t.h
+ __mdspan/default_accessor.h
__mdspan/extents.h
__mdspan/layout_left.h
__mdspan/layout_right.h
diff --git a/libcxx/include/__mdspan/default_accessor.h b/libcxx/include/__mdspan/default_accessor.h
new file mode 100644
index 00000000000000..1cc5f15545fc8c
--- /dev/null
+++ b/libcxx/include/__mdspan/default_accessor.h
@@ -0,0 +1,66 @@
+// -*- 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_DEFAULT_ACCESSOR_H
+#define _LIBCPP___MDSPAN_DEFAULT_ACCESSOR_H
+
+#include <__config>
+#include <__type_traits/is_abstract.h>
+#include <__type_traits/is_array.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/remove_const.h>
+#include <cinttypes>
+#include <cstddef>
+
+#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 >= 23
+
+template <class _ElementType>
+struct default_accessor {
+ static_assert(!is_array_v<_ElementType>, "default_accessor: template argument may not be an array type");
+ static_assert(!is_abstract_v<_ElementType>, "default_accessor: template argument may not be an abstract class");
+
+ using offset_policy = default_accessor;
+ using element_type = _ElementType;
+ using reference = _ElementType&;
+ using data_handle_type = _ElementType*;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr default_accessor() noexcept = default;
+ template <class _OtherElementType>
+ requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>)
+ _LIBCPP_HIDE_FROM_ABI constexpr default_accessor(default_accessor<_OtherElementType>) noexcept {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { return __p[__i]; }
+ _LIBCPP_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept {
+ return __p + __i;
+ }
+};
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_DEFAULT_ACCESSOR_H
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index 9116c859a8809f..701def50b40a4d 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -27,7 +27,7 @@ namespace std {
// [mdspan.accessor.default], class template default_accessor
template<class ElementType>
- class default_accessor; // not implemented yet
+ class default_accessor;
// [mdspan.mdspan], class template mdspan
template<class ElementType, class Extents, class LayoutPolicy = layout_right,
@@ -190,6 +190,24 @@ namespace std {
};
}
+// default_accessor synopsis
+
+namespace std {
+ template<class ElementType>
+ struct default_accessor {
+ using offset_policy = default_accessor;
+ using element_type = ElementType;
+ using reference = ElementType&;
+ using data_handle_type = ElementType*;
+
+ constexpr default_accessor() noexcept = default;
+ template<class OtherElementType>
+ constexpr default_accessor(default_accessor<OtherElementType>) noexcept;
+ constexpr reference access(data_handle_type p, size_t i) const noexcept;
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;
+ };
+}
+
*/
#ifndef _LIBCPP_MDSPAN
@@ -197,6 +215,7 @@ namespace std {
#include <__config>
#include <__fwd/mdspan.h>
+#include <__mdspan/default_accessor.h>
#include <__mdspan/extents.h>
#include <__mdspan/layout_left.h>
#include <__mdspan/layout_right.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 395e6fa318268e..19db0c89e015a2 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1239,6 +1239,7 @@ module std [system] {
export *
module __mdspan {
+ module default_accessor { private header "__mdspan/default_accessor.h" }
module extents {
private header "__mdspan/extents.h"
export array
diff --git a/libcxx/modules/std/mdspan.cppm b/libcxx/modules/std/mdspan.cppm
index eef6097e88ef4c..5023dfb925ea11 100644
--- a/libcxx/modules/std/mdspan.cppm
+++ b/libcxx/modules/std/mdspan.cppm
@@ -23,11 +23,9 @@ export namespace std {
using std::layout_right;
// using std::layout_stride;
-#if 0
- // [mdspan.accessor.default], class template default_accessor
+ // [mdspan.accessor.default], class template default_accessor
using std::default_accessor;
// [mdspan.mdspan], class template mdspan
- using std::mdspan;
-#endif
+ // using std::mdspan;
} // namespace std
diff --git a/libcxx/test/std/containers/views/mdspan/MinimalElementType.h b/libcxx/test/std/containers/views/mdspan/MinimalElementType.h
new file mode 100644
index 00000000000000..b1fbd6ed944d17
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/MinimalElementType.h
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_STD_CONTAINERS_VIEWS_MDSPAN_MINIMAL_ELEMENT_TYPE_H
+#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MINIMAL_ELEMENT_TYPE_H
+
+#include<memory>
+
+// Idiosyncratic element type for mdspan
+// Make sure we don't assume copyable, default constructible, movable etc.
+struct MinimalElementType {
+ int val;
+ constexpr MinimalElementType() = delete;
+ constexpr MinimalElementType(const MinimalElementType&) = delete;
+ constexpr explicit MinimalElementType(int v) noexcept : val(v){}
+ constexpr MinimalElementType& operator=(const MinimalElementType&) = delete;
+};
+
+// Helper class to create pointer to MinimalElementType
+template<class T, size_t N>
+struct ElementPool {
+ constexpr ElementPool() {
+ ptr_ = std::allocator<T>().allocate(N);
+ for (int i = 0; i != N; ++i)
+ std::construct_at(ptr_ + i, 42);
+ }
+
+ constexpr T* get_ptr() { return ptr_; }
+
+ constexpr ~ElementPool() {
+ for (int i = 0; i != N; ++i)
+ std::destroy_at(ptr_ + i);
+ std::allocator<T>().deallocate(ptr_, N);
+ }
+
+private:
+ T* ptr_;
+};
+
+#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MINIMAL_ELEMENT_TYPE_H
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/access.pass.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/access.pass.cpp
new file mode 100644
index 00000000000000..a15ad6895254e6
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/access.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <mdspan>
+
+// constexpr reference access(data_handle_type p, size_t i) const noexcept;
+//
+// Effects: Equivalent to: return p[i];
+
+#include <mdspan>
+#include <cassert>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+template <class T>
+constexpr void test_access() {
+ ElementPool<std::remove_const_t<T>, 10> data;
+ T* ptr = data.get_ptr();
+ std::default_accessor<T> acc;
+ for(int i = 0; i < 10; i++) {
+ static_assert(std::is_same_v<decltype(acc.access(ptr, i)), typename std::default_accessor<T>::reference>);
+ ASSERT_NOEXCEPT(acc.access(ptr, i));
+ assert(&acc.access(ptr, i) == ptr + i);
+ }
+}
+
+constexpr bool test() {
+ test_access<int>();
+ test_access<const int>();
+ test_access<MinimalElementType>();
+ test_access<const MinimalElementType>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.conversion.pass.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.conversion.pass.cpp
new file mode 100644
index 00000000000000..299d98f0b2d01d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.conversion.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <mdspan>
+//
+// Test converting constructor:
+//
+// template<class OtherElementType>
+// constexpr default_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>
+constexpr void test_conversion() {
+ std::default_accessor<FromT> acc_from;
+ ASSERT_NOEXCEPT(std::default_accessor<ToT>(acc_from));
+ [[maybe_unused]] std::default_accessor<ToT> acc_to(acc_from);
+}
+
+constexpr bool test() {
+ // default accessor conversion largely behaves like pointer conversion
+ test_conversion<int, int>();
+ test_conversion<int, const int>();
+ test_conversion<const int, const int>();
+ test_conversion<MinimalElementType, MinimalElementType>();
+ test_conversion<MinimalElementType, const MinimalElementType>();
+ test_conversion<const MinimalElementType, const MinimalElementType>();
+
+ // char is convertible to int, but accessors are not
+ static_assert(!std::is_constructible_v<std::default_accessor<int>, std::default_accessor<char>>);
+ // don't allow conversion from const elements to non-const
+ static_assert(!std::is_constructible_v<std::default_accessor<int>, std::default_accessor<const int>>);
+ // MinimalElementType is constructible from int, but accessors should not be convertible
+ static_assert(!std::is_constructible_v<std::default_accessor<MinimalElementType>, std::default_accessor<int>>);
+ // don't allow conversion from const elements to non-const
+ static_assert(!std::is_constructible_v<std::default_accessor<MinimalElementType>, std::default_accessor<const MinimalElementType>>);
+ // don't allow conversion from Base to Derived
+ static_assert(!std::is_constructible_v<std::default_accessor<Derived>, std::default_accessor<Base>>);
+ // don't allow conversion from Derived to Base
+ static_assert(!std::is_constructible_v<std::default_accessor<Base>, std::default_accessor<Derived>>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..28bd7c0fcb2b15
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/ctor.default.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <mdspan>
+
+// Test default construction:
+//
+// constexpr default_accessor() noexcept = default;
+
+#include <mdspan>
+#include <cassert>
+#include <cstdint>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+template <class T>
+constexpr void test_construction() {
+ ASSERT_NOEXCEPT(std::default_accessor<T>{});
+ [[maybe_unused]] std::default_accessor<T> acc;
+ static_assert(std::is_trivially_default_constructible_v<std::default_accessor<T>>);
+}
+
+constexpr bool test() {
+ test_construction<int>();
+ test_construction<const int>();
+ test_construction<MinimalElementType>();
+ test_construction<const MinimalElementType>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/element_type.verify.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/element_type.verify.cpp
new file mode 100644
index 00000000000000..d62171e722da2f
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/element_type.verify.cpp
@@ -0,0 +1,33 @@
+//
+// 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
+
+// <mdspan>
+
+// template<class ElementType>
+// class default_accessor;
+
+// ElementType is required to be a complete object type that is neither an abstract class type nor an array type.
+
+#include <mdspan>
+
+class AbstractClass {
+public:
+ virtual void method() = 0;
+};
+
+void not_abstract_class() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}default_accessor: template argument may not be an abstract class}}
+ [[maybe_unused]] std::default_accessor<AbstractClass> acc;
+}
+
+void not_array_type() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}default_accessor: template argument may not be an array type}}
+ [[maybe_unused]] std::default_accessor<int[5]> acc;
+}
+
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/offset.pass.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/offset.pass.cpp
new file mode 100644
index 00000000000000..5842ff91796347
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/offset.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <mdspan>
+
+// constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;
+//
+// Effects: Equivalent to: return p+i;
+
+#include <mdspan>
+#include <cassert>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+template <class T>
+constexpr void test_offset() {
+ ElementPool<std::remove_const_t<T>, 10> data;
+ T* ptr = data.get_ptr();
+ std::default_accessor<T> acc;
+ for(int i = 0; i < 10; i++) {
+ static_assert(std::is_same_v<decltype(acc.offset(ptr, i)), typename std::default_accessor<T>::data_handle_type>);
+ ASSERT_NOEXCEPT(acc.offset(ptr, i));
+ assert(acc.offset(ptr, i) == ptr + i);
+ }
+}
+
+constexpr bool test() {
+ test_offset<int>();
+ test_offset<const int>();
+ test_offset<MinimalElementType>();
+ test_offset<const MinimalElementType>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/default_accessor/types.pass.cpp b/libcxx/test/std/containers/views/mdspan/default_accessor/types.pass.cpp
new file mode 100644
index 00000000000000..025b992f97aeff
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/default_accessor/types.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <mdspan>
+
+// template<class ElementType>
+// struct default_accessor {
+// using offset_policy = default_accessor;
+// using element_type = ElementType;
+// using reference = ElementType&;
+// using data_handle_type = ElementType*;
+// ...
+// };
+//
+// Each specialization of default_accessor is a trivially copyable type that models semiregular.
+
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+
+template <class T>
+void test() {
+ using A = std::default_accessor<T>;
+ ASSERT_SAME_TYPE(typename A::offset_policy, A);
+ ASSERT_SAME_TYPE(typename A::element_type, T);
+ ASSERT_SAME_TYPE(typename A::reference, T&);
+ ASSERT_SAME_TYPE(typename A::data_handle_type, T*);
+
+ static_assert(std::semiregular<A>);
+ static_assert(std::is_trivially_copyable_v<A>);
+
+ LIBCPP_STATIC_ASSERT(std::is_empty_v<A>);
+}
+
+int main(int, char**) {
+ test<int>();
+ test<const int>();
+ test<MinimalElementType>();
+ test<const MinimalElementType>();
+ return 0;
+}
More information about the libcxx-commits
mailing list