From 3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Sat, 11 Jul 2026 22:48:30 +0800 Subject: lib: establish Zircon libc++ and KTL foundation --- .../include/c++/v1/__mdspan/aligned_accessor.h | 87 ++++ .../include/c++/v1/__mdspan/default_accessor.h | 65 +++ .../libcxx/include/c++/v1/__mdspan/extents.h | 536 +++++++++++++++++++++ .../libcxx/include/c++/v1/__mdspan/layout_left.h | 203 ++++++++ .../libcxx/include/c++/v1/__mdspan/layout_right.h | 201 ++++++++ .../libcxx/include/c++/v1/__mdspan/layout_stride.h | 370 ++++++++++++++ .../libcxx/include/c++/v1/__mdspan/mdspan.h | 328 +++++++++++++ 7 files changed, 1790 insertions(+) create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/aligned_accessor.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/default_accessor.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/extents.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/layout_left.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/layout_right.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/layout_stride.h create mode 100644 third_party/libcxx/include/c++/v1/__mdspan/mdspan.h (limited to 'third_party/libcxx/include/c++/v1/__mdspan') diff --git a/third_party/libcxx/include/c++/v1/__mdspan/aligned_accessor.h b/third_party/libcxx/include/c++/v1/__mdspan/aligned_accessor.h new file mode 100644 index 0000000..2b8d4c5 --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/aligned_accessor.h @@ -0,0 +1,87 @@ +// -*- 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 <__mdspan/default_accessor.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 +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 + requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]> && _OtherByteAlignment >= byte_alignment) + _LIBCPP_HIDE_FROM_ABI constexpr aligned_accessor(aligned_accessor<_OtherElementType, _OtherByteAlignment>) noexcept {} + + template + requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>) + _LIBCPP_HIDE_FROM_ABI explicit constexpr aligned_accessor(default_accessor<_OtherElementType>) noexcept {} + + template + requires(is_convertible_v) + _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(__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(__p) + __i; + } +}; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H diff --git a/third_party/libcxx/include/c++/v1/__mdspan/default_accessor.h b/third_party/libcxx/include/c++/v1/__mdspan/default_accessor.h new file mode 100644 index 0000000..d6f3ddb --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/default_accessor.h @@ -0,0 +1,65 @@ +// -*- 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 <__cstddef/size_t.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 >= 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/third_party/libcxx/include/c++/v1/__mdspan/extents.h b/third_party/libcxx/include/c++/v1/__mdspan/extents.h new file mode 100644 index 0000000..d16bbd2 --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/extents.h @@ -0,0 +1,536 @@ +// -*- 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_EXTENTS_H +#define _LIBCPP___MDSPAN_EXTENTS_H + +#include <__assert> +#include <__config> + +#include <__concepts/arithmetic.h> +#include <__type_traits/common_type.h> +#include <__type_traits/integer_traits.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_signed.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/integer_sequence.h> +#include <__utility/unreachable.h> +#include +#include +#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 + +namespace __mdspan_detail { + +// ------------------------------------------------------------------ +// ------------ __static_array -------------------------------------- +// ------------------------------------------------------------------ +// array like class which provides an array of static values with get +template +struct __static_array { + static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...}; + +public: + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); } + _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() { + return __get(_Index); + } +}; + +// ------------------------------------------------------------------ +// ------------ __possibly_empty_array ----------------------------- +// ------------------------------------------------------------------ + +// array like class which provides get function and operator [], and +// has a specialization for the size 0 case. +// This is needed to make the __maybe_static_array be truly empty, for +// all static values. + +template +struct __possibly_empty_array { + _Tp __vals_[_Size]; + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; } +}; + +template +struct __possibly_empty_array<_Tp, 0> { + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); } +}; + +// ------------------------------------------------------------------ +// ------------ static_partial_sums --------------------------------- +// ------------------------------------------------------------------ + +// Provides a compile time partial sum one can index into + +template +struct __static_partial_sums { + _LIBCPP_HIDE_FROM_ABI static constexpr array __static_partial_sums_impl() { + array __values{_Values...}; + array __partial_sums{{}}; + size_t __running_sum = 0; + for (int __i = 0; __i != sizeof...(_Values); ++__i) { + __partial_sums[__i] = __running_sum; + __running_sum += __values[__i]; + } + return __partial_sums; + } + static constexpr array __result{__static_partial_sums_impl()}; + + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; } +}; + +// ------------------------------------------------------------------ +// ------------ __maybe_static_array -------------------------------- +// ------------------------------------------------------------------ + +// array like class which has a mix of static and runtime values but +// only stores the runtime values. +// The type of the static and the runtime values can be different. +// The position of a dynamic value is indicated through a tag value. +template +struct __maybe_static_array { + static_assert(is_convertible<_TStatic, _TDynamic>::value, + "__maybe_static_array: _TStatic must be convertible to _TDynamic"); + static_assert(is_convertible<_TDynamic, _TStatic>::value, + "__maybe_static_array: _TDynamic must be convertible to _TStatic"); + +private: + // Static values member + static constexpr size_t __size_ = sizeof...(_Values); + static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0); + using _StaticValues _LIBCPP_NODEBUG = __static_array<_TStatic, _Values...>; + using _DynamicValues _LIBCPP_NODEBUG = __possibly_empty_array<_TDynamic, __size_dynamic_>; + + // Dynamic values member + _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_; + + // static mapping of indices to the position in the dynamic values array + using _DynamicIdxMap _LIBCPP_NODEBUG = __static_partial_sums(_Values == _DynTag)...>; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept { + return _DynamicValues{((void)_Indices, 0)...}; + } + +public: + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept + : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {} + + // constructors from dynamic values only -- this covers the case for rank() == 0 + template + requires(sizeof...(_DynVals) == __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) + : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {} + + template + requires(_Size == __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) { + if constexpr (_Size > 0) { + for (size_t __i = 0; __i < _Size; __i++) + __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]); + } + } + + // constructors from all values -- here rank will be greater than 0 + template + requires(sizeof...(_DynVals) != __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) { + static_assert(sizeof...(_DynVals) == __size_, "Invalid number of values."); + _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...}; + for (size_t __i = 0; __i < __size_; __i++) { + _TStatic __static_val = _StaticValues::__get(__i); + if (__static_val == _DynTag) { + __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i]; + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan>; my_mdspan_t = m(new int[5], 5); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __values[__i] == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); + } + } + + template + requires(_Size != __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) { + static_assert(_Size == __size_ || __size_ == dynamic_extent); + for (size_t __i = 0; __i < __size_; __i++) { + _TStatic __static_val = _StaticValues::__get(__i); + if (__static_val == _DynTag) { + __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]); + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan>; my_mdspan_t = m(new int[N], span(&N)); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); + } + } + + // access functions + _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + return _StaticValues::__get(__i); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + _TStatic __static_val = _StaticValues::__get(__i); + return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val); + } + _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + return __value(__i); + } + + // observers + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; } +}; + +// Function to check whether a value is representable as another type +// value must be a positive integer otherwise returns false +// if _From is not an integral, we just check positivity +template + requires(integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { + using _To_u = make_unsigned_t<_To>; + using _From_u = make_unsigned_t<_From>; + if constexpr (is_signed_v<_From>) { + if (__value < 0) + return false; + } + if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) { + return true; + } else { + return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value); + } +} + +template + requires(!integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { + if constexpr (is_signed_v<_To>) { + if (static_cast<_To>(__value) < 0) + return false; + } + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) { + return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) { + for (size_t __i = 0; __i < _Size; __i++) + if (!__mdspan_detail::__is_representable_as<_To>(__values[__i])) + return false; + return true; +} + +} // namespace __mdspan_detail + +// ------------------------------------------------------------------ +// ------------ extents --------------------------------------------- +// ------------------------------------------------------------------ + +// Class to describe the extents of a multi dimensional array. +// Used by mdspan, mdarray and layout mappings. +// See ISO C++ standard [mdspan.extents] + +template +class extents { +public: + // typedefs for integral types used + using index_type = _IndexType; + using size_type = make_unsigned_t; + using rank_type = size_t; + + static_assert(__signed_or_unsigned_integer, + "extents::index_type must be a signed or unsigned integer type"); + static_assert(((__mdspan_detail::__is_representable_as(_Extents) || (_Extents == dynamic_extent)) && ...), + "extents ctor: arguments must be representable as index_type and nonnegative"); + +private: + static constexpr rank_type __rank_ = sizeof...(_Extents); + static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0); + + // internal storage type using __maybe_static_array + using _Values _LIBCPP_NODEBUG = + __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>; + [[no_unique_address]] _Values __vals_; + +public: + // [mdspan.extents.obs], observers of multidimensional index space + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + return __vals_.__value(__r); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + return _Values::__static_value(__r); + } + + // [mdspan.extents.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default; + + // Construction from just dynamic or all values. + // Precondition check is deferred to __maybe_static_array constructor + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_)) + _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept + : __vals_(static_cast(__dynvals)...) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents(200u)); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(__dynvals...), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + (_Size == __rank_ || _Size == __rank_dynamic_)) + explicit(_Size != __rank_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept + : __vals_(span(__exts)) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents(array(200))); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(span(__exts)), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + (_Size == __rank_ || _Size == __rank_dynamic_)) + explicit(_Size != __rank_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept + : __vals_(__exts) { + // Not catching this could lead to out of bounds errors later + // e.g. array a{200u}; mdspan> m(ptr, extents(span(a))); leads to an extent of -56 + // on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(__exts), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + +private: + // Function to construct extents storage from other extents. + template + requires(_Idx < __rank_) + _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents( + integral_constant, + integral_constant, + const _OtherExtents& __exts, + _DynamicValues... __dynamic_values) noexcept { + if constexpr (static_extent(_Idx) == dynamic_extent) + return __construct_vals_from_extents( + integral_constant(), + integral_constant(), + __exts, + __dynamic_values..., + __exts.extent(_Idx)); + else + return __construct_vals_from_extents( + integral_constant(), integral_constant(), __exts, __dynamic_values...); + } + + template + requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_)) + _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents( + integral_constant, + integral_constant, + const _OtherExtents&, + _DynamicValues... __dynamic_values) noexcept { + return _Values{static_cast(__dynamic_values)...}; + } + +public: + // Converting constructor from other extents specializations + template + requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) && + ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...)) + explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) || + (static_cast>(numeric_limits::max()) < + static_cast>(numeric_limits<_OtherIndexType>::max()))) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept + : __vals_( + __construct_vals_from_extents(integral_constant(), integral_constant(), __other)) { + if constexpr (rank() > 0) { + for (size_t __r = 0; __r < rank(); __r++) { + if constexpr (static_cast>(numeric_limits::max()) < + static_cast>(numeric_limits<_OtherIndexType>::max())) { + // Not catching this could lead to out of bounds errors later + // e.g. dextents> e(dextents(200)) leads to an extent of -56 on e + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.extent(__r)), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + // Not catching this could lead to out of bounds errors later + // e.g. mdspan> m = mdspan>(new int[5], 5); + // Right-hand-side construction was ok, but m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + (_Values::__static_value(__r) == dynamic_extent) || + (static_cast(__other.extent(__r)) == static_cast(_Values::__static_value(__r))), + "extents construction: mismatch of provided arguments with static extents."); + } + } + } + + // Comparison operator + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept { + if constexpr (rank() != sizeof...(_OtherExtents)) { + return false; + } else { + for (rank_type __r = 0; __r < __rank_; __r++) { + // avoid warning when comparing signed and unsigner integers and pick the wider of two types + using _CommonType = common_type_t; + if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) { + return false; + } + } + } + return true; + } +}; + +// Recursive helper classes to implement dextents alias for extents +namespace __mdspan_detail { + +template > +struct __make_dextents; + +template +struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> { + using type _LIBCPP_NODEBUG = + typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type; +}; + +template +struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> { + using type _LIBCPP_NODEBUG = extents<_IndexType, _ExtentsPack...>; +}; + +} // namespace __mdspan_detail + +// [mdspan.extents.dextents], alias template +template +using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type; + +# if _LIBCPP_STD_VER >= 26 +// [mdspan.extents.dims], alias template `dims` +template +using dims = dextents<_IndexType, _Rank>; +# endif + +// Deduction guide for extents +# if _LIBCPP_STD_VER >= 26 +template + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents...>; +# else +template + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents; +# endif + +namespace __mdspan_detail { + +// Helper type traits for identifying a class as extents. +template +struct __is_extents : false_type {}; + +template +struct __is_extents> : true_type {}; + +template +inline constexpr bool __is_extents_v = __is_extents<_Tp>::value; + +// Function to check whether a set of indices are a multidimensional +// index into extents. This is a word of power in the C++ standard +// requiring that the indices are larger than 0 and smaller than +// the respective extents. + +template + requires(integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_From>) { + if (__value < 0) + return false; + } + using _Tp = common_type_t<_IndexType, _From>; + return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent); +} + +template + requires(!integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_IndexType>) { + if (static_cast<_IndexType>(__value) < 0) + return false; + } + return static_cast<_IndexType>(__value) < __extent; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool +__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) { + return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) { + return __mdspan_detail::__is_multidimensional_index_in_impl( + make_index_sequence<_Extents::rank()>(), __ext, __values...); +} + +} // namespace __mdspan_detail + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_EXTENTS_H diff --git a/third_party/libcxx/include/c++/v1/__mdspan/layout_left.h b/third_party/libcxx/include/c++/v1/__mdspan/layout_left.h new file mode 100644 index 0000000..fb1b595 --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/layout_left.h @@ -0,0 +1,203 @@ +// -*- 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_LAYOUT_LEFT_H +#define _LIBCPP___MDSPAN_LAYOUT_LEFT_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__memory/addressof.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/integer_sequence.h> +#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 +class layout_left::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_left::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = extents_type::index_type; + using size_type = extents_type::size_type; + using rank_type = extents_type::rank_type; + using layout_type = layout_left; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod)); + if (__overflowed) + return false; + } + return true; + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_left::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.left.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(dextents(40,40)); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_left::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(mapping>(dextents(40,40))); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_left::mapping> map( + // layout_right::mapping>(dextents(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + if constexpr (extents_type::rank() > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&]() { + using _CommonType = common_type_t; + for (rank_type __r = 0; __r < extents_type::rank(); __r++) + if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r))) + return false; + return true; + }()), + "layout_left::mapping from layout_stride ctor: strides are not compatible with layout_left."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping from layout_stride ctor: other.required_span_size() must be representable as " + "index_type."); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.left.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_left::mapping: out of bounds indexing"); + array __idx_a{static_cast(__idx)...}; + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = __idx_a[extents_type::rank() - 1 - _Pos] + __extents_.extent(extents_type::rank() - 1 - _Pos) * __res), + ...); + return __res; + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept + requires(extents_type::rank() > 0) + { + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = 0; __i < __r; __i++) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_LEFT_H diff --git a/third_party/libcxx/include/c++/v1/__mdspan/layout_right.h b/third_party/libcxx/include/c++/v1/__mdspan/layout_right.h new file mode 100644 index 0000000..7cb8280 --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/layout_right.h @@ -0,0 +1,201 @@ +// -*- 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_LAYOUT_RIGHT_H +#define _LIBCPP___MDSPAN_LAYOUT_RIGHT_H + +#include <__assert> +#include <__config> +#include <__cstddef/size_t.h> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__memory/addressof.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/integer_sequence.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 >= 23 + +template +class layout_right::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_right::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = extents_type::index_type; + using size_type = extents_type::size_type; + using rank_type = extents_type::rank_type; + using layout_type = layout_right; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod)); + if (__overflowed) + return false; + } + return true; + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_right::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.right.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(dextents(40,40)); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_right::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(mapping>(dextents(40,40))); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_right::mapping> map( + // layout_left::mapping>(dextents(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + if constexpr (extents_type::rank() > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&]() { + using _CommonType = common_type_t; + for (rank_type __r = 0; __r < extents_type::rank(); __r++) + if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r))) + return false; + return true; + }()), + "layout_right::mapping from layout_stride ctor: strides are not compatible with layout_right."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping from layout_stride ctor: other.required_span_size() must be representable as " + "index_type."); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_right::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = static_cast(__idx) + __extents_.extent(_Pos) * __res), ...); + return __res; + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept + requires(extents_type::rank() > 0) + { + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_RIGHT_H diff --git a/third_party/libcxx/include/c++/v1/__mdspan/layout_stride.h b/third_party/libcxx/include/c++/v1/__mdspan/layout_stride.h new file mode 100644 index 0000000..66d5a7f --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/layout_stride.h @@ -0,0 +1,370 @@ +// -*- 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_LAYOUT_STRIDE_H +#define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H + +#include <__assert> +#include <__concepts/same_as.h> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__memory/addressof.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__utility/as_const.h> +#include <__utility/integer_sequence.h> +#include <__utility/swap.h> +#include +#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 + +namespace __mdspan_detail { +template +constexpr bool __is_mapping_of = + is_same_v, _Mapping>; + +template +concept __layout_mapping_alike = requires { + requires __is_mapping_of; + requires __is_extents_v; + { _Mapping::is_always_strided() } -> same_as; + { _Mapping::is_always_exhaustive() } -> same_as; + { _Mapping::is_always_unique() } -> same_as; + bool_constant<_Mapping::is_always_strided()>::value; + bool_constant<_Mapping::is_always_exhaustive()>::value; + bool_constant<_Mapping::is_always_unique()>::value; +}; +} // namespace __mdspan_detail + +template +class layout_stride::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_stride::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = extents_type::index_type; + using size_type = extents_type::size_type; + using rank_type = extents_type::rank_type; + using layout_type = layout_stride; + +private: + static constexpr rank_type __rank_ = extents_type::rank(); + + // Used for default construction check and mandates + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (__rank_ == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < __rank_; __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod)); + if (__overflowed) + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool + __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) { + if constexpr (__rank_ == 0) + return true; + + index_type __size = 1; + for (rank_type __r = 0; __r < __rank_; __r++) { + // We can only check correct conversion of _OtherIndexType if it is an integral + if constexpr (is_integral_v<_OtherIndexType>) { + using _CommonType = common_type_t; + if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits::max())) + return false; + } + if (__ext.extent(__r) == static_cast(0)) + return true; + index_type __prod = (__ext.extent(__r) - 1); + bool __overflowed_mul = + __builtin_mul_overflow(__prod, static_cast(__strides[__r]), std::addressof(__prod)); + if (__overflowed_mul) + return false; + bool __overflowed_add = __builtin_add_overflow(__size, __prod, std::addressof(__size)); + if (__overflowed_add) + return false; + } + return true; + } + + // compute offset of a strided layout mapping + template + _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) { + if constexpr (_StridedMapping::extents_type::rank() == 0) { + return static_cast(__mapping()); + } else if (__mapping.required_span_size() == static_cast(0)) { + return static_cast(0); + } else { + return [&](index_sequence<_Pos...>) { + return static_cast(__mapping((_Pos ? 0 : 0)...)); + }(make_index_sequence<__rank_>()); + } + } + + // compute the permutation for sorting the stride array + // we never actually sort the stride array + _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array& __permute) const { + for (rank_type __i = __rank_ - 1; __i > 0; __i--) { + for (rank_type __r = 0; __r < __i; __r++) { + if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) { + swap(__permute[__r], __permute[__r + 1]); + } else { + // if two strides are the same then one of the associated extents must be 1 or 0 + // both could be, but you can't have one larger than 1 come first + if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) && + (__extents_.extent(__permute[__r]) > static_cast(1))) + swap(__permute[__r], __permute[__r + 1]); + } + } + } + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_stride::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.stride.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) { + // Note the nominal precondition is covered by above static assert since + // if rank_dynamic is != 0 required_span_size is zero for default construction + if constexpr (__rank_ > 0) { + index_type __stride = 1; + for (rank_type __r = __rank_ - 1; __r > static_cast(0); __r--) { + __strides_[__r] = __stride; + __stride *= __extents_.extent(__r); + } + __strides_[0] = __stride; + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept + : __extents_(__ext), __strides_([&](index_sequence<_Pos...>) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(std::as_const(__strides[_Pos]))...}; + }(make_index_sequence<__rank_>())) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&](index_sequence<_Pos...>) { + // For integrals we can do a pre-conversion check, for other types not + if constexpr (is_integral_v<_OtherIndexType>) { + return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true); + } else { + return ((static_cast(__strides[_Pos]) > static_cast(0)) && ... && true); + } + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: all strides must be greater than 0"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext, __strides), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + if constexpr (__rank_ > 1) { + _LIBCPP_ASSERT_UNCATEGORIZED( + ([&](index_sequence<_Pos...>) { + // basically sort the dimensions based on strides and extents, sorting is represented in permute array + array __permute{_Pos...}; + __bubble_sort_by_strides(__permute); + + // check that this permutations represents a growing set + for (rank_type __i = 1; __i < __rank_; __i++) + if (static_cast(__strides[__permute[__i]]) < + static_cast(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1])) + return false; + return true; + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); + } + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, + const array<_OtherIndexType, __rank_>& __strides) noexcept + : mapping(__ext, span(__strides)) {} + + template + requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> && + is_constructible_v && + _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI constexpr explicit( + !(is_convertible_v && + (__mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of))) + mapping(const _StridedLayoutMapping& __other) noexcept + : __extents_(__other.extents()), __strides_([&](index_sequence<_Pos...>) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(__other.stride(_Pos))...}; + } else { + return __mdspan_detail::__possibly_empty_array{}; + } + }(make_index_sequence<__rank_>())) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&](index_sequence<_Pos...>) { + return ((static_cast(__other.stride(_Pos)) > static_cast(0)) && ... && true); + }(make_index_sequence<__rank_>())), + "layout_stride::mapping converting ctor: all strides must be greater than 0"); + } + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast(0) == __offset(__other), + "layout_stride::mapping converting ctor: base offset of mapping must be zero."); + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.stride.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr array strides() const noexcept { + return [&](index_sequence<_Pos...>) { + return array{__strides_[_Pos]...}; + }(make_index_sequence<__rank_>()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + if constexpr (__rank_ == 0) { + return static_cast(1); + } else { + return [&](index_sequence<_Pos...>) { + if ((__extents_.extent(_Pos) * ... * 1) == 0) + return static_cast(0); + + return static_cast( + static_cast(1) + (((__extents_.extent(_Pos) - static_cast(1)) * __strides_[_Pos]) + + ... + static_cast(0))); + }(make_index_sequence<__rank_>()); + } + } + + template + requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_stride::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + return ((static_cast(__idx) * __strides_[_Pos]) + ... + index_type(0)); + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + // The answer of this function is fairly complex in the case where one or more + // extents are zero. + // Technically it is meaningless to query is_exhaustive() in that case, but unfortunately + // the way the standard defines this function, we can't give a simple true or false then. + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept { + if constexpr (__rank_ == 0) + return true; + else { + index_type __span_size = required_span_size(); + if (__span_size == static_cast(0)) { + if constexpr (__rank_ == 1) + return __strides_[0] == 1; + else { + rank_type __r_largest = 0; + for (rank_type __r = 1; __r < __rank_; __r++) + if (__strides_[__r] > __strides_[__r_largest]) + __r_largest = __r; + for (rank_type __r = 0; __r < __rank_; __r++) + if (__extents_.extent(__r) == 0 && __r != __r_largest) + return false; + return true; + } + } else { + return required_span_size() == [&](index_sequence<_Pos...>) { + return (__extents_.extent(_Pos) * ... * static_cast(1)); + }(make_index_sequence<__rank_>()); + } + } + } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + // according to the standard layout_stride does not have a constraint on stride(r) for rank>0 + // it still has the precondition though + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index"); + return __strides_[__r]; + } + + template + requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> && + (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { + if (__offset(__rhs)) + return false; + if constexpr (__rank_ == 0) + return true; + else { + return __lhs.extents() == __rhs.extents() && [&](index_sequence<_Pos...>) { + // avoid warning when comparing signed and unsigner integers and pick the wider of two types + using _CommonType = common_type_t; + return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... && + true); + }(make_index_sequence<__rank_>()); + } + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; + _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array __strides_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_STRIDE_H diff --git a/third_party/libcxx/include/c++/v1/__mdspan/mdspan.h b/third_party/libcxx/include/c++/v1/__mdspan/mdspan.h new file mode 100644 index 0000000..54685b5 --- /dev/null +++ b/third_party/libcxx/include/c++/v1/__mdspan/mdspan.h @@ -0,0 +1,328 @@ +// -*- 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_MDSPAN_H +#define _LIBCPP___MDSPAN_MDSPAN_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/aligned_accessor.h> +#include <__mdspan/default_accessor.h> +#include <__mdspan/extents.h> +#include <__memory/addressof.h> +#include <__type_traits/extent.h> +#include <__type_traits/is_abstract.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_same.h> +#include <__type_traits/rank.h> +#include <__type_traits/remove_all_extents.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/integer_sequence.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 + +// Helper for lightweight test checking that one did pass a layout policy as LayoutPolicy template argument +namespace __mdspan_detail { +template +concept __has_invalid_mapping = !requires { typename _Layout::template mapping<_Extents>; }; +} // namespace __mdspan_detail + +template > +class mdspan { +private: + static_assert(__mdspan_detail::__is_extents_v<_Extents>, + "mdspan: Extents template parameter must be a specialization of extents."); + static_assert( + is_object_v<_ElementType> && requires { sizeof(_ElementType); }, + "mdspan: ElementType template parameter must be a complete object type"); + static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type"); + static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class"); + static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>, + "mdspan: ElementType template parameter must match AccessorPolicy::element_type"); + static_assert(!__mdspan_detail::__has_invalid_mapping<_LayoutPolicy, _Extents>, + "mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping " + "instead of a layout policy"); + +public: + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = layout_type::template mapping; + using element_type = _ElementType; + using value_type = remove_cv_t; + using index_type = extents_type::index_type; + using size_type = extents_type::size_type; + using rank_type = extents_type::rank_type; + using data_handle_type = accessor_type::data_handle_type; + using reference = accessor_type::reference; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { + return extents_type::rank_dynamic(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + return extents_type::static_extent(__r); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + return __map_.extents().extent(__r); + } + + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan() + requires((extents_type::rank_dynamic() > 0) && is_default_constructible_v && + is_default_constructible_v && is_default_constructible_v) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default; + + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + ((sizeof...(_OtherIndexTypes) == rank()) || (sizeof...(_OtherIndexTypes) == rank_dynamic())) && + is_constructible_v && is_default_constructible_v) + _LIBCPP_HIDE_FROM_ABI explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts) + : __ptr_(std::move(__p)), __map_(extents_type(static_cast(std::move(__exts))...)), __acc_{} {} + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const extents_type& __exts) + requires(is_default_constructible_v && is_constructible_v) + : __ptr_(std::move(__p)), __map_(__exts), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m) + requires(is_default_constructible_v) + : __ptr_(std::move(__p)), __map_(__m), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a) + : __ptr_(std::move(__p)), __map_(__m), __acc_(__a) {} + + template + requires(is_constructible_v&> && + is_constructible_v) + explicit(!is_convertible_v&, mapping_type> || + !is_convertible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan( + const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other) + : __ptr_(__other.__ptr_), __map_(__other.__map_), __acc_(__other.__acc_) { + static_assert(is_constructible_v, + "mdspan: incompatible data_handle_type for mdspan construction"); + static_assert( + is_constructible_v, "mdspan: incompatible extents for mdspan construction"); + + // The following precondition is part of the standard, but is unlikely to be triggered. + // The extents constructor checks this and the mapping must be storing the extents, since + // its extents() function returns a const reference to extents_type. + // The only way this can be triggered is if the mapping conversion constructor would for example + // always construct its extents() only from the dynamic extents, instead of from the other extents. + if constexpr (rank() > 0) { + for (size_t __r = 0; __r < rank(); __r++) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan, non_checking_layout> m = + // mdspan, non_checking_layout>(ptr, 200); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + (static_extent(__r) == dynamic_extent) || + (static_cast(__other.extent(__r)) == static_cast(static_extent(__r))), + "mdspan: conversion mismatch of source dynamic extents with static extents"); + } + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default; + + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.members], members + + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + (sizeof...(_OtherIndexTypes) == rank())) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { + // Note the standard layouts would also check this, but user provided ones may not, so we + // check the precondition here + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...), + "mdspan: operator[] out of bounds access"); + return __acc_.access(__ptr_, __map_(static_cast(std::move(__indices))...)); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference + operator[](const array< _OtherIndexType, rank()>& __indices) const { + return __acc_.access(__ptr_, [&](index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence())); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { + return __acc_.access(__ptr_, [&](index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence())); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { + // Could leave this as only checked in debug mode: semantically size() is never + // guaranteed to be related to any accessible range + _LIBCPP_ASSERT_UNCATEGORIZED( + false == ([&](index_sequence<_Idxs...>) { + size_type __prod = 1; + return (__builtin_mul_overflow(__prod, extent(_Idxs), std::addressof(__prod)) || ... || false); + }(make_index_sequence())), + "mdspan: size() is not representable as size_type"); + return [&](index_sequence<_Idxs...>) { + return ((static_cast(__map_.extents().extent(_Idxs))) * ... * size_type(1)); + }(make_index_sequence()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { + return [&](index_sequence<_Idxs...>) { + return (rank() > 0) && ((__map_.extents().extent(_Idxs) == index_type(0)) || ... || false); + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept { + swap(__x.__ptr_, __y.__ptr_); + swap(__x.__map_, __y.__map_); + swap(__x.__acc_, __y.__acc_); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { + return __map_.extents(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; } + + // per LWG-4021 "mdspan::is_always_meow() should be noexcept" + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { + return mapping_type::is_always_unique(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { + return mapping_type::is_always_exhaustive(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { + return mapping_type::is_always_strided(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{}; + _LIBCPP_NO_UNIQUE_ADDRESS mapping_type __map_{}; + _LIBCPP_NO_UNIQUE_ADDRESS accessor_type __acc_{}; + + template + friend class mdspan; +}; + +# if _LIBCPP_STD_VER >= 26 +template + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, _OtherIndexTypes...) + -> mdspan<_ElementType, extents...>>; +# else +template + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, _OtherIndexTypes...) + -> mdspan<_ElementType, dextents>; +# endif + +template + requires(is_pointer_v>) +mdspan(_Pointer&&) -> mdspan>, extents>; + +template + requires(is_array_v<_CArray> && (rank_v<_CArray> == 1)) +mdspan(_CArray&) -> mdspan, extents>>; + +template +mdspan(_ElementType*, const array<_OtherIndexType, _Size>&) -> mdspan<_ElementType, dextents>; + +template +mdspan(_ElementType*, span<_OtherIndexType, _Size>) -> mdspan<_ElementType, dextents>; + +// This one is necessary because all the constructors take `data_handle_type`s, not +// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which +// seems to throw off automatic deduction guides. +template +mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>; + +template +mdspan(_ElementType*, const _MappingType&) + -> mdspan<_ElementType, typename _MappingType::extents_type, typename _MappingType::layout_type>; + +template +mdspan(typename _AccessorType::data_handle_type, const _MappingType&, const _AccessorType&) + -> mdspan; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_MDSPAN_H -- cgit v1.2.3