//===----------------------------------------------------------------------===//
//
// 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 <limits>
#include <span>
#include <stdexcept>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "test_macros.h"
template <typename ReferenceT>
constexpr void testSpanAt(auto&& anySpan, int index, int expectedValue) {
// non-const
{
std::same_as<ReferenceT> decltype(auto) elem = anySpan.at(index);
assert(elem == expectedValue);
}
// const
{
std::same_as<ReferenceT> decltype(auto) elem = std::as_const(anySpan).at(index);
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);
using ReferenceT = typename decltype(arrSpan)::reference;
testSpanAt<ReferenceT>(arrSpan, 0, 0);
testSpanAt<ReferenceT>(arrSpan, 1, 1);
testSpanAt<ReferenceT>(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);
using ReferenceT = typename decltype(vecSpan)::reference;
testSpanAt<ReferenceT>(vecSpan, 0, 0);
testSpanAt<ReferenceT>(vecSpan, 1, 1);
testSpanAt<ReferenceT>(vecSpan, 6, 9084);
}
return true;
}
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using namespace std::string_literals;
// With static extent
{
std::array arr{0, 1, 2, 3, 4, 5, 9084, std::numeric_limits<int>::max()};
const std::span arrSpan{arr};
try {
using SizeT = typename decltype(arrSpan)::size_type;
std::ignore = arrSpan.at(std::numeric_limits<SizeT>::max());
assert(false);
} catch ([[maybe_unused]] const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
try {
std::ignore = arrSpan.at(arr.size());
assert(false);
} catch ([[maybe_unused]] const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
try {
std::ignore = arrSpan.at(arr.size() - 1);
// pass
assert(arrSpan.at(arr.size() - 1) == std::numeric_limits<int>::max());
} catch (...) {
assert(false);
}
}
{
std::array<int, 0> arr{};
const std::span arrSpan{arr};
try {
std::ignore = arrSpan.at(0);
assert(false);
} catch ([[maybe_unused]] const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
}
// With dynamic extent
{
std::vector vec{0, 1, 2, 3, 4, 5, 9084, std::numeric_limits<int>::max()};
const std::span vecSpan{vec};
try {
using SizeT = typename decltype(vecSpan)::size_type;
std::ignore = vecSpan.at(std::numeric_limits<SizeT>::max());
assert(false);
} catch ([[maybe_unused]] const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
try {
std::ignore = vecSpan.at(vec.size());
assert(false);
} catch (const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
try {
std::ignore = vecSpan.at(vec.size() - 1);
assert(vecSpan.at(vec.size() - 1) == std::numeric_limits<int>::max());
} catch (...) {
assert(false);
}
}
{
std::vector<int> vec{};
const std::span vecSpan{vec};
try {
std::ignore = vecSpan.at(0);
assert(false);
} catch ([[maybe_unused]] const std::out_of_range& e) {
// pass
LIBCPP_ASSERT(e.what() == "span"s);
} catch (...) {
assert(false);
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
}
int main(int, char**) {
test();
static_assert(test());
test_exceptions();
return 0;
}