Diag-Client-Lib
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, int line_no) {
47  if (!cond) {
48  std::cerr << message << " [" << file_name << ":" << line_no << "]" << std::endl;
49  std::abort();
50  }
51 }
52 
58 template<typename T>
59 using remove_cv_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
60 
64 template<typename>
65 struct is_span : std::false_type {};
66 
74 template<typename T, std::size_t Extent>
75 struct is_span<Span<T, Extent>> : std::true_type {};
76 
80 template<typename>
81 struct is_std_array : std::false_type {};
82 
90 template<typename T, std::size_t N>
91 struct is_std_array<std::array<T, N>> : std::true_type {};
92 
96 template<typename T, typename = void>
97 struct is_data_size_valid : std::false_type {};
98 
104 template<typename T>
106  std::void_t<decltype(std::data(std::declval<T>())), decltype(std::size(std::declval<T>()))>>
107  : std::true_type {};
108 
116 template<typename T, typename ElementType = remove_cv_ref_t<T>>
119  !std::is_array<ElementType>::value && is_data_size_valid<T>::value;
120 };
121 
129 template<typename, typename, typename = void>
130 struct is_container_element_type_convertible : std::false_type {};
131 
139 template<typename F, typename T>
141  F, T,
142  typename std::enable_if<
143  std::is_convertible<std::remove_pointer_t<decltype(std::data(std::declval<F>()))> (*)[], T (*)[]>::value>::type>
144  : std::true_type {};
145 
153 template<typename T, std::size_t Extent>
154 struct span_storage {
155  constexpr span_storage() noexcept = default;
156 
157  constexpr span_storage(T *ptr, std::size_t) noexcept : ptr_{ptr} {}
158 
159  T *ptr_ = nullptr;
160  std::size_t size_{Extent};
161 };
162 
168 template<typename T>
170  constexpr span_storage() noexcept = default;
171 
172  constexpr span_storage(T *ptr, std::size_t size) noexcept : ptr_{ptr}, size_{size} {}
173 
174  T *ptr_ = nullptr;
175  std::size_t size_ = 0;
176 };
177 
178 } // namespace details
179 
189 template<typename T, std::size_t Extent>
190 class Span final {
191  static_assert(!std::is_abstract<T>::value, "A span's element type cannot be an abstract class type");
192 
193  public:
197  using element_type = T;
198 
202  using value_type = typename std::remove_cv<element_type>::type;
203 
207  using size_type = std::size_t;
208 
212  using difference_type = std::ptrdiff_t;
213 
218 
222  using const_pointer = const element_type *;
223 
228 
232  using const_reference = const element_type &;
233 
238  using iterator = pointer;
239 
245 
249  using reverse_iterator = std::reverse_iterator<iterator>;
250 
254  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
255 
259  static constexpr size_type extent = Extent;
260 
265  template<std::size_t E = Extent, typename std::enable_if<(E == dynamic_extent || E == 0), bool>::type = true>
266  constexpr Span() noexcept {}
267 
277  constexpr Span(pointer ptr, size_type count) : storage_{ptr, count} {
278  details::CheckIfExpectedOrAbort(Extent == dynamic_extent || count == Extent, "Invalid range", __FILE__, __LINE__);
279  }
280 
290  constexpr Span(pointer first_elem, pointer last_elem) : storage_{first_elem, last_elem - first_elem} {
291  details::CheckIfExpectedOrAbort(Extent == dynamic_extent || (last_elem - first_elem) == Extent, "Invalid range",
292  __FILE__, __LINE__);
293  }
294 
304  template<std::size_t N, std::size_t E = Extent,
305  typename std::enable_if<(E == dynamic_extent || N == extent) &&
307  bool>::type = true>
308  constexpr explicit Span(element_type (&arr)[N]) noexcept : storage_{arr, N} {}
309 
321  template<typename U, std::size_t N, std::size_t E = Extent,
322  typename std::enable_if<(E == dynamic_extent || N == extent) &&
323  details::is_container_element_type_convertible<std::array<U, N> &, T>::value,
324  bool>::type = true>
325  constexpr explicit Span(std::array<U, N> &arr) noexcept : storage_{arr.data(), N} {}
326 
338  template<
339  typename U, std::size_t N, std::size_t E = Extent,
340  typename std::enable_if<(E == dynamic_extent || N == extent) &&
341  details::is_container_element_type_convertible<const std::array<U, N> &, T>::value,
342  bool>::type = true>
343  constexpr explicit Span(const std::array<U, N> &arr) noexcept : storage_{arr.data(), N} {}
344 
357  template<typename Container, std::size_t E = Extent,
358  typename std::enable_if<(E == dynamic_extent) && details::is_container_type<Container>::value &&
359  details::is_container_element_type_convertible<Container &, T>::value,
360  bool>::type = true>
361  constexpr explicit Span(Container &cont) noexcept : storage_{std::data(cont), std::size(cont)} {}
362 
375  template<typename Container, std::size_t E = Extent,
376  typename std::enable_if<(E == dynamic_extent) && details::is_container_type<Container>::value &&
377  details::is_container_element_type_convertible<Container &, T>::value,
378  bool>::type = true>
379  constexpr explicit Span(const Container &cont) noexcept : storage_{std::data(cont), std::size(cont)} {}
380 
384  constexpr Span(const Span &) noexcept = default;
385 
398  template<
399  typename U, std::size_t N,
400  typename std::enable_if<(Extent == dynamic_extent || N == dynamic_extent || Extent == N) &&
401  details::is_container_element_type_convertible<U (*)[], T (*)[]>::value>::type = true>
402  constexpr explicit Span(const Span<U, N> &other_span) noexcept : storage_{other_span.data(), other_span.size()} {}
403 
407  ~Span() noexcept = default;
408 
412  constexpr Span &operator=(const Span &other) noexcept = default;
413 
422  template<std::size_t Count>
423  constexpr Span<element_type, Count> first() const {
424  details::CheckIfExpectedOrAbort(Count <= size(), "Count > size()", __FILE__, __LINE__);
425  return Span{data(), Count};
426  }
427 
436  details::CheckIfExpectedOrAbort(count <= size(), "Count > size()", __FILE__, __LINE__);
437  return Span{data(), count};
438  }
439 
448  template<std::size_t Count>
449  constexpr Span<element_type, Count> last() const {
450  details::CheckIfExpectedOrAbort(Count <= size(), "Count > size()", __FILE__, __LINE__);
451  return Span{data() + (size() - Count), Count};
452  }
453 
462  details::CheckIfExpectedOrAbort(count <= size(), "count > size()", __FILE__, __LINE__);
463  return Span{data() + (size() - count), count};
464  }
465 
478  template<std::size_t Offset, std::size_t Count = dynamic_extent>
479  constexpr auto subspan() const noexcept
480  -> Span<element_type,
481  Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)> {
482  details::CheckIfExpectedOrAbort((Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset)),
483  "(Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset))",
484  __FILE__, __LINE__);
485  return Span{data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
486  }
487 
498  details::CheckIfExpectedOrAbort((offset <= size() && (count == dynamic_extent || count <= size() - offset)),
499  "(offset <= size() && (count == dynamic_extent || count <= size() - offset))",
500  __FILE__, __LINE__);
501  return {data() + offset, count == dynamic_extent ? size() - offset : count};
502  }
503 
508  constexpr size_type size() const noexcept { return storage_.size_; }
509 
514  constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
515 
520  constexpr bool empty() const noexcept { return size() == 0u; }
521 
528  constexpr reference operator[](size_type idx) const {
529  details::CheckIfExpectedOrAbort(idx < size(), "idx > size()", __FILE__, __LINE__);
530  return *(data() + idx);
531  }
532 
538  constexpr reference front() const {
539  details::CheckIfExpectedOrAbort(!empty(), "Span is empty", __FILE__, __LINE__);
540  return *(data());
541  }
542 
548  constexpr reference back() const {
549  details::CheckIfExpectedOrAbort(!empty(), "Span is empty", __FILE__, __LINE__);
550  return *(data() + (size() - 1));
551  }
552 
557  constexpr pointer data() const noexcept { return storage_.ptr_; }
558 
563  constexpr iterator begin() const noexcept { return data(); }
564 
569  constexpr iterator end() const noexcept { return data() + size(); }
570 
575  constexpr const_iterator cbegin() const noexcept { return const_iterator(begin()); }
576 
581  constexpr const_iterator cend() const noexcept { return const_iterator(end()); }
582 
587  constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
588 
593  constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
594 
599  constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
600 
605  constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
606 
607  private:
612 };
613 
614 template<class T, size_t N>
615 Span(T (&)[N]) -> Span<T, N>;
616 
617 template<class T, size_t N>
618 Span(std::array<T, N> &) -> Span<T, N>;
619 
620 template<class T, size_t N>
621 Span(const std::array<T, N> &) -> Span<const T, N>;
622 
623 template<class Container>
625 
626 template<class Container>
628 
629 } // namespace core_type
630 
631 #endif // DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_SPAN_H_
A view over a contiguous sequence of objects.
Definition: span.h:190
constexpr reference back() const
Return a reference to the last element of this Span.
Definition: span.h:548
typename std::remove_cv< element_type >::type value_type
Type alias for the type of values in this Span.
Definition: span.h:202
const element_type * const_pointer
Type alias type for a pointer to an const element.
Definition: span.h:222
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:461
constexpr size_type size_bytes() const noexcept
Return the size of this Span in bytes.
Definition: span.h:514
pointer iterator
The type of an iterator to elements.
Definition: span.h:238
details::span_storage< T, Extent > storage_
The storage of span related data.
Definition: span.h:611
element_type & reference
Type alias type for a reference to an element.
Definition: span.h:227
constexpr pointer data() const noexcept
Return a pointer to the start of the memory block covered by this Span.
Definition: span.h:557
static constexpr size_type extent
A constant reflecting the configured Extent of this Span.
Definition: span.h:259
const element_type & const_reference
Type alias type for a reference to an const element.
Definition: span.h:232
constexpr Span(element_type(&arr)[N]) noexcept
Construct a new Span from the given raw array.
Definition: span.h:308
constexpr Span(const std::array< U, N > &arr) noexcept
Construct a new Span from the given const std::array.
Definition: span.h:343
T element_type
Type alias for the type of elements in this Span.
Definition: span.h:197
constexpr Span(pointer ptr, size_type count)
Construct a new Span from the given pointer and size.
Definition: span.h:277
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:479
std::size_t size_type
Type alias for the type of parameters that indicate a size or a number of values.
Definition: span.h:207
constexpr const_reverse_iterator crbegin() const noexcept
Return a const_reverse_iterator pointing to the last element of this Span.
Definition: span.h:599
constexpr Span() noexcept
Default constructor.
Definition: span.h:266
std::ptrdiff_t difference_type
Type alias for the type of parameters that indicate a difference of indexes into the Span.
Definition: span.h:212
constexpr size_type size() const noexcept
Return the size of this Span.
Definition: span.h:508
constexpr Span< element_type, Count > first() const
Return a subspan containing only the first elements of this Span.
Definition: span.h:423
constexpr Span(const Container &cont) noexcept
Construct a new Span from the given const container.
Definition: span.h:379
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:435
constexpr Span< element_type, Count > last() const
Return a subspan containing only the last elements of this Span.
Definition: span.h:449
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:361
element_type * pointer
Type alias type for a pointer to an element.
Definition: span.h:217
constexpr reverse_iterator rbegin() const noexcept
Return a reverse_iterator pointing to the last element of this Span.
Definition: span.h:587
constexpr Span(std::array< U, N > &arr) noexcept
Construct a new Span from the given std::array.
Definition: span.h:325
const_pointer const_iterator
The type of a const_iterator to elements.
Definition: span.h:244
constexpr reverse_iterator rend() const noexcept
Return a reverse_iterator pointing past the first element of this Span.
Definition: span.h:593
constexpr Span(const Span< U, N > &other_span) noexcept
Converting constructor.
Definition: span.h:402
~Span() noexcept=default
Destructor.
constexpr iterator end() const noexcept
Return an iterator pointing past the last element of this Span.
Definition: span.h:569
constexpr const_iterator cend() const noexcept
Return a const_iterator pointing past the last element of this Span.
Definition: span.h:581
constexpr const_reverse_iterator crend() const noexcept
Return a const_reverse_iterator pointing past the first element of this Span.
Definition: span.h:605
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:497
constexpr bool empty() const noexcept
Return whether this Span is empty.
Definition: span.h:520
constexpr const_iterator cbegin() const noexcept
Return a const_iterator pointing to the first element of this Span.
Definition: span.h:575
constexpr reference operator[](size_type idx) const
Return a reference to the n-th element of this Span.
Definition: span.h:528
constexpr Span(pointer first_elem, pointer last_elem)
Construct a new Span from the open range between [first_elem, last_elem)
Definition: span.h:290
std::reverse_iterator< iterator > reverse_iterator
The type of a reverse_iterator to elements.
Definition: span.h:249
constexpr reference front() const
Return a reference to the first element of this Span.
Definition: span.h:538
std::reverse_iterator< const_iterator > const_reverse_iterator
The type of a const_reverse_iterator to elements.
Definition: span.h:254
constexpr iterator begin() const noexcept
Return an iterator pointing to the first element of this Span.
Definition: span.h:563
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:59
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:130
Check if the element type is not a specialization of Span, Container is not a specialization of Array...
Definition: span.h:117
static constexpr bool value
Definition: span.h:118
Primary template handles std::size, std::data that have no nested ::type member.
Definition: span.h:97
Primary template handles Span types that have no nested ::type member.
Definition: span.h:65
Primary template handles std::array types that have no nested ::type member.
Definition: span.h:81
Storage class needed for span.
Definition: span.h:154
constexpr span_storage() noexcept=default