|
18 | 18 | #define ASSERT_IF_DEBUG(x)
|
19 | 19 | #endif
|
20 | 20 |
|
| 21 | +#if defined(__clang__) |
| 22 | +#if __has_attribute(lifetimebound) |
| 23 | +#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]] |
| 24 | +#else |
| 25 | +#define SPAN_ATTR_LIFETIMEBOUND |
| 26 | +#endif |
| 27 | +#else |
| 28 | +#define SPAN_ATTR_LIFETIMEBOUND |
| 29 | +#endif |
| 30 | + |
21 | 31 | /** A Span is an object that can refer to a contiguous sequence of objects.
|
22 | 32 | *
|
23 | 33 | * It implements a subset of C++20's std::span.
|
@@ -84,6 +94,14 @@ class Span
|
84 | 94 | C* m_data;
|
85 | 95 | std::size_t m_size;
|
86 | 96 |
|
| 97 | + template <class T> |
| 98 | + struct is_Span_int : public std::false_type {}; |
| 99 | + template <class T> |
| 100 | + struct is_Span_int<Span<T>> : public std::true_type {}; |
| 101 | + template <class T> |
| 102 | + struct is_Span : public is_Span_int<typename std::remove_cv<T>::type>{}; |
| 103 | + |
| 104 | + |
87 | 105 | public:
|
88 | 106 | constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
|
89 | 107 |
|
@@ -134,8 +152,19 @@ class Span
|
134 | 152 | * To prevent surprises, only Spans for constant value types are supported when passing in temporaries.
|
135 | 153 | * Note that this restriction does not exist when converting arrays or other Spans (see above).
|
136 | 154 | */
|
137 |
| - template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0> |
138 |
| - constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {} |
| 155 | + template <typename V> |
| 156 | + constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND, |
| 157 | + typename std::enable_if<!is_Span<V>::value && |
| 158 | + std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && |
| 159 | + std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) |
| 160 | + : m_data(other.data()), m_size(other.size()){} |
| 161 | + |
| 162 | + template <typename V> |
| 163 | + constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND, |
| 164 | + typename std::enable_if<!is_Span<V>::value && |
| 165 | + std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value && |
| 166 | + std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) |
| 167 | + : m_data(other.data()), m_size(other.size()){} |
139 | 168 |
|
140 | 169 | constexpr C* data() const noexcept { return m_data; }
|
141 | 170 | constexpr C* begin() const noexcept { return m_data; }
|
@@ -192,9 +221,9 @@ class Span
|
192 | 221 | /** MakeSpan for arrays: */
|
193 | 222 | template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
|
194 | 223 | /** MakeSpan for temporaries / rvalue references, only supporting const output. */
|
195 |
| -template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); } |
| 224 | +template <typename V> constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); } |
196 | 225 | /** MakeSpan for (lvalue) references, supporting mutable output. */
|
197 |
| -template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; } |
| 226 | +template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; } |
198 | 227 |
|
199 | 228 | /** Pop the last element off a span, and return a reference to that element. */
|
200 | 229 | template <typename T>
|
|
0 commit comments