[libcxx] [llvm] [clang] [clang-tools-extra] [libc++][span] P2821R5: span.at() (PR #74994)

via cfe-commits cfe-commits at lists.llvm.org
Sun Dec 10 09:49:01 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

Implements: [P2821R5](https://wg21.link/P2821R5)

---
Full diff: https://github.com/llvm/llvm-project/pull/74994.diff


5 Files Affected:

- (modified) libcxx/docs/ReleaseNotes/18.rst (+1) 
- (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1) 
- (modified) libcxx/include/span (+30) 
- (added) libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp (+136) 
- (modified) libcxx/test/std/containers/views/views.span/span.elem/op_idx.pass.cpp (-1) 


``````````diff
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 9e509db6359c4a..f3e8281e74da2f 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -55,6 +55,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 ff83648aa76830..fa4a112d143673 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/include/span b/libcxx/include/span
index f94bda40fa7350..9af8dabb3ebd34 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_HIDE_FROM_ABI 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_HIDE_FROM_ABI 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..75a45171185cf3
--- /dev/null
+++ b/libcxx/test/std/containers/views/views.span/span.elem/at.pass.cpp
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <utility>
+#include <vector>
+
+#include "test_macros.h"
+
+constexpr void testSpanAt(auto span, int idx, int expectedValue) {
+  // non-const
+  {
+    std::same_as<typename decltype(span)::reference> decltype(auto) elem = span.at(idx);
+    assert(elem == expectedValue);
+  }
+
+  // const
+  {
+    std::same_as<typename decltype(span)::reference> decltype(auto) elem = std::as_const(span).at(idx);
+    assert(elem == expectedValue);
+  }
+}
+
+constexpr bool test() {
+  // With static extent
+  {
+    std::array arr{0, 1, 2, 3, 4, 5, 9084};
+    std::span arrSpan{arr};
+
+    assert(std::dynamic_extent != arrSpan.extent);
+
+    testSpanAt(arrSpan, 0, 0);
+    testSpanAt(arrSpan, 1, 1);
+    testSpanAt(arrSpan, 6, 9084);
+  }
+
+  // With dynamic extent
+  {
+    std::vector vec{0, 1, 2, 3, 4, 5, 9084};
+    std::span vecSpan{vec};
+
+    assert(std::dynamic_extent == vecSpan.extent);
+
+    testSpanAt(vecSpan, 0, 0);
+    testSpanAt(vecSpan, 1, 1);
+    testSpanAt(vecSpan, 6, 9084);
+  }
+
+  return true;
+}
+
+void test_exceptions() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  // With static extent
+  {
+    std::array arr{1, 2, 3, 4};
+    const std::span arrSpan{arr};
+
+    try {
+      TEST_IGNORE_NODISCARD arrSpan.at(arr.size() + 1);
+      assert(false);
+    } catch (std::out_of_range const&) {
+      // pass
+    } catch (...) {
+      assert(false);
+    }
+  }
+
+  {
+    std::array<int, 0> arr{};
+    const std::span arrSpan{arr};
+
+    try {
+      TEST_IGNORE_NODISCARD arrSpan.at(0);
+      assert(false);
+    } catch (std::out_of_range const&) {
+      // pass
+    } catch (...) {
+      assert(false);
+    }
+  }
+
+  // With dynamic extent
+
+  {
+    std::vector vec{1, 2, 3, 4};
+    const std::span vecSpan{vec};
+
+    try {
+      TEST_IGNORE_NODISCARD vecSpan.at(vec.size() + 1);
+      assert(false);
+    } catch (std::out_of_range const&) {
+      // pass
+    } catch (...) {
+      assert(false);
+    }
+  }
+
+  {
+    std::vector<int> vec{};
+    const std::span vecSpan{vec};
+
+    try {
+      TEST_IGNORE_NODISCARD vecSpan.at(0);
+      assert(false);
+    } catch (std::out_of_range const&) {
+      // pass
+    } catch (...) {
+      assert(false);
+    }
+  }
+#endif // TEST_HAS_NO_EXCEPTIONS
+}
+
+int main(int, char**) {
+  test();
+  test_exceptions();
+  static_assert(test());
+
+  return 0;
+}
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};
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/74994


More information about the cfe-commits mailing list