aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiaoyang Liu <siujoeng.lau@gmail.com>2024-04-12 13:25:22 -0400
committerGitHub <noreply@github.com>2024-04-12 19:25:22 +0200
commit7cafe04e0d74c1e9f7e3871a0bcdf4ccb1c89f0c (patch)
tree64933b581921230fe5fee6c06803f05c7110bd69
parent6a85cf8fc0437d4885fc829948befe32c1e5a21d (diff)
downloadllvm-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.rst1
-rw-r--r--libcxx/docs/Status/Cxx2cPapers.csv2
-rw-r--r--libcxx/include/__mdspan/mdspan.h7
-rw-r--r--libcxx/include/mdspan6
-rw-r--r--libcxx/include/span44
-rw-r--r--libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp18
-rw-r--r--libcxx/test/std/containers/views/views.span/span.cons/deduct.pass.cpp11
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() {