Diag-Client-Lib
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
span.h
Go to the documentation of this file.
1 /* Diagnostic Client library
2  * Copyright (C) 2024 Avijit Dey
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8 #ifndef DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_SPAN_H_
9 #define DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_SPAN_H_
10 
11 #include <array>
12 #include <iostream>
13 #include <limits>
14 #include <type_traits>
15 #include <utility>
16 
17 namespace core_type {
18 
23 constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
24 
34 template<typename T, std::size_t Extent = dynamic_extent>
35 class Span;
36 
37 namespace details {
38 
46 inline void CheckIfExpectedOrAbort(bool cond, const char *message, const std::string_view file_name,
47  int line_no) {
48  if (!cond) {
49  std::cerr << message << " [" << file_name << ":" << line_no << "]" << std::endl;
50  std::abort();
51  }
52 }
53 
59 template<typename T>
60 using remove_cv_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
61 
65 template<typename>
66 struct is_span : std::false_type {};
67 
75 template<typename T, std::size_t Extent>
76 struct is_span<Span<T, Extent>> : std::true_type {};
77 
81 template<typename>
82 struct is_std_array : std::false_type {};
83 
91 template<typename T, std::size_t N>
92 struct is_std_array<std::array<T, N>> : std::true_type {};
93 
97 template<typename T, typename = void>
98 struct is_data_size_valid : std::false_type {};
99 
105 template<typename T>
107  T, std::void_t<decltype(std::data(std::declval<T>())), decltype(std::size(std::declval<T>()))>>
108  : std::true_type {};
109 
117 template<typename T, typename ElementType = remove_cv_ref_t<T>>
120  !std::is_array<ElementType>::value && is_data_size_valid<T>::value;
121 };
122 
130 template<typename, typename, typename = void>
131 struct is_container_element_type_convertible : std::false_type {};
132 
140 template<typename F, typename T>
142  F, T,
143  typename std::enable_if<std::is_convertible<
144  std::remove_pointer_t<decltype(std::data(std::declval<F>()))> (*)[], T (*)[]>::value>::type>
145  : std::true_type {};
146 
154 template<typename T, std::size_t Extent>
155 struct span_storage {
156  constexpr span_storage() noexcept = default;
157 
158  constexpr span_storage(T *ptr, std::size_t) noexcept : ptr_{ptr} {}
159 
160  T *ptr_ = nullptr;
161  std::size_t size_{Extent};
162 };
163 
169 template<typename T>
171  constexpr span_storage() noexcept = default;
172 
173  constexpr span_storage(T *ptr, std::size_t size) noexcept : ptr_{ptr}, size_{size} {}
174 
175  T *ptr_ = nullptr;
176  std::size_t size_ = 0;
177 };
178 
179 } // namespace details
180 
190 template<typename T, std::size_t Extent>
191 class Span final {
192  static_assert(!std::is_abstract<T>::value,
193  "A span's element type cannot be an abstract class type");
194 
195  public:
199  using element_type = T;
200 
204  using value_type = typename std::remove_cv<element_type>::type;
205 
209  using size_type = std::size_t;
210 
214  using difference_type = std::ptrdiff_t;
215 
220 
224  using const_pointer = const element_type *;
225 
230 
234  using const_reference = const element_type &;
235 
240  using iterator = pointer;
241 
247 
251  using reverse_iterator = std::reverse_iterator<iterator>;
252 
256  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
257 
261  static constexpr size_type extent = Extent;
262 
267  template<std::size_t E = Extent,
268  typename std::enable_if<(E == dynamic_extent || E == 0), bool>::type = true>
269  constexpr Span() noexcept {}
270 
280  constexpr Span(pointer ptr, size_type count) : storage_{ptr, count} {
281  details::CheckIfExpectedOrAbort(Extent == dynamic_extent || count == Extent, "Invalid range",
282  __FILE__, __LINE__);
283  }
284 
294  constexpr Span(pointer first_elem, pointer last_elem)
295  : storage_{first_elem, last_elem - first_elem} {
296  details::CheckIfExpectedOrAbort(Extent == dynamic_extent || (last_elem - first_elem) == Extent,
297  "Invalid range", __FILE__, __LINE__);
298  }
299 
309  template<std::size_t N, std::size_t E = Extent,
310  typename std::enable_if<
311  (E == dynamic_extent || N == extent) &&
313  bool>::type = true>
314  constexpr explicit Span(element_type (&arr)[N]) noexcept : storage_{arr, N} {}
315 
327  template<typename U, std::size_t N, std::size_t E = Extent,
328  typename std::enable_if<
329  (E == dynamic_extent || N == extent) &&
330  details::is_container_element_type_convertible<std::array<U, N> &, T>::value,
331  bool>::type = true>
332  constexpr explicit Span(std::array<U, N> &arr) noexcept : storage_{arr.data(), N} {}
333 
345  template<typename U, std::size_t N, std::size_t E = Extent,
346  typename std::enable_if<(E == dynamic_extent || N == extent) &&
347  details::is_container_element_type_convertible<
348  const std::array<U, N> &, T>::value,
349  bool>::type = true>
350  constexpr explicit Span(const std::array<U, N> &arr) noexcept : storage_{arr.data(), N} {}
351 
364  template<typename Container, std::size_t E = Extent,
365  typename std::enable_if<
367  details::is_container_element_type_convertible<Container &, T>::value,
368  bool>::type = true>
369  constexpr explicit Span(Container &cont) noexcept : storage_{std::data(cont), std::size(cont)} {}
370 
383  template<typename Container, std::size_t E = Extent,
384  typename std::enable_if<
386  details::is_container_element_type_convertible<Container &, T>::value,
387  bool>::type = true>
388  constexpr explicit Span(const Container &cont) noexcept
389  : storage_{std::data(cont), std::size(cont)} {}
390 
394  constexpr Span(const Span &) noexcept = default;
395 
408  template<
409  typename U, std::size_t N,
410  typename std::enable_if<
411  (Extent == dynamic_extent || N == dynamic_extent || Extent == N) &&
412  details::is_container_element_type_convertible<U (*)[], T (*)[]>::value>::type = true>
413  constexpr explicit Span(const Span<U, N> &other_span) noexcept
414  : storage_{other_span.data(), other_span.size()} {}
415 
419  ~Span() noexcept = default;
420 
424  constexpr Span &operator=(const Span &other) noexcept = default;
425 
434  template<std::size_t Count>
435  constexpr Span<element_type, Count> first() const {
436  details::CheckIfExpectedOrAbort(Count <= size(), "Count > size()", __FILE__, __LINE__);
437  return Span{data(), Count};
438  }
439 
448  details::CheckIfExpectedOrAbort(count <= size(), "Count > size()", __FILE__, __LINE__);
449  return Span{data(), count};
450  }
451 
460  template<std::size_t Count>
461  constexpr Span<element_type, Count> last() const {
462  details::CheckIfExpectedOrAbort(Count <= size(), "Count > size()", __FILE__, __LINE__);
463  return Span{data() + (size() - Count), Count};
464  }
465 
474  details::CheckIfExpectedOrAbort(count <= size(), "count > size()", __FILE__, __LINE__);
475  return Span{data() + (size() - count), count};
476  }
477 
490  template<std::size_t Offset, std::size_t Count = dynamic_extent>
491  constexpr auto subspan() const noexcept
492  -> Span<element_type, Count != dynamic_extent
493  ? Count
494  : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)> {
496  (Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset)),
497  "(Offset <= size() && (Count == dynamic_extent || Count <= size() - "
498  "Offset))",
499  __FILE__, __LINE__);
500  return Span{data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
501  }
502 
513  size_type count = dynamic_extent) const {
515  (offset <= size() && (count == dynamic_extent || count <= size() - offset)),
516  "(offset <= size() && (count == dynamic_extent || count <= size() - "
517  "offset))",
518  __FILE__, __LINE__);
519  return {data() + offset, count == dynamic_extent ? size() - offset : count};
520  }
521 
526  constexpr size_type size() const noexcept { return storage_.size_; }
527 
532  constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
533 
538  constexpr bool empty() const noexcept { return size() == 0u; }
539 
546  constexpr reference operator[](size_type idx) const {
547  details::CheckIfExpectedOrAbort(idx < size(), "idx > size()", __FILE__, __LINE__);
548  return *(data() + idx);
549  }
550 
556  constexpr reference front() const {
557  details::CheckIfExpectedOrAbort(!empty(), "Span is empty", __FILE__, __LINE__);
558  return *(data());
559  }
560 
566  constexpr reference back() const {
567  details::CheckIfExpectedOrAbort(!empty(), "Span is empty", __FILE__, __LINE__);
568  return *(data() + (size() - 1));
569  }
570 
575  constexpr pointer data() const noexcept { return storage_.ptr_; }
576 
581  constexpr iterator begin() const noexcept { return data(); }
582 
587  constexpr iterator end() const noexcept { return data() + size(); }
588 
593  constexpr const_iterator cbegin() const noexcept { return const_iterator(begin()); }
594 
599  constexpr const_iterator cend() const noexcept { return const_iterator(end()); }
600 
605  constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
606 
611  constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
612 
617  constexpr const_reverse_iterator crbegin() const noexcept {
618  return const_reverse_iterator(end());
619  }
620 
625  constexpr const_reverse_iterator crend() const noexcept {
626  return const_reverse_iterator(begin());
627  }
628 
629  private:
634 };
635 
636 template<class T, size_t N>
637 Span(T (&)[N]) -> Span<T, N>;
638 
639 template<class T, size_t N>
640 Span(std::array<T, N> &) -> Span<T, N>;
641 
642 template<class T, size_t N>
643 Span(const std::array<T, N> &) -> Span<const T, N>;
644 
645 template<class Container>
646 Span(Container &) -> Span<
647  typename std::remove_reference<decltype(*std::data(std::declval<Container &>()))>::type>;
648 
649 template<class Container>
651 
652 } // namespace core_type
653 
654 #endif // DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_SPAN_H_
A view over a contiguous sequence of objects.
Definition: span.h:191
constexpr reference back() const
Return a reference to the last element of this Span.
Definition: span.h:566
typename std::remove_cv< element_type >::type value_type
Type alias for the type of values in this Span.
Definition: span.h:204
const element_type * const_pointer
Type alias type for a pointer to an const element.
Definition: span.h:224
constexpr Span< element_type, dynamic_extent > last(size_type count) const
Return a subspan containing only the last elements of this Span.
Definition: span.h:473
constexpr size_type size_bytes() const noexcept
Return the size of this Span in bytes.
Definition: span.h:532
pointer iterator
The type of an iterator to elements.
Definition: span.h:240
details::span_storage< T, Extent > storage_
The storage of span related data.
Definition: span.h:633
element_type & reference
Type alias type for a reference to an element.
Definition: span.h:229
constexpr pointer data() const noexcept
Return a pointer to the start of the memory block covered by this Span.
Definition: span.h:575
static constexpr size_type extent
A constant reflecting the configured Extent of this Span.
Definition: span.h:261
const element_type & const_reference
Type alias type for a reference to an const element.
Definition: span.h:234
constexpr Span(element_type(&arr)[N]) noexcept
Construct a new Span from the given raw array.
Definition: span.h:314
constexpr Span(const std::array< U, N > &arr) noexcept
Construct a new Span from the given const std::array.
Definition: span.h:350
T element_type
Type alias for the type of elements in this Span.
Definition: span.h:199
constexpr Span(pointer ptr, size_type count)
Construct a new Span from the given pointer and size.
Definition: span.h:280
constexpr auto subspan() const noexcept -> Span< element_type, Count !=dynamic_extent ? Count :(Extent !=dynamic_extent ? Extent - Offset :dynamic_extent)>
Return a subspan of this Span.
Definition: span.h:491
std::size_t size_type
Type alias for the type of parameters that indicate a size or a number of values.
Definition: span.h:209
constexpr const_reverse_iterator crbegin() const noexcept
Return a const_reverse_iterator pointing to the last element of this Span.
Definition: span.h:617
constexpr Span() noexcept
Default constructor.
Definition: span.h:269
std::ptrdiff_t difference_type
Type alias for the type of parameters that indicate a difference of indexes into the Span.
Definition: span.h:214
constexpr size_type size() const noexcept
Return the size of this Span.
Definition: span.h:526
constexpr Span< element_type, Count > first() const
Return a subspan containing only the first elements of this Span.
Definition: span.h:435
constexpr Span(const Container &cont) noexcept
Construct a new Span from the given const container.
Definition: span.h:388
constexpr Span< element_type, dynamic_extent > first(size_type count) const
Return a subspan containing only the first elements of this Span.
Definition: span.h:447
constexpr Span< element_type, Count > last() const
Return a subspan containing only the last elements of this Span.
Definition: span.h:461
constexpr Span(const Span &) noexcept=default
Copy construct a new Span from another instance.
constexpr Span(Container &cont) noexcept
Construct a new Span from the given container.
Definition: span.h:369
element_type * pointer
Type alias type for a pointer to an element.
Definition: span.h:219
constexpr reverse_iterator rbegin() const noexcept
Return a reverse_iterator pointing to the last element of this Span.
Definition: span.h:605
constexpr Span(std::array< U, N > &arr) noexcept
Construct a new Span from the given std::array.
Definition: span.h:332
const_pointer const_iterator
The type of a const_iterator to elements.
Definition: span.h:246
constexpr reverse_iterator rend() const noexcept
Return a reverse_iterator pointing past the first element of this Span.
Definition: span.h:611
constexpr Span(const Span< U, N > &other_span) noexcept
Converting constructor.
Definition: span.h:413
~Span() noexcept=default
Destructor.
constexpr iterator end() const noexcept
Return an iterator pointing past the last element of this Span.
Definition: span.h:587
constexpr const_iterator cend() const noexcept
Return a const_iterator pointing past the last element of this Span.
Definition: span.h:599
constexpr const_reverse_iterator crend() const noexcept
Return a const_reverse_iterator pointing past the first element of this Span.
Definition: span.h:625
constexpr Span< element_type, dynamic_extent > subspan(size_type offset, size_type count=dynamic_extent) const
Return a subspan of this Span.
Definition: span.h:512
constexpr bool empty() const noexcept
Return whether this Span is empty.
Definition: span.h:538
constexpr const_iterator cbegin() const noexcept
Return a const_iterator pointing to the first element of this Span.
Definition: span.h:593
constexpr reference operator[](size_type idx) const
Return a reference to the n-th element of this Span.
Definition: span.h:546
constexpr Span(pointer first_elem, pointer last_elem)
Construct a new Span from the open range between [first_elem, last_elem)
Definition: span.h:294
std::reverse_iterator< iterator > reverse_iterator
The type of a reverse_iterator to elements.
Definition: span.h:251
constexpr reference front() const
Return a reference to the first element of this Span.
Definition: span.h:556
std::reverse_iterator< const_iterator > const_reverse_iterator
The type of a const_reverse_iterator to elements.
Definition: span.h:256
constexpr iterator begin() const noexcept
Return an iterator pointing to the first element of this Span.
Definition: span.h:581
void CheckIfExpectedOrAbort(bool cond, const char *message, const std::string_view file_name, int line_no)
Check if the condition is as expected otherwise abort with provided message.
Definition: span.h:46
typename std::remove_cv< typename std::remove_reference< T >::type >::type remove_cv_ref_t
Helper template alias to remove reference and cv and return the actual type.
Definition: span.h:60
constexpr std::size_t dynamic_extent
A constant for creating Spans with dynamic sizes.
Definition: span.h:23
Span(T(&)[N]) -> Span< T, N >
Checks if std::remove_pointer_t<decltype(std::data(arr))>(*)[] is convertible to T(*)[].
Definition: span.h:131
Check if the element type is not a specialization of Span, Container is not a specialization of Array...
Definition: span.h:118
static constexpr bool value
Definition: span.h:119
Primary template handles std::size, std::data that have no nested ::type member.
Definition: span.h:98
Primary template handles Span types that have no nested ::type member.
Definition: span.h:66
Primary template handles std::array types that have no nested ::type member.
Definition: span.h:82
Storage class needed for span.
Definition: span.h:155
constexpr span_storage() noexcept=default