diff options
author | Xiaoyang Liu <siujoeng.lau@gmail.com> | 2024-04-12 13:25:22 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-12 19:25:22 +0200 |
commit | 7cafe04e0d74c1e9f7e3871a0bcdf4ccb1c89f0c (patch) | |
tree | 64933b581921230fe5fee6c06803f05c7110bd69 | |
parent | 6a85cf8fc0437d4885fc829948befe32c1e5a21d (diff) | |
download | llvm-7cafe04e0d74c1e9f7e3871a0bcdf4ccb1c89f0c.zip llvm-7cafe04e0d74c1e9f7e3871a0bcdf4ccb1c89f0c.tar.gz llvm-7cafe04e0d74c1e9f7e3871a0bcdf4ccb1c89f0c.tar.bz2 |
[libc++] P3029R1: Better `mdspan`'s CTAD (#87873)
## Abstract
This pull request implements [P3029R1](https://wg21.link/P3029R1). The
paper discusses the current behavior of `mdspan`'s most common
pointer-indices CTAD, where the `Extents` template parameter is deduced
as `dextents` (dynamic extents), even when passing compile-time constant
values. The author believes this behavior is suboptimal, as it doesn't
take advantage of the compile-time information. The proposed change
suggests deducing static extents if `integral_constant`-like constants
are passed, resulting in more intuitive syntax and less error-prone
code.
## Reference
- [P3029R1](https://wg21.link/P3029R1)
- [Draft C++ Standard: [span.syn]](https://eel.is/c++draft/span.syn)
- [Draft C++ Standard: [mdspan.syn]](https://eel.is/c++draft/mdspan.syn)
-rw-r--r-- | libcxx/docs/ReleaseNotes/19.rst | 1 | ||||
-rw-r--r-- | libcxx/docs/Status/Cxx2cPapers.csv | 2 | ||||
-rw-r--r-- | libcxx/include/__mdspan/mdspan.h | 7 | ||||
-rw-r--r-- | libcxx/include/mdspan | 6 | ||||
-rw-r--r-- | libcxx/include/span | 44 | ||||
-rw-r--r-- | libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp | 18 | ||||
-rw-r--r-- | libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp | 11 |
7 files changed, 84 insertions, 5 deletions
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 81c05b9..7bc0148 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -47,6 +47,7 @@ Implemented Papers - P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23) - P2302R4 - ``std::ranges::contains`` - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with`` +- P3029R1 - Better ``mdspan``'s CTAD Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index fa11da6..8516070 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -61,5 +61,5 @@ "`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","","" "`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","","","" "`P2642R6 <https://wg21.link/P2642R6>`__","LWG","Padded ``mdspan`` layouts","Tokyo March 2024","","","" -"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","","","" +"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0","" "","","","","","","" diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h index d9a0108..09665af 100644 --- a/libcxx/include/__mdspan/mdspan.h +++ b/libcxx/include/__mdspan/mdspan.h @@ -266,10 +266,17 @@ private: friend class mdspan; }; +# if _LIBCPP_STD_VER >= 26 +template <class _ElementType, class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, + _OtherIndexTypes...) -> mdspan<_ElementType, extents<size_t, __maybe_static_ext<_OtherIndexTypes>...>>; +# else template <class _ElementType, class... _OtherIndexTypes> requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) explicit mdspan(_ElementType*, _OtherIndexTypes...) -> mdspan<_ElementType, dextents<size_t, sizeof...(_OtherIndexTypes)>>; +# endif template <class _Pointer> requires(is_pointer_v<remove_reference_t<_Pointer>>) diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan index c13d9ee..8d443f4 100644 --- a/libcxx/include/mdspan +++ b/libcxx/include/mdspan @@ -370,7 +370,11 @@ namespace std { template<class ElementType, class... Integrals> requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) - -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; + -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; // until C++26 + template<class ElementType, class... Integrals> + requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) + explicit mdspan(ElementType*, Integrals...) + -> mdspan<ElementType, extents<size_t, maybe-static-ext<Integrals>...>>; // since C++26 template<class ElementType, class OtherIndexType, size_t N> mdspan(ElementType*, span<OtherIndexType, N>) diff --git a/libcxx/include/span b/libcxx/include/span index c0fe25d..0307edc 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -18,6 +18,20 @@ namespace std { // constants inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max(); +template<class T> + concept integral-constant-like = // exposition only, since C++26 + is_integral_v<decltype(T::value)> && + !is_same_v<bool, remove_const_t<decltype(T::value)>> && + convertible_to<T, decltype(T::value)> && + equality_comparable_with<T, decltype(T::value)> && + bool_constant<T() == T::value>::value && + bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value; + +template<class T> + constexpr size_t maybe-static-ext = dynamic_extent; // exposition only, since C++26 +template<integral-constant-like T> + constexpr size_t maybe-static-ext<T> = {T::value}; + // [views.span], class template span template <class ElementType, size_t Extent = dynamic_extent> class span; @@ -110,7 +124,9 @@ private: }; template<class It, class EndOrSize> - span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; + span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; // until C++26 +template<class It, class EndOrSize> + span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>, maybe-static-ext<EndOrSize>>; // since C++26 template<class T, size_t N> span(T (&)[N]) -> span<T, N>; @@ -129,6 +145,8 @@ template<class R> */ #include <__assert> +#include <__concepts/convertible_to.h> +#include <__concepts/equality_comparable.h> #include <__config> #include <__fwd/array.h> #include <__fwd/span.h> @@ -143,15 +161,19 @@ template<class R> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/size.h> +#include <__type_traits/integral_constant.h> #include <__type_traits/is_array.h> #include <__type_traits/is_const.h> #include <__type_traits/is_convertible.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_const.h> #include <__type_traits/remove_cv.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> #include <__type_traits/type_identity.h> #include <__utility/forward.h> -#include <cstddef> // for byte +#include <cstddef> // for byte #include <initializer_list> #include <stdexcept> #include <version> @@ -563,8 +585,26 @@ _LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept { return __s.__as_writable_bytes(); } +# if _LIBCPP_STD_VER >= 26 +template <class _Tp> +concept __integral_constant_like = + is_integral_v<decltype(_Tp::value)> && !is_same_v<bool, remove_const_t<decltype(_Tp::value)>> && + convertible_to<_Tp, decltype(_Tp::value)> && equality_comparable_with<_Tp, decltype(_Tp::value)> && + bool_constant<_Tp() == _Tp::value>::value && + bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>::value; + +template <class _Tp> +inline constexpr size_t __maybe_static_ext = dynamic_extent; + +template <__integral_constant_like _Tp> +inline constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; + +template <contiguous_iterator _It, class _EndOrSize> +span(_It, _EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>, __maybe_static_ext<_EndOrSize>>; +# else template <contiguous_iterator _It, class _EndOrSize> span(_It, _EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; +# endif template <class _Tp, size_t _Sz> span(_Tp (&)[_Sz]) -> span<_Tp, _Sz>; diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp index 557829d..876a3e8 100644 --- a/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp +++ b/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp @@ -22,7 +22,11 @@ // template<class ElementType, class... Integrals> // requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) // explicit mdspan(ElementType*, Integrals...) -// -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; +// -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; // until C++26 +// template<class ElementType, class... Integrals> +// requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) +// explicit mdspan(ElementType*, Integrals...) +// -> mdspan<ElementType, extents<size_t, maybe-static-ext<Integrals>...>>; // since C++26 // // template<class ElementType, class OtherIndexType, size_t N> // mdspan(ElementType*, span<OtherIndexType, N>) @@ -102,6 +106,18 @@ constexpr bool test_no_layout_deduction_guides(const H& handle, const A&) { // deduction from pointer and integral like ASSERT_SAME_TYPE(decltype(std::mdspan(handle, 5, SizeTIntType(6))), std::mdspan<T, std::dextents<size_t, 2>>); +#if _LIBCPP_STD_VER >= 26 + // P3029R1: deduction from `integral_constant` + ASSERT_SAME_TYPE( + decltype(std::mdspan(handle, std::integral_constant<size_t, 5>{})), std::mdspan<T, std::extents<size_t, 5>>); + ASSERT_SAME_TYPE(decltype(std::mdspan(handle, std::integral_constant<size_t, 5>{}, std::dynamic_extent)), + std::mdspan<T, std::extents<size_t, 5, std::dynamic_extent>>); + ASSERT_SAME_TYPE( + decltype(std::mdspan( + handle, std::integral_constant<size_t, 5>{}, std::dynamic_extent, std::integral_constant<size_t, 7>{})), + std::mdspan<T, std::extents<size_t, 5, std::dynamic_extent, 7>>); +#endif + std::array<char, 3> exts; // deduction from pointer and array ASSERT_SAME_TYPE(decltype(std::mdspan(handle, exts)), std::mdspan<T, std::dextents<size_t, 3>>); diff --git a/libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp index 398862d..92bb7c9 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp @@ -31,6 +31,7 @@ #include <iterator> #include <memory> #include <string> +#include <type_traits> #include "test_macros.h" @@ -48,6 +49,16 @@ void test_iterator_sentinel() { assert(s.size() == std::size(arr)); assert(s.data() == std::data(arr)); } + +#if _LIBCPP_STD_VER >= 26 + // P3029R1: deduction from `integral_constant` + { + std::span s{std::begin(arr), std::integral_constant<size_t, 3>{}}; + ASSERT_SAME_TYPE(decltype(s), std::span<int, 3>); + assert(s.size() == std::size(arr)); + assert(s.data() == std::data(arr)); + } +#endif } void test_c_array() { |