You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
7.0 KiB

1 year ago
  1. #pragma once
  2. #include <assert.h>
  3. #include <type_traits>
  4. #include <array>
  5. #include "utility.h"
  6. namespace vlc
  7. {
  8. static constexpr const std::size_t dynamic_extent = ~0u;
  9. namespace detail
  10. {
  11. template<class...> using void_t = void;
  12. template<bool B> using bool_constant = std::integral_constant<bool, B>;
  13. template<class T, class ElementType, typename = void> struct is_array_convertible : std::false_type {};
  14. template<class T, class ElementType>
  15. struct is_array_convertible<T, ElementType,
  16. typename std::enable_if<!std::is_void<typename std::remove_pointer<decltype(vlc::data(std::declval<T>()))>::type>::value>::type
  17. > : std::is_convertible<typename std::remove_pointer<decltype(vlc::data(std::declval<T>()))>::type(*)[], ElementType(*)[]>::type
  18. {};
  19. }
  20. template<typename T, std::size_t Extent = dynamic_extent> class span
  21. {
  22. public:
  23. static const std::size_t extent = Extent;
  24. using element_type = T;
  25. using value_type = typename std::remove_cv<T>::type;
  26. using pointer = T * ;
  27. using const_pointer = const T*;
  28. using reference = T & ;
  29. using const_reference = const T&;
  30. using iterator = pointer;
  31. using const_iterator = const_pointer;
  32. using reverse_iterator = std::reverse_iterator<iterator>;
  33. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  34. using index_type = std::size_t;
  35. using difference_type = std::ptrdiff_t;
  36. template<
  37. std::size_t E = Extent,
  38. class = typename std::enable_if<(E == dynamic_extent) || (E == 0)>::type
  39. >
  40. span() noexcept
  41. {}
  42. span(pointer ptr, index_type count) : m_ptr(ptr), m_size(count)
  43. {
  44. assert(extent == dynamic_extent || count == extent);
  45. }
  46. span(pointer first, pointer last) : span(first, last - first)
  47. {}
  48. template <std::size_t N,
  49. std::size_t E = Extent,
  50. class = typename std::enable_if<
  51. (E == dynamic_extent || N == E)
  52. && detail::is_array_convertible<element_type(&)[N], element_type>::value
  53. >::type
  54. >
  55. span(element_type(&arr)[N]) noexcept : span(arr, N)
  56. {}
  57. template <std::size_t N,
  58. std::size_t E = Extent,
  59. class = typename std::enable_if<
  60. (E == dynamic_extent || N == E)
  61. && detail::is_array_convertible<std::array<value_type, N>&, element_type>::value
  62. >::type
  63. >
  64. span(std::array<value_type, N>& arr) noexcept : span(vlc::data(arr), N)
  65. {}
  66. template <std::size_t N,
  67. std::size_t E = Extent,
  68. class = typename std::enable_if<
  69. (E == dynamic_extent || N == E)
  70. && detail::is_array_convertible<const std::array<value_type, N>&, element_type>::value
  71. >::type
  72. >
  73. span(const std::array<value_type, N>& arr) noexcept : span(vlc::data(arr), N)
  74. {}
  75. template<typename Container,
  76. std::size_t E = Extent,
  77. class = typename std::enable_if<
  78. E == dynamic_extent &&
  79. !std::is_same<Container, span<element_type>>::value &&
  80. !std::is_array<Container>::value &&
  81. detail::is_array_convertible<Container&, element_type>::value
  82. >::type
  83. >
  84. span(Container& c) : span(vlc::data(c), vlc::size(c))
  85. {}
  86. template<typename Container,
  87. std::size_t E = Extent,
  88. class = typename std::enable_if<
  89. E == dynamic_extent &&
  90. !std::is_same<Container, span<element_type>>::value &&
  91. !std::is_array<Container>::value &&
  92. detail::is_array_convertible<const Container&, element_type>::value
  93. >::type
  94. >
  95. span(const Container& c) : span(vlc::data(c), vlc::size(c))
  96. {}
  97. template<typename U, std::size_t N,
  98. std::size_t E = Extent,
  99. class = typename std::enable_if<
  100. (E == dynamic_extent || N == E)
  101. && std::is_convertible<U(*)[], element_type(*)[]>::value
  102. >::type
  103. >
  104. span(const span<U, N>& other) noexcept : m_ptr(other.data()), m_size(other.size())
  105. {}
  106. span(const span& other) noexcept = default;
  107. span& operator = (const span& other) noexcept = default;
  108. pointer data() const noexcept
  109. {
  110. return m_ptr;
  111. }
  112. index_type size() const noexcept
  113. {
  114. return m_size;
  115. }
  116. index_type size_bytes() const noexcept
  117. {
  118. return size() * sizeof(element_type);
  119. }
  120. bool empty() const noexcept
  121. {
  122. return !size();
  123. }
  124. iterator begin() const noexcept
  125. {
  126. return data();
  127. }
  128. const_iterator cbegin() const noexcept
  129. {
  130. return data();
  131. }
  132. iterator end() const noexcept
  133. {
  134. return data() + size();
  135. }
  136. const_iterator cend() const noexcept
  137. {
  138. return data() + size();
  139. }
  140. reverse_iterator rbegin() const noexcept
  141. {
  142. return reverse_iterator(end());
  143. }
  144. const_reverse_iterator crbegin() const noexcept
  145. {
  146. return const_reverse_iterator(end());
  147. }
  148. reverse_iterator rend() const noexcept
  149. {
  150. return reverse_iterator(begin());
  151. }
  152. const_reverse_iterator crend() const noexcept
  153. {
  154. return const_reverse_iterator(begin());
  155. }
  156. friend iterator begin(span s) noexcept { return s.begin(); }
  157. friend iterator end(span s) noexcept { return s.end(); }
  158. reference front() const
  159. {
  160. return *begin();
  161. }
  162. reference back() const
  163. {
  164. return *(end() - 1);
  165. }
  166. reference operator[](index_type idx) const
  167. {
  168. assert(idx < size());
  169. return *(begin() + idx);
  170. }
  171. template<std::size_t Count>
  172. span<element_type, Count> first() const
  173. {
  174. assert(Count <= size());
  175. return { data(), Count };
  176. }
  177. template<std::size_t Count>
  178. span<element_type, Count> last() const
  179. {
  180. assert(Count <= size());
  181. return { data() + (size() - Count), Count };
  182. }
  183. template<std::size_t Offset, std::size_t Count = dynamic_extent,
  184. typename return_t = span<
  185. element_type,
  186. Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)
  187. >
  188. >
  189. auto subspan() const -> return_t
  190. {
  191. assert(Offset < size());
  192. assert(Count == dynamic_extent || (Offset + Count <= size()));
  193. return { data() + Offset, Count != dynamic_extent ? Count : size() - Offset };
  194. }
  195. span<element_type, dynamic_extent> first(std::size_t count) const
  196. {
  197. assert(count <= size());
  198. return { data(), count };
  199. }
  200. span<element_type, dynamic_extent> last(std::size_t count) const
  201. {
  202. assert(count <= size());
  203. return { data() + (size() - count), count };
  204. }
  205. auto subspan(std::size_t offset, std::size_t count = dynamic_extent) const
  206. -> span<element_type, dynamic_extent>
  207. {
  208. assert(offset < size());
  209. assert(count == dynamic_extent || (offset + count <= size()));
  210. return {
  211. data() + offset,
  212. count != dynamic_extent ? count : size() - offset
  213. };
  214. }
  215. private:
  216. T* m_ptr = nullptr;
  217. index_type m_size = 0;
  218. };
  219. template<typename ElementType, std::size_t Extent>
  220. span<ElementType, Extent>
  221. make_span(span<ElementType, Extent> s) noexcept
  222. {
  223. return s;
  224. }
  225. template <typename T, std::size_t N>
  226. span<T, N> make_span(T(&arr)[N]) noexcept
  227. {
  228. return { arr };
  229. }
  230. template <typename T, std::size_t N>
  231. span<T, N> make_span(std::array<T, N>& arr) noexcept
  232. {
  233. return { arr };
  234. }
  235. template <typename T, std::size_t N>
  236. span<const T, N>
  237. make_span(const std::array<T, N>& arr) noexcept
  238. {
  239. return { arr };
  240. }
  241. template <typename Container>
  242. span<typename Container::value_type> make_span(Container& cont)
  243. {
  244. return { cont };
  245. }
  246. template <typename Container>
  247. span<const typename Container::value_type>
  248. make_span(const Container& cont)
  249. {
  250. return { cont };
  251. }
  252. }