6 #include <initializer_list>
13 constexpr auto size(T
&cont
) noexcept(noexcept(cont
.size())) -> decltype(cont
.size())
14 { return cont
.size(); }
17 constexpr auto size(const T
&cont
) noexcept(noexcept(cont
.size())) -> decltype(cont
.size())
18 { return cont
.size(); }
20 template<typename T
, size_t N
>
21 constexpr size_t size(T (&)[N
]) noexcept
25 constexpr size_t size(std::initializer_list
<T
> list
) noexcept
26 { return list
.size(); }
30 constexpr auto data(T
&cont
) noexcept(noexcept(cont
.data())) -> decltype(cont
.data())
31 { return cont
.data(); }
34 constexpr auto data(const T
&cont
) noexcept(noexcept(cont
.data())) -> decltype(cont
.data())
35 { return cont
.data(); }
37 template<typename T
, size_t N
>
38 constexpr T
* data(T (&arr
)[N
]) noexcept
42 constexpr const T
* data(std::initializer_list
<T
> list
) noexcept
43 { return list
.begin(); }
46 constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
48 template<typename T
, size_t E
=dynamic_extent
>
52 template<typename
... Ts
>
53 struct make_void
{ using type
= void; };
54 template<typename
... Ts
>
55 using void_t
= typename make_void
<Ts
...>::type
;
58 struct is_span_
: std::false_type
{ };
59 template<typename T
, size_t E
>
60 struct is_span_
<span
<T
,E
>> : std::true_type
{ };
62 using is_span
= is_span_
<std::remove_cv_t
<T
>>;
65 struct is_std_array_
: std::false_type
{ };
66 template<typename T
, size_t N
>
67 struct is_std_array_
<std::array
<T
,N
>> : std::true_type
{ };
69 using is_std_array
= is_std_array_
<std::remove_cv_t
<T
>>;
71 template<typename T
, typename
= void>
72 struct has_size_and_data
: std::false_type
{ };
74 struct has_size_and_data
<T
,
75 void_t
<decltype(al::size(std::declval
<T
>())), decltype(al::data(std::declval
<T
>()))>>
77 } // namespace detail_
79 #define REQUIRES(...) bool rt_=true, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
80 #define IS_VALID_CONTAINER(C) \
81 !detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
82 !std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
83 std::is_convertible<std::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
85 template<typename T
, size_t E
>
88 using element_type
= T
;
89 using value_type
= std::remove_cv_t
<T
>;
90 using index_type
= size_t;
91 using difference_type
= ptrdiff_t;
94 using const_pointer
= const T
*;
96 using const_reference
= const T
&;
98 using iterator
= pointer
;
99 using const_iterator
= const_pointer
;
100 using reverse_iterator
= std::reverse_iterator
<iterator
>;
101 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
103 static constexpr size_t extent
{E
};
105 template<REQUIRES(extent
==0)>
106 constexpr span() noexcept
{ }
107 constexpr span(pointer ptr
, index_type
/*count*/) : mData
{ptr
} { }
108 constexpr span(pointer first
, pointer
/*last*/) : mData
{first
} { }
109 constexpr span(element_type (&arr
)[E
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
110 constexpr span(std::array
<value_type
,E
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
111 template<REQUIRES(std::is_const
<element_type
>::value
)>
112 constexpr span(const std::array
<value_type
,E
> &arr
) noexcept
113 : span
{al::data(arr
), al::size(arr
)}
115 template<typename U
, REQUIRES(IS_VALID_CONTAINER(U
))>
116 constexpr span(U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
117 template<typename U
, REQUIRES(IS_VALID_CONTAINER(const U
))>
118 constexpr span(const U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
119 template<typename U
, REQUIRES(!std::is_same
<element_type
,U
>::value
120 && std::is_convertible
<U(*)[],element_type(*)[]>::value
)>
121 constexpr span(const span
<U
,E
> &span_
) noexcept
: span
{al::data(span_
), al::size(span_
)} { }
122 constexpr span(const span
&) noexcept
= default;
124 constexpr span
& operator=(const span
&rhs
) noexcept
= default;
126 constexpr reference
front() const { return *mData
; }
127 constexpr reference
back() const { return *(mData
+E
-1); }
128 constexpr reference
operator[](index_type idx
) const { return mData
[idx
]; }
129 constexpr pointer
data() const noexcept
{ return mData
; }
131 constexpr index_type
size() const noexcept
{ return E
; }
132 constexpr index_type
size_bytes() const noexcept
{ return E
* sizeof(value_type
); }
133 constexpr bool empty() const noexcept
{ return E
== 0; }
135 constexpr iterator
begin() const noexcept
{ return mData
; }
136 constexpr iterator
end() const noexcept
{ return mData
+E
; }
137 constexpr const_iterator
cbegin() const noexcept
{ return mData
; }
138 constexpr const_iterator
cend() const noexcept
{ return mData
+E
; }
140 constexpr reverse_iterator
rbegin() const noexcept
{ return reverse_iterator
{end()}; }
141 constexpr reverse_iterator
rend() const noexcept
{ return reverse_iterator
{begin()}; }
142 constexpr const_reverse_iterator
crbegin() const noexcept
143 { return const_reverse_iterator
{cend()}; }
144 constexpr const_reverse_iterator
crend() const noexcept
145 { return const_reverse_iterator
{cbegin()}; }
148 constexpr span
<element_type
,C
> first() const
150 static_assert(E
>= C
, "New size exceeds original capacity");
151 return span
<element_type
,C
>{mData
, C
};
155 constexpr span
<element_type
,C
> last() const
157 static_assert(E
>= C
, "New size exceeds original capacity");
158 return span
<element_type
,C
>{mData
+(E
-C
), C
};
161 template<size_t O
, size_t C
>
162 constexpr auto subspan() const -> std::enable_if_t
<C
!=dynamic_extent
,span
<element_type
,C
>>
164 static_assert(E
>= O
, "Offset exceeds extent");
165 static_assert(E
-O
>= C
, "New size exceeds original capacity");
166 return span
<element_type
,C
>{mData
+O
, C
};
169 template<size_t O
, size_t C
=dynamic_extent
>
170 constexpr auto subspan() const -> std::enable_if_t
<C
==dynamic_extent
,span
<element_type
,E
-O
>>
172 static_assert(E
>= O
, "Offset exceeds extent");
173 return span
<element_type
,E
-O
>{mData
+O
, E
-O
};
176 /* NOTE: Can't declare objects of a specialized template class prior to
177 * defining the specialization. As a result, these methods need to be
180 constexpr span
<element_type
,dynamic_extent
> first(size_t count
) const;
181 constexpr span
<element_type
,dynamic_extent
> last(size_t count
) const;
182 constexpr span
<element_type
,dynamic_extent
> subspan(size_t offset
,
183 size_t count
=dynamic_extent
) const;
186 pointer mData
{nullptr};
190 class span
<T
,dynamic_extent
> {
192 using element_type
= T
;
193 using value_type
= std::remove_cv_t
<T
>;
194 using index_type
= size_t;
195 using difference_type
= ptrdiff_t;
198 using const_pointer
= const T
*;
199 using reference
= T
&;
200 using const_reference
= const T
&;
202 using iterator
= pointer
;
203 using const_iterator
= const_pointer
;
204 using reverse_iterator
= std::reverse_iterator
<iterator
>;
205 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
207 static constexpr size_t extent
{dynamic_extent
};
209 constexpr span() noexcept
= default;
210 constexpr span(pointer ptr
, index_type count
) : mData
{ptr
}, mDataEnd
{ptr
+count
} { }
211 constexpr span(pointer first
, pointer last
) : mData
{first
}, mDataEnd
{last
} { }
213 constexpr span(element_type (&arr
)[N
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
215 constexpr span(std::array
<value_type
,N
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
216 template<size_t N
, REQUIRES(std::is_const
<element_type
>::value
)>
217 constexpr span(const std::array
<value_type
,N
> &arr
) noexcept
218 : span
{al::data(arr
), al::size(arr
)}
220 template<typename U
, REQUIRES(IS_VALID_CONTAINER(U
))>
221 constexpr span(U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
222 template<typename U
, REQUIRES(IS_VALID_CONTAINER(const U
))>
223 constexpr span(const U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
224 template<typename U
, size_t N
, REQUIRES((!std::is_same
<element_type
,U
>::value
|| extent
!= N
)
225 && std::is_convertible
<U(*)[],element_type(*)[]>::value
)>
226 constexpr span(const span
<U
,N
> &span_
) noexcept
: span
{al::data(span_
), al::size(span_
)} { }
227 constexpr span(const span
&) noexcept
= default;
229 constexpr span
& operator=(const span
&rhs
) noexcept
= default;
231 constexpr reference
front() const { return *mData
; }
232 constexpr reference
back() const { return *(mDataEnd
-1); }
233 constexpr reference
operator[](index_type idx
) const { return mData
[idx
]; }
234 constexpr pointer
data() const noexcept
{ return mData
; }
236 constexpr index_type
size() const noexcept
{ return static_cast<index_type
>(mDataEnd
-mData
); }
237 constexpr index_type
size_bytes() const noexcept
238 { return static_cast<index_type
>(mDataEnd
-mData
) * sizeof(value_type
); }
239 constexpr bool empty() const noexcept
{ return mData
== mDataEnd
; }
241 constexpr iterator
begin() const noexcept
{ return mData
; }
242 constexpr iterator
end() const noexcept
{ return mDataEnd
; }
243 constexpr const_iterator
cbegin() const noexcept
{ return mData
; }
244 constexpr const_iterator
cend() const noexcept
{ return mDataEnd
; }
246 constexpr reverse_iterator
rbegin() const noexcept
{ return reverse_iterator
{end()}; }
247 constexpr reverse_iterator
rend() const noexcept
{ return reverse_iterator
{begin()}; }
248 constexpr const_reverse_iterator
crbegin() const noexcept
249 { return const_reverse_iterator
{cend()}; }
250 constexpr const_reverse_iterator
crend() const noexcept
251 { return const_reverse_iterator
{cbegin()}; }
254 constexpr span
<element_type
,C
> first() const
255 { return span
<element_type
,C
>{mData
, C
}; }
257 constexpr span
first(size_t count
) const
258 { return (count
>= size()) ? *this : span
{mData
, mData
+count
}; }
261 constexpr span
<element_type
,C
> last() const
262 { return span
<element_type
,C
>{mDataEnd
-C
, C
}; }
264 constexpr span
last(size_t count
) const
265 { return (count
>= size()) ? *this : span
{mDataEnd
-count
, mDataEnd
}; }
267 template<size_t O
, size_t C
>
268 constexpr auto subspan() const -> std::enable_if_t
<C
!=dynamic_extent
,span
<element_type
,C
>>
269 { return span
<element_type
,C
>{mData
+O
, C
}; }
271 template<size_t O
, size_t C
=dynamic_extent
>
272 constexpr auto subspan() const -> std::enable_if_t
<C
==dynamic_extent
,span
<element_type
,C
>>
273 { return span
<element_type
,C
>{mData
+O
, mDataEnd
}; }
275 constexpr span
subspan(size_t offset
, size_t count
=dynamic_extent
) const
277 return (offset
> size()) ? span
{} :
278 (count
>= size()-offset
) ? span
{mData
+offset
, mDataEnd
} :
279 span
{mData
+offset
, mData
+offset
+count
};
283 pointer mData
{nullptr};
284 pointer mDataEnd
{nullptr};
287 template<typename T
, size_t E
>
288 constexpr inline auto span
<T
,E
>::first(size_t count
) const -> span
<element_type
,dynamic_extent
>
290 return (count
>= size()) ? span
<element_type
>{mData
, extent
} :
291 span
<element_type
>{mData
, count
};
294 template<typename T
, size_t E
>
295 constexpr inline auto span
<T
,E
>::last(size_t count
) const -> span
<element_type
,dynamic_extent
>
297 return (count
>= size()) ? span
<element_type
>{mData
, extent
} :
298 span
<element_type
>{mData
+extent
-count
, count
};
301 template<typename T
, size_t E
>
302 constexpr inline auto span
<T
,E
>::subspan(size_t offset
, size_t count
) const
303 -> span
<element_type
,dynamic_extent
>
305 return (offset
> size()) ? span
<element_type
>{} :
306 (count
>= size()-offset
) ? span
<element_type
>{mData
+offset
, mData
+extent
} :
307 span
<element_type
>{mData
+offset
, mData
+offset
+count
};
310 #undef IS_VALID_CONTAINER
315 #endif /* AL_SPAN_H */