1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
//===---------------------------------------------------------------------===//
//
// 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
// <span>
// template <class It, class End>
// constexpr explicit(Extent != dynamic_extent) span(It first, End last);
// Requires: [first, last) shall be a valid range.
// If Extent is not equal to dynamic_extent, then last - first shall be equal to Extent.
// Throws: When and what last - first throws.
#include <array>
#include <span>
#include <cassert>
#include <utility>
#include "assert_macros.h"
#include "test_iterators.h"
#include "test_macros.h"
template <class T, class Sentinel>
constexpr bool test_ctor() {
T val[2] = {};
auto s1 = std::span<T>(std::begin(val), Sentinel(std::end(val)));
auto s2 = std::span<T, 2>(std::begin(val), Sentinel(std::end(val)));
assert(s1.data() == std::data(val) && s1.size() == std::size(val));
assert(s2.data() == std::data(val) && s2.size() == std::size(val));
return true;
}
template <std::size_t Extent>
constexpr void test_constructibility() {
static_assert(std::is_constructible_v<std::span<int, Extent>, int*, int*>);
static_assert(!std::is_constructible_v<std::span<int, Extent>, const int*, const int*>);
static_assert(!std::is_constructible_v<std::span<int, Extent>, volatile int*, volatile int*>);
static_assert(std::is_constructible_v<std::span<const int, Extent>, int*, int*>);
static_assert(std::is_constructible_v<std::span<const int, Extent>, const int*, const int*>);
static_assert(!std::is_constructible_v<std::span<const int, Extent>, volatile int*, volatile int*>);
static_assert(std::is_constructible_v<std::span<volatile int, Extent>, int*, int*>);
static_assert(!std::is_constructible_v<std::span<volatile int, Extent>, const int*, const int*>);
static_assert(std::is_constructible_v<std::span<volatile int, Extent>, volatile int*, volatile int*>);
static_assert(!std::is_constructible_v<std::span<int, Extent>, int*, float*>); // types wrong
}
constexpr bool test() {
test_constructibility<std::dynamic_extent>();
test_constructibility<3>();
struct A {};
assert((test_ctor<int, int*>()));
assert((test_ctor<int, sized_sentinel<int*>>()));
assert((test_ctor<A, A*>()));
assert((test_ctor<A, sized_sentinel<A*>>()));
return true;
}
#ifndef TEST_HAS_NO_EXCEPTIONS
// A stripped down contiguous iterator that throws when using operator-.
template <class It>
class throw_operator_minus {
It it_;
public:
typedef std::contiguous_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
typedef std::remove_reference_t<reference> element_type;
throw_operator_minus() : it_() {}
explicit throw_operator_minus(It it) : it_(it) {}
reference operator*() const { return *it_; }
pointer operator->() const { return it_; }
reference operator[](difference_type n) const { return it_[n]; }
throw_operator_minus& operator++() {
++it_;
return *this;
}
throw_operator_minus& operator--() {
--it_;
return *this;
}
throw_operator_minus operator++(int) { return throw_operator_minus(it_++); }
throw_operator_minus operator--(int) { return throw_operator_minus(it_--); }
throw_operator_minus& operator+=(difference_type n) {
it_ += n;
return *this;
}
throw_operator_minus& operator-=(difference_type n) {
it_ -= n;
return *this;
}
friend throw_operator_minus operator+(throw_operator_minus x, difference_type n) {
x += n;
return x;
}
friend throw_operator_minus operator+(difference_type n, throw_operator_minus x) {
x += n;
return x;
}
friend throw_operator_minus operator-(throw_operator_minus x, difference_type n) {
x -= n;
return x;
}
friend difference_type operator-(throw_operator_minus, throw_operator_minus) { throw 42; };
friend bool operator==(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ == y.it_; }
friend bool operator<(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ < y.it_; }
friend bool operator>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ > y.it_; }
friend bool operator<=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <= y.it_; }
friend bool operator>=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ >= y.it_; }
};
template <class It>
throw_operator_minus(It) -> throw_operator_minus<It>;
void test_exceptions() {
std::array a{42};
TEST_VALIDATE_EXCEPTION(
int,
[](int i) { assert(i == 42); },
(std::span<int>{throw_operator_minus{a.begin()}, throw_operator_minus{a.end()}}));
TEST_VALIDATE_EXCEPTION(
int,
[](int i) { assert(i == 42); },
(std::span<int, 1>{throw_operator_minus{a.begin()}, throw_operator_minus{a.end()}}));
}
#endif // TEST_HAS_NO_EXCEPTIONS
int main(int, char**) {
test();
#ifndef TEST_HAS_NO_EXCEPTIONS
test_exceptions();
#endif
static_assert(test());
return 0;
}
|