#ifndef _LIBCPP___MDSPAN_EXTENTS_H
#define _LIBCPP___MDSPAN_EXTENTS_H
#include <__assert>
#include <__config>
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.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 <__type_traits/remove_cvref.h>
#include <__utility/as_const.h>
#include <__utility/forward.h>
#include <__utility/integer_sequence.h>
#include <__utility/unreachable.h>
#include <array>
#include <concepts>
#include <limits>
#include <span>
#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 <class _Tp, size_t _Size>
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 <class _Tp>
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(); }
};
template <size_t... _Values>
struct __static_partial_sums {
_LIBCPP_HIDE_FROM_ABI static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl() {
array<size_t, sizeof...(_Values)> __values{_Values...};
array<size_t, sizeof...(_Values)> __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<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
_LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
};
template <class _TDynamic, class _TStatic, _TStatic... _Values>
struct __maybe_static_array {
static_assert(is_convertible_v<_TStatic, _TDynamic>,
"__maybe_static_array: _TStatic must be convertible to _TDynamic");
static_assert(is_convertible_v<_TDynamic, _TStatic>,
"__maybe_static_array: _TDynamic must be convertible to _TStatic");
private:
static constexpr size_t __size_ = sizeof...(_Values);
static constexpr size_t __size_dynamic_ = ((_Values == dynamic_extent) + ... + 0);
using _DynamicValues _LIBCPP_NODEBUG = __possibly_empty_array<_TDynamic, __size_dynamic_>;
static constexpr array<_TStatic, sizeof...(_Values)> __static_values_ = {_Values...};
_LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
using _DynamicIdxMap _LIBCPP_NODEBUG = __static_partial_sums<static_cast<size_t>(_Values == dynamic_extent)...>;
public:
_LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept : __dyn_vals_{} {}
template <class... _DynVals>
requires(sizeof...(_DynVals) == __size_dynamic_)
_LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals)
: __dyn_vals_{static_cast<_TDynamic>(__vals)...} {}
template <class _Tp, size_t _Size >
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]);
}
}
template <class... _DynVals>
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 = __static_values_[__i];
if (__static_val == dynamic_extent) {
__dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i];
} else
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__values[__i] == static_cast<_TDynamic>(__static_val),
"extents construction: mismatch of provided arguments with static extents.");
}
}
template <class _Tp, size_t _Size>
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 = __static_values_[__i];
if (__static_val == dynamic_extent) {
__dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
} else
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
"extents construction: mismatch of provided arguments with static extents.");
}
}
_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 __static_values_[__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 = __static_values_[__i];
return __static_val == dynamic_extent
? __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);
}
_LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; }
_LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; }
};
template <integral _To, class _From>
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 <integral _To, class _From>
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 <class _IndexType, size_t... _Extents>
class extents {
public:
using index_type = _IndexType;
using size_type = make_unsigned_t<index_type>;
using rank_type = size_t;
static_assert(__signed_or_unsigned_integer<index_type>,
"extents::index_type must be a signed or unsigned integer type");
static_assert(((__mdspan_detail::__is_representable_as<index_type>(_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);
using _Values _LIBCPP_NODEBUG = __mdspan_detail::__maybe_static_array<_IndexType, size_t, _Extents...>;
[[no_unique_address]] _Values __vals_;
template <class _OtherIndexType>
_LIBCPP_HIDE_FROM_ABI static constexpr index_type __checked_index_cast(_OtherIndexType&& __value) noexcept {
using _OtherType = remove_cvref_t<_OtherIndexType>;
if constexpr (integral<_OtherType> && !same_as<_OtherType, bool>) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__mdspan_detail::__is_representable_as<index_type>(__value),
"extents ctor: arguments must be representable as index_type and nonnegative");
return static_cast<index_type>(__value);
} else {
auto __converted_val = static_cast<index_type>(std::forward<_OtherIndexType>(__value));
if constexpr (is_signed_v<index_type>) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__converted_val >= 0, "extents ctor: arguments must be representable as index_type and nonnegative");
}
return __converted_val;
}
}
template <class... _OtherIndexTypes>
_LIBCPP_HIDE_FROM_ABI static constexpr _Values
__representability_checked_cast(_OtherIndexTypes&&... __values) noexcept {
return _Values{__checked_index_cast(std::forward<_OtherIndexTypes>(__values))...};
}
template <class _OtherIndexType, size_t _Size, size_t... _Idxs>
_LIBCPP_HIDE_FROM_ABI static constexpr _Values
__representability_checked_cast(const array<_OtherIndexType, _Size>& __exts, index_sequence<_Idxs...>) noexcept {
return __representability_checked_cast(__exts[_Idxs]...);
}
template <class _OtherIndexType, size_t _Size, size_t... _Idxs>
_LIBCPP_HIDE_FROM_ABI static constexpr _Values
__representability_checked_cast(const span<_OtherIndexType, _Size>& __exts, index_sequence<_Idxs...>) noexcept {
return __representability_checked_cast(std::as_const(__exts[_Idxs])...);
}
public:
[[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);
}
_LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
template <class... _OtherIndexTypes>
requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
(is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
(sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
_LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
: __vals_(__representability_checked_cast(std::move(__dynvals)...)) {}
template <class _OtherIndexType, size_t _Size>
requires(is_convertible_v<const _OtherIndexType&, index_type> &&
is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
(_Size == __rank_ || _Size == __rank_dynamic_))
explicit(_Size != __rank_dynamic_)
_LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
: __vals_(__representability_checked_cast(__exts, make_index_sequence<_Size>())) {}
template <class _OtherIndexType, size_t _Size>
requires(is_convertible_v<const _OtherIndexType&, index_type> &&
is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
(_Size == __rank_ || _Size == __rank_dynamic_))
explicit(_Size != __rank_dynamic_)
_LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
: __vals_(__representability_checked_cast(__exts, make_index_sequence<_Size>())) {}
private:
template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
requires(_Idx < __rank_)
_LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
integral_constant<size_t, _DynCount>,
integral_constant<size_t, _Idx>,
const _OtherExtents& __exts,
_DynamicValues... __dynamic_values) noexcept {
if constexpr (static_extent(_Idx) == dynamic_extent)
return __construct_vals_from_extents(
integral_constant<size_t, _DynCount + 1>(),
integral_constant<size_t, _Idx + 1>(),
__exts,
__dynamic_values...,
__exts.extent(_Idx));
else
return __construct_vals_from_extents(
integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
}
template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
_LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
integral_constant<size_t, _DynCount>,
integral_constant<size_t, _Idx>,
const _OtherExtents&,
_DynamicValues... __dynamic_values) noexcept {
return _Values{static_cast<index_type>(__dynamic_values)...};
}
public:
template <class _OtherIndexType, size_t... _OtherExtents>
requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
(static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
_LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
: __vals_(
__construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
if constexpr (rank() > 0) {
for (size_t __r = 0; __r < rank(); __r++) {
if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
"extents ctor: arguments must be representable as index_type and nonnegative");
}
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
(_Values::__static_value(__r) == dynamic_extent) ||
(static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
"extents construction: mismatch of provided arguments with static extents.");
}
}
}
template <class _OtherIndexType, size_t... _OtherExtents>
_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++) {
using _CommonType = common_type_t<index_type, _OtherIndexType>;
if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
return false;
}
}
}
return true;
}
template <class _OtherIndexType>
_LIBCPP_HIDE_FROM_ABI static constexpr auto __index_cast(_OtherIndexType&& __i) noexcept {
using _OtherIndex = remove_cvref_t<_OtherIndexType>;
if constexpr (integral<_OtherIndex> && !same_as<_OtherIndex, bool>)
return __i;
else
return static_cast<index_type>(std::forward<_OtherIndexType>(__i));
}
};
namespace __mdspan_detail {
template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
struct __make_dextents;
template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
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 <class _IndexType, size_t... _ExtentsPack>
struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
using type _LIBCPP_NODEBUG = extents<_IndexType, _ExtentsPack...>;
};
}
template <class _IndexType, size_t _Rank>
using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
# if _LIBCPP_STD_VER >= 26
template <size_t _Rank, class _IndexType = size_t>
using dims = dextents<_IndexType, _Rank>;
# endif
# if _LIBCPP_STD_VER >= 26
template <class... _IndexTypes>
requires(is_convertible_v<_IndexTypes, size_t> && ...)
explicit extents(_IndexTypes...) -> extents<size_t, __maybe_static_ext<_IndexTypes>...>;
# else
template <class... _IndexTypes>
requires(is_convertible_v<_IndexTypes, size_t> && ...)
explicit extents(_IndexTypes...) -> extents<size_t, size_t(((void)sizeof(_IndexTypes), dynamic_extent))...>;
# endif
namespace __mdspan_detail {
template <class _Tp>
struct __is_extents : false_type {};
template <class _IndexType, size_t... _ExtentsPack>
struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
template <class _Tp>
inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
template <integral _IndexType, class _From>
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 <integral _IndexType, class _From>
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 <size_t... _Idxs, class _Extents, class... _From>
_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 <class _Extents, class... _From>
_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...);
}
}
#endif
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif