35 #ifndef KAT_CONTAINERS_SPAN_HPP_ 36 #define KAT_CONTAINERS_SPAN_HPP_ 38 #include <type_traits> 43 #include "detail/normal_iterator.hpp" 44 #include <kat/detail/execution_space_specifiers.hpp> 45 #include <kat/detail/range_access.hpp> 48 #if __cplusplus >= 202001L 54 #if __cplusplus >= 201703L 57 constexpr
const std::size_t dynamic_extent =
static_cast<std::size_t
>(-1);
59 template<
typename Type, std::
size_t Extent>
65 #if __cplusplus >= 202001L 66 using iter_reference_t = std::iter_reference_t<T>;
68 using iter_reference_t = decltype(*std::declval<T&>());
74 template<
typename T, std::
size_t Num>
77 #if __cplusplus >= 202001L 78 template<
typename T, std::
size_t Num>
79 struct is_span<std::
span<T, Num>> : std::true_type {};
81 template<
typename T, std::
size_t Num>
82 struct is_span<std::
span<T, Num>> : std::true_type {};
96 template<std::
size_t Extent>
103 static constexpr KAT_HD std::size_t extent() noexcept
113 : extent_value(extent)
116 constexpr KAT_HD std::size_t
117 extent()
const noexcept
119 return this->extent_value;
123 std::size_t extent_value;
128 template<
typename Type, std::
size_t Extent = dynamic_extent>
134 template<std::size_t Offset, std::size_t Count, typename = typename std::enable_if<Count != dynamic_extent>::type>
135 static constexpr KAT_HD std::size_t S_subspan_extent()
137 static_assert(Count != dynamic_extent,
"This implementation should not have been instantiated for Count == dynamic_extent...");
141 template<std::
size_t Offset>
142 static constexpr KAT_HD std::size_t S_subspan_extent<Offset, dynamic_extent>()
144 #if __cplusplus >= 201703L 145 if constexpr KAT_HD (extent != dynamic_extent)
147 if (extent != dynamic_extent)
149 return Extent - Offset;
151 return dynamic_extent;
161 template<
typename T, std::
size_t ArrayExtent>
162 using is_compatible_array = std::integral_constant<bool,
164 and (Extent == dynamic_extent or ArrayExtent == Extent)
165 and (std::is_const<Type>::value or not std::is_const<T>::value)
167 and __is_array_convertible<Type, T>
171 template<
typename Iter,
typename Ref = detail::iter_reference_t<Iter>>
172 using is_compatible_iterator = std::integral_constant<bool,
174 #if __cplusplus >= 202001L 176 and contiguous_iterator<Iter>::value
178 and std::is_lvalue_reference<detail::iter_reference_t<Iter>>::value,
179 and std::is_same<std::iter_value_t<Iter>, std::remove_cvref_t<Ref>>::value,
182 and __is_array_convertible<Type, std::remove_reference_t<Ref>>::value
186 #if __cplusplus >= 202001L 187 template<
typename Range>
188 using __is_compatible_range
189 = is_compatible_iterator<ranges::iterator_t<Range>>;
194 using value_type =
typename std::remove_cv<Type>::type;
195 using element_type = Type;
196 using size_type = std::size_t;
197 using reference = element_type&;
198 using const_reference =
const element_type&;
199 using pointer = Type*;
200 using const_pointer =
const Type*;
202 using iterator = kat::detail::normal_iterator<pointer, span>;
203 using const_iterator = kat::detail::normal_iterator<const_pointer, span>;
204 using reverse_iterator = std::reverse_iterator<iterator>;
205 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
206 using difference_type = std::ptrdiff_t;
209 #if __cplusplus >= 201703L 212 static constexpr
const std::size_t extent = Extent;
216 constexpr KAT_HD
span() noexcept
217 #if __cplusplus >= 202001L 218 requires ((Extent + 1u) <= 1u)
220 : extent_(0), ptr_(
nullptr)
222 #if __cplusplus < 202001L 223 static_assert((Extent + 1u) <= 1u,
"Invalid Extent value - for this constructor, can be either dynamic_extent or 0");
228 span(
const span&) noexcept =
default;
230 #if __cplusplus >= 202001L 231 template<
typename T, std::
size_t ArrayExtent>
232 requires (is_compatible_array<T, ArrayExtent>::value)
234 template<typename T, std::size_t ArrayExtent, typename = typename std::enable_if<is_compatible_array<T, ArrayExtent>::value>::type >
237 span(T (&arr)[ArrayExtent]) noexcept
238 :
span(static_cast<pointer>(arr), ArrayExtent)
241 static_assert(is_compatible_array<T, ArrayExtent>::value,
"Attempt to construct a span with an incompatible raw array");
244 #if __cplusplus >= 202001L 245 template<
typename T, std::
size_t ArrayExtent>
246 requires (is_compatible_array<T, ArrayExtent>::value)
248 template<typename T, std::size_t ArrayExtent, typename = typename std::enable_if<is_compatible_array<T, ArrayExtent>::value>::type >
252 :
span(static_cast<pointer>(arr.data()), ArrayExtent)
254 static_assert(is_compatible_array<T, ArrayExtent>::value,
"Attempt to construct a span with an incompatible kat::array");
257 #if __cplusplus >= 202001L 258 template<
typename T, std::
size_t ArrayExtent>
259 requires (is_compatible_array<T, ArrayExtent>::value)
261 template<typename T, std::size_t ArrayExtent, typename = typename std::enable_if<is_compatible_array<const T, ArrayExtent>::value>::type >
264 :
span(static_cast<pointer>(arr.data()), ArrayExtent)
266 static_assert(is_compatible_array<T, ArrayExtent>::value,
"Attempt to construct a span with an incompatible const kat::array");
269 #if __cplusplus >= 202001L 270 template<
typename T, std::
size_t ArrayExtent>
271 requires (is_compatible_array<T, ArrayExtent>::value)
273 template<typename T, std::size_t ArrayExtent, typename = typename std::enable_if<is_compatible_array<T, ArrayExtent>::value>::type >
275 constexpr KAT_HOST
span(std::array<T, ArrayExtent>& arr) noexcept
276 :
span(static_cast<pointer>(arr.data()), ArrayExtent)
278 static_assert(is_compatible_array<T, ArrayExtent>::value,
"Constructing a span with an incompatible std::array");
281 #if __cplusplus >= 202001L 282 template<
typename T, std::
size_t ArrayExtent>
283 requires (is_compatible_array<T, ArrayExtent>::value)
285 template<typename T, std::size_t ArrayExtent, typename = typename std::enable_if<is_compatible_array<const T, ArrayExtent>::value>::type >
287 constexpr KAT_HOST
span(
const std::array<T, ArrayExtent>& arr) noexcept
288 :
span(static_cast<pointer>(arr.data()), ArrayExtent)
290 static_assert(is_compatible_array<T, ArrayExtent>::value,
"Constructing a span with an incompatible const std::array");
298 #if __cplusplus >= 202001L 299 template<ranges::contiguous_range Range>
300 requires (Extent == dynamic_extent)
302 and (!detail::__is_std_array<std::remove_cvref_t<Range>>::value)
303 and (!is_array_v<std::remove_reference_t<Range>>)
304 and (__is_compatible_range<Range>::value)
307 noexcept(noexcept(ranges::data(range))
308 and noexcept(ranges::size(range)))
309 :
span(ranges::data(range), ranges::size(range))
315 #if __cplusplus >= 202001L 316 template<contiguous_iterator ContiguousIterator,
317 sized_sentinel_for<ContiguousIterator> Sentinel>
318 requires (is_compatible_iterator<ContiguousIterator>::value)
319 and (!is_convertible_v<Sentinel, size_type>)
321 span(ContiguousIterator first, Sentinel last)
322 noexcept(noexcept(last - first))
323 : extent_(static_cast<size_type>(last - first)),
324 ptr_(std::to_address(first))
326 if (Extent != dynamic_extent)
327 assert((last - first) == Extent);
330 constexpr KAT_HD
span(pointer first, pointer last) noexcept
331 : extent_(static_cast<size_type>(last - first)),
336 #if __cplusplus >= 202001L 337 template<contiguous_iterator ContiguousIterator>
338 requires (is_compatible_iterator<ContiguousIterator>::value)
340 span(ContiguousIterator first, size_type count)
342 : extent_(count), ptr_(std::to_address(first))
343 { assert(Extent == dynamic_extent or count == Extent); }
345 constexpr KAT_HD
span(pointer first, std::size_t count) noexcept
346 : extent_(count), ptr_(first)
351 template<
typename OType, std::
size_t OExtent>
352 #if __cplusplus >= 2017031L 353 requires (Extent == dynamic_extent or Extent == OExtent)
354 and (__is_array_convertible<Type, OType>::value)
358 : extent_(s.size()), ptr_(s.data())
360 #if __cplusplus < 2017031L 361 static_assert(Extent == dynamic_extent or Extent == OExtent,
"Invalid extent");
368 constexpr KAT_HD
span&
369 operator=(
const span&) noexcept =
default;
373 constexpr KAT_HD size_type
374 size()
const noexcept
375 {
return extent_.extent();}
377 constexpr KAT_HD size_type
378 size_bytes()
const noexcept
379 {
return extent_.extent() *
sizeof(element_type);}
381 [[nodiscard]] constexpr KAT_HD
bool 382 empty()
const noexcept
383 {
return size() == 0;}
387 constexpr KAT_HD reference
388 front()
const noexcept
390 static_assert(extent != 0,
"Zero span extent");
395 constexpr KAT_HD reference
396 back()
const noexcept
398 static_assert(extent != 0,
"Zero span extent");
400 return *(ptr_ + (size() - 1));
403 constexpr KAT_HD reference
404 operator[](size_type idx)
const noexcept
406 static_assert(extent != 0,
"Zero span extent");
407 assert(idx < size());
408 return *(ptr_ + idx);
411 constexpr KAT_HD pointer
412 data()
const noexcept
417 constexpr KAT_HD iterator
418 begin()
const noexcept
419 {
return iterator(ptr_);}
421 constexpr KAT_HD const_iterator
422 cbegin()
const noexcept
423 {
return const_iterator(ptr_);}
425 constexpr KAT_HD iterator
427 {
return iterator(ptr_ + size());}
429 constexpr KAT_HD const_iterator
430 cend()
const noexcept
431 {
return const_iterator(ptr_ + size());}
433 constexpr KAT_HD reverse_iterator
434 rbegin()
const noexcept
435 {
return reverse_iterator(this->end());}
437 constexpr KAT_HD const_reverse_iterator
438 crbegin()
const noexcept
439 {
return const_reverse_iterator(this->cend());}
441 constexpr KAT_HD reverse_iterator
442 rend()
const noexcept
443 {
return reverse_iterator(this->begin());}
445 constexpr KAT_HD const_reverse_iterator
446 crend()
const noexcept
447 {
return const_reverse_iterator(this->cbegin());}
451 template<std::
size_t Count>
453 first()
const noexcept
455 #if __cplusplus >= 201703L 456 if constexpr KAT_HD (Extent == dynamic_extent)
457 assert(Count <= size());
459 static_assert(Count <= extent);
461 if (Extent == dynamic_extent) {
462 assert ((Count < size() or Count == size()) and
"Span fixed element count exceeds its size");
465 assert ((size() < Extent or size() == Extent ) and
"Span size exceeds its extent");
468 return { data(), Count };
472 first(size_type count)
const noexcept
474 assert(count <= size());
475 return { data(), count };
478 template<std::
size_t Count>
480 last()
const noexcept
482 #if __cplusplus >= 201703L 483 if constexpr KAT_HD (Extent == dynamic_extent)
484 assert(Count <= size());
486 static_assert(Count <= extent);
488 if (Extent == dynamic_extent) {
489 assert ((Count < size() or Count == size()) and
"Span fixed element count exceeds its size");
492 assert ((size() < Extent or size() == Extent) and
"Span size exceeds its extent");
495 return {data() + (size() - Count), Count};
499 last(size_type count)
const noexcept
501 assert(count <= size());
502 return {data() + (size() - count), count};
505 template<std::
size_t Offset, std::
size_t Count = dynamic_extent>
506 constexpr KAT_HD
auto 507 subspan()
const noexcept
510 #if __cplusplus >= 201703L 511 if constexpr KAT_HD (Extent == dynamic_extent)
512 assert(Offset <= size());
514 static_assert(Offset <= extent);
516 if (Extent == dynamic_extent) {
517 assert((Offset < size() or Offset == size()) and
"Subspan offset exceeds span size");
520 assert((Offset < Extent or Offset == Extent) and
"Subspan offset exceeds fixed span extent");
524 #if __cplusplus >= 201703L 525 if constexpr KAT_HD (Extent == dynamic_extent)
527 assert(Count <= size());
528 assert(Count <= (size() - Offset));
532 static_assert(Count <= extent);
533 static_assert(Count <= (extent - Offset));
536 if (Extent == dynamic_extent) {
538 assert((size() > Count or size() == Count ) and
"Count exceeds span size");
539 assert( (Count < (size() - Offset) or Count == (size() - Offset)) and
"Subspan ends past the span's end");
542 assert((Count <= extent) and
"Count exceeds span extent");
543 assert(Count <= (extent - Offset) and
"Subspan ends past the span's extent");
547 return {data() + Offset, Count};
550 template<std::
size_t Offset>
551 constexpr KAT_HD
auto 552 subspan<Offset, dynamic_extent>()
const noexcept
553 ->
span<element_type, S_subspan_extent<Offset, dynamic_extent>()>
555 #if __cplusplus >= 201703L 556 if constexpr KAT_HD (Extent == dynamic_extent)
557 assert(Offset <= size());
559 static_assert(Offset <= extent);
561 if (Extent == dynamic_extent) {
562 assert(Offset <= size() and
"Subspan offset exceeds span size");
565 assert((Offset <= Extent) and
"Subspan offset exceeds fixed span extent");
568 return {data() + Offset, size() - Offset};
572 subspan(size_type offset, size_type count = dynamic_extent)
const 575 assert(offset <= size());
576 if (count == dynamic_extent) {
577 count = size() - offset;
581 assert(count <= size());
582 assert(offset + count <= size());
584 return {data() + offset, count};
588 #if __cplusplus >= 202001L 589 [[no_unique_address]]
595 #if __cplusplus < 201703L 596 template<
typename Type, std::
size_t Extent>
601 #if __cplusplus >= 201703L 603 template<
typename Type, std::
size_t ArrayExtent>
606 template<
typename Type, std::
size_t ArrayExtent>
609 template<
typename Type, std::
size_t ArrayExtent>
612 template<
typename Type, std::
size_t ArrayExtent>
616 template<
typename Type, std::
size_t ArrayExtent>
617 span(
const std::array<Type, ArrayExtent>&)
620 template<contiguous_iterator Iter,
typename Sentinel>
624 template<
typename Range>
629 #if __cplusplus >= 201703L 630 template<
typename Type, std::
size_t Extent>
634 return {
reinterpret_cast<const byte*
>(sp.data()), sp.size_bytes()};
637 template<
typename Type, std::
size_t Extent>
641 return {
reinterpret_cast<byte*
>(sp.data()), sp.size_bytes()};
659 span<Type> make_span(Type* ptr, std::size_t count)
664 template<
class Type, std::
size_t Extent>
671 template<
class Type, std::
size_t Extent>
679 template<
class Type, std::
size_t Extent>
687 template<
class Container>
690 make_span(Container &container)
695 template<
class Container>
698 make_span(
const Container &container)
703 template<
class Po
inter>
706 make_span(Pointer& container, std::size_t count)
711 template<
class Po
inter>
714 make_span(Pointer& container)
724 template<std::
size_t Index,
typename Type, std::
size_t Extent>
725 constexpr KAT_HD Type&
728 static_assert(Extent != kat::dynamic_extent and Index < Extent,
729 "get<I> can only be used with a span of non-dynamic (fixed) extent");
736 template<
typename Type, std::
size_t Extent>
737 struct tuple_size<
kat::span<Type, Extent>> :
public std::integral_constant<std::size_t, Extent> {
738 static_assert(Extent != kat::dynamic_extent,
"tuple_size can only " 739 "be used with a span of non-dynamic (fixed) extent");
742 template<std::
size_t Index,
typename Type, std::
size_t Extent>
744 static_assert(Extent != kat::dynamic_extent,
"tuple_element can only " 745 "be used with a span of non-dynamic (fixed) extent");
746 static_assert(Index < Extent,
"Index is less than Extent");
750 #if __cplusplus >= 202001L 753 template<
typename>
extern inline const bool enable_safe_range;
755 template<
typename _ElementType, std::
size_t Extent>
756 inline constexpr KAT_HD
bool 757 enable_safe_range<kat::span<_ElementType, Extent>> =
true;
763 #endif // KAT_CONTAINERS_SPAN_HPP_
Definition: array.hpp:353
Definition: common.hpp:16
This file implements kat::array, an equivalent of C++11's std::array which may be used both in host-s...
Definition: array.hpp:358
A standard container for storing a fixed size sequence of elements, based on std::array - but fully G...
Definition: array.hpp:81