diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst --- a/libcxx/docs/Status/Cxx23.rst +++ b/libcxx/docs/Status/Cxx23.rst @@ -40,7 +40,7 @@ .. 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 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -478,6 +478,7 @@ __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 --- /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 +#include + +#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 +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 + 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 --- a/libcxx/include/mdspan +++ b/libcxx/include/mdspan @@ -27,7 +27,7 @@ // [mdspan.accessor.default], class template default_accessor template - class default_accessor; // not implemented yet + class default_accessor; // [mdspan.mdspan], class template mdspan template + 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 + constexpr default_accessor(default_accessor) 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 @@ #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 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1239,6 +1239,7 @@ 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 --- a/libcxx/modules/std/mdspan.cppm +++ b/libcxx/modules/std/mdspan.cppm @@ -23,11 +23,9 @@ 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 --- /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 + +// 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 +struct ElementPool { + constexpr ElementPool() { + ptr_ = std::allocator().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().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 --- /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 + +// + +// constexpr reference access(data_handle_type p, size_t i) const noexcept; +// +// Effects: Equivalent to: return p[i]; + +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" + +template +constexpr void test_access() { + ElementPool, 10> data; + T* ptr = data.get_ptr(); + std::default_accessor acc; + for(int i = 0; i < 10; i++) { + static_assert(std::is_same_v::reference>); + ASSERT_NOEXCEPT(acc.access(ptr, i)); + assert(&acc.access(ptr, i) == ptr + i); + } +} + +constexpr bool test() { + test_access(); + test_access(); + test_access(); + test_access(); + 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 --- /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 + +// +// +// Test converting constructor: +// +// template +// constexpr default_accessor(default_accessor) noexcept {} +// +// Constraints: is_convertible_v is true. + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" + +struct Base {}; +struct Derived: public Base {}; + +template +constexpr void test_conversion() { + std::default_accessor acc_from; + ASSERT_NOEXCEPT(std::default_accessor(acc_from)); + [[maybe_unused]] std::default_accessor acc_to(acc_from); +} + +constexpr bool test() { + // default accessor conversion largely behaves like pointer conversion + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + test_conversion(); + + // char is convertible to int, but accessors are not + static_assert(!std::is_constructible_v, std::default_accessor>); + // don't allow conversion from const elements to non-const + static_assert(!std::is_constructible_v, std::default_accessor>); + // MinimalElementType is constructible from int, but accessors should not be convertible + static_assert(!std::is_constructible_v, std::default_accessor>); + // don't allow conversion from const elements to non-const + static_assert(!std::is_constructible_v, std::default_accessor>); + // don't allow conversion from Base to Derived + static_assert(!std::is_constructible_v, std::default_accessor>); + // don't allow conversion from Derived to Base + static_assert(!std::is_constructible_v, std::default_accessor>); + + 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 --- /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 + +// + +// Test default construction: +// +// constexpr default_accessor() noexcept = default; + +#include +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" + +template +constexpr void test_construction() { + ASSERT_NOEXCEPT(std::default_accessor{}); + [[maybe_unused]] std::default_accessor acc; + static_assert(std::is_trivially_default_constructible_v>); +} + +constexpr bool test() { + test_construction(); + test_construction(); + test_construction(); + test_construction(); + 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 --- /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 + +// + +// template +// class default_accessor; + +// ElementType is required to be a complete object type that is neither an abstract class type nor an array type. + +#include + +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 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 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 --- /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 + +// + +// constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept; +// +// Effects: Equivalent to: return p+i; + +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" + +template +constexpr void test_offset() { + ElementPool, 10> data; + T* ptr = data.get_ptr(); + std::default_accessor acc; + for(int i = 0; i < 10; i++) { + static_assert(std::is_same_v::data_handle_type>); + ASSERT_NOEXCEPT(acc.offset(ptr, i)); + assert(acc.offset(ptr, i) == ptr + i); + } +} + +constexpr bool test() { + test_offset(); + test_offset(); + test_offset(); + test_offset(); + 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 --- /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 + +// + +// template +// 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 +#include +#include +#include + +#include "test_macros.h" + +#include "../MinimalElementType.h" + +template +void test() { + using A = std::default_accessor; + 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); + static_assert(std::is_trivially_copyable_v); + + LIBCPP_STATIC_ASSERT(std::is_empty_v); +} + +int main(int, char**) { + test(); + test(); + test(); + test(); + return 0; +}