https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/74994
>From 6e26ca239c49e1b7d9ab72217db7339e92df163f Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Sun, 10 Dec 2023 14:16:02 +0200 Subject: [PATCH 1/2] [libc++][span] P2821R5: span.at() --- libcxx/include/span | 30 +++ .../views/views.span/span.elem/at.pass.cpp | 246 ++++++++++++++++++ .../views.span/span.elem/op_idx.pass.cpp | 1 - 3 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp diff --git a/libcxx/include/span b/libcxx/include/span index 69b0a2875e26cc..b015d7cf1c15b6 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -92,6 +92,7 @@ public: // [span.elem], span element access constexpr reference operator[](size_type idx) const; + constexpr reference at(size_type idx) const; // since C++26 constexpr reference front() const; constexpr reference back() const; constexpr pointer data() const noexcept; @@ -146,6 +147,9 @@ template<class R> #include <__utility/forward.h> #include <array> // for array #include <cstddef> // for byte +#if _LIBCPP_STD_VER >= 26 +# include <stdexcept> +#endif #include <version> // standard-mandated includes @@ -343,6 +347,15 @@ public: return __data_[__idx]; } +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __idx) const { + if (__idx >= size()) { + __throw_out_of_range(); + } + return *(data() + __idx); + } +# endif + _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::front() on empty span"); @@ -383,6 +396,10 @@ public: private: pointer __data_; + +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw_out_of_range() const { std::__throw_out_of_range("span"); } +# endif }; @@ -510,6 +527,15 @@ public: return __data_[__idx]; } +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __idx) const { + if (__idx >= size()) { + __throw_out_of_range(); + } + return *(data() + __idx); + } +# endif + _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::front() on empty span"); @@ -552,6 +578,10 @@ public: private: pointer __data_; size_type __size_; + +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw_out_of_range() const { std::__throw_out_of_range("span"); } +# endif }; template <class _Tp, size_t _Extent> diff --git a/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp b/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp new file mode 100644 index 00000000000000..2a9ce2baeec1a5 --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp @@ -0,0 +1,246 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +// <span> + +// constexpr reference at(size_type idx) const; // since C++26 + +#include <array> +#include <cassert> +#include <concepts> +#include <span> +#include <stdexcept> +#include <vector> + +#include "test_macros.h" + +// template <typename Span> +// constexpr bool testConstexprSpan(Span sp, std::size_t idx) +// { +// LIBCPP_ASSERT(noexcept(sp[idx])); + +// typename Span::reference r1 = sp[idx]; +// typename Span::reference r2 = *(sp.data() + idx); + +// return r1 == r2; +// } + +// template <typename Span> +// void testRuntimeSpan(Span sp, std::size_t idx) +// { +// LIBCPP_ASSERT(noexcept(sp[idx])); + +// typename Span::reference r1 = sp[idx]; +// typename Span::reference r2 = *(sp.data() + idx); + +// assert(r1 == r2); +// } + +// struct A{}; +// constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +// int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +// int main(int, char**) +// { +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 1), 0), ""); + +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 2), 0), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 2), 1), ""); + +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 0), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 1), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 2), ""); + +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 0), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 1), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 2), ""); +// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 3), ""); + +// static_assert(testConstexprSpan(std::span<const int, 1>(iArr1, 1), 0), ""); + +// static_assert(testConstexprSpan(std::span<const int, 2>(iArr1, 2), 0), ""); +// static_assert(testConstexprSpan(std::span<const int, 2>(iArr1, 2), 1), ""); + +// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 0), ""); +// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 1), ""); +// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 2), ""); + +// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 0), ""); +// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 1), ""); +// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 2), ""); +// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 3), ""); + +// testRuntimeSpan(std::span<int>(iArr2, 1), 0); + +// testRuntimeSpan(std::span<int>(iArr2, 2), 0); +// testRuntimeSpan(std::span<int>(iArr2, 2), 1); + +// testRuntimeSpan(std::span<int>(iArr2, 3), 0); +// testRuntimeSpan(std::span<int>(iArr2, 3), 1); +// testRuntimeSpan(std::span<int>(iArr2, 3), 2); + +// testRuntimeSpan(std::span<int>(iArr2, 4), 0); +// testRuntimeSpan(std::span<int>(iArr2, 4), 1); +// testRuntimeSpan(std::span<int>(iArr2, 4), 2); +// testRuntimeSpan(std::span<int>(iArr2, 4), 3); + +// testRuntimeSpan(std::span<int, 1>(iArr2, 1), 0); + +// testRuntimeSpan(std::span<int, 2>(iArr2, 2), 0); +// testRuntimeSpan(std::span<int, 2>(iArr2, 2), 1); + +// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 0); +// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 1); +// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 2); + +// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 0); +// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 1); +// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 2); +// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 3); + +// std::string s; +// testRuntimeSpan(std::span<std::string> (&s, 1), 0); +// testRuntimeSpan(std::span<std::string, 1>(&s, 1), 0); + +// return 0; +// } + +constexpr bool test() { + // { + // typedef double T; + // typedef std::array<T, 3> C; + // C const c = {1, 2, 3.5}; + // typename C::const_reference r1 = c.at(0); + // assert(r1 == 1); + + // typename C::const_reference r2 = c.at(2); + // assert(r2 == 3.5); + // } + + const auto testSpan = + [](auto span, int idx, int expectedValue) { + { + std::same_as<decltype(span)::reference> elem = span.at(idx); + assert(elem == expectedValue); + } + + { + std::same_as<decltype(span)::const_reference> elem = std::as_const(span).at(idx); + assert(elem == expectedValue); + } + } + + // With static extent + + std::array arr{0, 1, 2, 3, 4, 5, 9084}; + std::span arrSpan{ar}; + + assert(std::dynamic_extent != arrSpan.extent); + + testSpan(arrSpan, 0, 0); + testSpan(arrSpan, 1, 1); + testSpan(arrSpan, 5, 9084); + + { + std::same_as<decltype(arrSpan)::reference> arrElem = arrSpan.at(1); + assert(arrElem == 1); + } + + { + std::same_as<decltype(arrSpan)::const_reference> arrElem = std::as_const(arrSpan).at(1); + assert(arrElem == 1); + } + + // With dynamic extent + + std::vector vec{0, 1, 2, 3, 4, 5}; + std::span vecSpan{vec}; + + assert(std::dynamic_extent == vecSpan.extent) + + { + std::same_as<decltype(vecSpan)::reference> vecElem = vecSpan.at(1); + assert(vec_elem == 1); + } + + { + std::same_as<decltype(vecSpan)::reference> vecElem = std::as_const(vecSpan).at(1); + assert(vec_elem == 1); + } + + return true; +} + +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + // With static extent + { + const std::array arr{1, 2, 3, 4}; + + try { + TEST_IGNORE_NODISCARD arr.at(4); + assert(false); + } catch (std::out_of_range const&) { + // pass + } catch (...) { + assert(false); + } + } + + { + const std::array<int, 0> arr{}; + + try { + TEST_IGNORE_NODISCARD arr.at(0); + assert(false); + } catch (std::out_of_range const&) { + // pass + } catch (...) { + assert(false); + } + } + + // With dynamic extent + + { + const std::vector vec{1, 2, 3, 4}; + + try { + TEST_IGNORE_NODISCARD vec.at(4); + assert(false); + } catch (std::out_of_range const&) { + // pass + } catch (...) { + assert(false); + } + } + + { + const std::vector<int> vec{}; + + try { + TEST_IGNORE_NODISCARD vec.at(0); + assert(false); + } catch (std::out_of_range const&) { + // pass + } catch (...) { + assert(false); + } + } +#endif +} + +int main(int, char**) { + test(); + test_exceptions(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/containers/views/views.span/span.elem/op_idx.pass.cpp b/libcxx/test/std/containers/views/views.span/span.elem/op_idx.pass.cpp index e46fd267ef5cc5..b7f36c57585881 100644 --- a/libcxx/test/std/containers/views/views.span/span.elem/op_idx.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.elem/op_idx.pass.cpp @@ -41,7 +41,6 @@ void testRuntimeSpan(Span sp, std::size_t idx) assert(r1 == r2); } -struct A{}; constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; >From ed7ee83fa9b10a37295d050e1edc538b05a22504 Mon Sep 17 00:00:00 2001 From: Zingam <zin...@outlook.com> Date: Sun, 10 Dec 2023 16:03:08 +0200 Subject: [PATCH 2/2] Cleanup tests --- libcxx/docs/ReleaseNotes/18.rst | 1 + libcxx/docs/Status/Cxx2cPapers.csv | 2 +- .../views/views.span/span.elem/at.pass.cpp | 139 ++---------------- z_libcxx-dev-tools | 1 + 4 files changed, 18 insertions(+), 125 deletions(-) create mode 160000 z_libcxx-dev-tools diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index abefe4c28ca958..05542f034e63b4 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -54,6 +54,7 @@ Implemented Papers - P2871R3 - Remove Deprecated Unicode Conversion Facets from C++26 - P2870R3 - Remove basic_string::reserve() - P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?) +- P2821R5 - span.at() Improvements and New Features diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 1d071b7ebcb4a7..b97dc44795ac82 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -35,7 +35,7 @@ "`P2909R4 <https://wg21.link/P2909R4>`__","LWG","Fix formatting of code units as integers (Dude, where’s my ``char``?)","Kona November 2023","|Complete|","18.0","|format| |DR|" "`P0952R2 <https://wg21.link/P0952R2>`__","LWG","A new specification for ``std::generate_canonical``","Kona November 2023","","","" "`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","","","" -"`P2821R5 <https://wg21.link/P2821R5>`__","LWG","``span.at()``","Kona November 2023","","","" +"`P2821R5 <https://wg21.link/P2821R5>`__","LWG","``span.at()``","Kona November 2023","|Complete|","18.0","" "`P2868R3 <https://wg21.link/P2868R3>`__","LWG","Remove Deprecated ``std::allocator`` Typedef From C++26","Kona November 2023","","","" "`P2870R3 <https://wg21.link/P2870R3>`__","LWG","Remove ``basic_string::reserve()`` From C++26","Kona November 2023","|Complete|","18.0","" "`P2871R3 <https://wg21.link/P2871R3>`__","LWG","Remove Deprecated Unicode Conversion Facets from C++26","Kona November 2023","|Complete|","18.0","" diff --git a/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp b/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp index 2a9ce2baeec1a5..8daaa6bb6fa127 100644 --- a/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp @@ -17,144 +17,35 @@ #include <concepts> #include <span> #include <stdexcept> +#include <utility> #include <vector> #include "test_macros.h" -// template <typename Span> -// constexpr bool testConstexprSpan(Span sp, std::size_t idx) -// { -// LIBCPP_ASSERT(noexcept(sp[idx])); - -// typename Span::reference r1 = sp[idx]; -// typename Span::reference r2 = *(sp.data() + idx); - -// return r1 == r2; -// } - -// template <typename Span> -// void testRuntimeSpan(Span sp, std::size_t idx) -// { -// LIBCPP_ASSERT(noexcept(sp[idx])); - -// typename Span::reference r1 = sp[idx]; -// typename Span::reference r2 = *(sp.data() + idx); - -// assert(r1 == r2); -// } - -// struct A{}; -// constexpr int iArr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; -// int iArr2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; - -// int main(int, char**) -// { -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 1), 0), ""); - -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 2), 0), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 2), 1), ""); - -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 0), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 1), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 3), 2), ""); - -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 0), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 1), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 2), ""); -// static_assert(testConstexprSpan(std::span<const int>(iArr1, 4), 3), ""); - -// static_assert(testConstexprSpan(std::span<const int, 1>(iArr1, 1), 0), ""); - -// static_assert(testConstexprSpan(std::span<const int, 2>(iArr1, 2), 0), ""); -// static_assert(testConstexprSpan(std::span<const int, 2>(iArr1, 2), 1), ""); - -// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 0), ""); -// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 1), ""); -// static_assert(testConstexprSpan(std::span<const int, 3>(iArr1, 3), 2), ""); - -// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 0), ""); -// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 1), ""); -// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 2), ""); -// static_assert(testConstexprSpan(std::span<const int, 4>(iArr1, 4), 3), ""); - -// testRuntimeSpan(std::span<int>(iArr2, 1), 0); - -// testRuntimeSpan(std::span<int>(iArr2, 2), 0); -// testRuntimeSpan(std::span<int>(iArr2, 2), 1); - -// testRuntimeSpan(std::span<int>(iArr2, 3), 0); -// testRuntimeSpan(std::span<int>(iArr2, 3), 1); -// testRuntimeSpan(std::span<int>(iArr2, 3), 2); - -// testRuntimeSpan(std::span<int>(iArr2, 4), 0); -// testRuntimeSpan(std::span<int>(iArr2, 4), 1); -// testRuntimeSpan(std::span<int>(iArr2, 4), 2); -// testRuntimeSpan(std::span<int>(iArr2, 4), 3); - -// testRuntimeSpan(std::span<int, 1>(iArr2, 1), 0); - -// testRuntimeSpan(std::span<int, 2>(iArr2, 2), 0); -// testRuntimeSpan(std::span<int, 2>(iArr2, 2), 1); - -// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 0); -// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 1); -// testRuntimeSpan(std::span<int, 3>(iArr2, 3), 2); - -// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 0); -// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 1); -// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 2); -// testRuntimeSpan(std::span<int, 4>(iArr2, 4), 3); - -// std::string s; -// testRuntimeSpan(std::span<std::string> (&s, 1), 0); -// testRuntimeSpan(std::span<std::string, 1>(&s, 1), 0); - -// return 0; -// } +constexpr void testSpan(auto span, int idx, int expectedValue) { + std::same_as<typename decltype(span)::reference> decltype(auto) elem = span.at(idx); + assert(elem == expectedValue); +} constexpr bool test() { - // { - // typedef double T; - // typedef std::array<T, 3> C; - // C const c = {1, 2, 3.5}; - // typename C::const_reference r1 = c.at(0); - // assert(r1 == 1); - - // typename C::const_reference r2 = c.at(2); - // assert(r2 == 3.5); - // } - - const auto testSpan = - [](auto span, int idx, int expectedValue) { - { - std::same_as<decltype(span)::reference> elem = span.at(idx); - assert(elem == expectedValue); - } - - { - std::same_as<decltype(span)::const_reference> elem = std::as_const(span).at(idx); - assert(elem == expectedValue); - } - } - // With static extent std::array arr{0, 1, 2, 3, 4, 5, 9084}; - std::span arrSpan{ar}; + std::span arrSpan{arr}; assert(std::dynamic_extent != arrSpan.extent); testSpan(arrSpan, 0, 0); testSpan(arrSpan, 1, 1); - testSpan(arrSpan, 5, 9084); + testSpan(arrSpan, 6, 9084); { - std::same_as<decltype(arrSpan)::reference> arrElem = arrSpan.at(1); + std::same_as<typename decltype(arrSpan)::reference> decltype(auto) arrElem = arrSpan.at(1); assert(arrElem == 1); } { - std::same_as<decltype(arrSpan)::const_reference> arrElem = std::as_const(arrSpan).at(1); + std::same_as<typename decltype(arrSpan)::reference> decltype(auto) arrElem = std::as_const(arrSpan).at(1); assert(arrElem == 1); } @@ -162,17 +53,17 @@ constexpr bool test() { std::vector vec{0, 1, 2, 3, 4, 5}; std::span vecSpan{vec}; - - assert(std::dynamic_extent == vecSpan.extent) + + assert(std::dynamic_extent == vecSpan.extent); { - std::same_as<decltype(vecSpan)::reference> vecElem = vecSpan.at(1); - assert(vec_elem == 1); + std::same_as<typename decltype(vecSpan)::reference> decltype(auto) vecElem = vecSpan.at(1); + assert(vecElem == 1); } { - std::same_as<decltype(vecSpan)::reference> vecElem = std::as_const(vecSpan).at(1); - assert(vec_elem == 1); + std::same_as<typename decltype(vecSpan)::reference> decltype(auto) vecElem = std::as_const(vecSpan).at(1); + assert(vecElem == 1); } return true; diff --git a/z_libcxx-dev-tools b/z_libcxx-dev-tools new file mode 160000 index 00000000000000..229818e01844e2 --- /dev/null +++ b/z_libcxx-dev-tools @@ -0,0 +1 @@ +Subproject commit 229818e01844e2cad56818bf06703600071848c0 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits