🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
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.

307 lines
12 KiB

  1. #ifndef AL_SPAN_H
  2. #define AL_SPAN_H
  3. #include <array>
  4. #include <cstddef>
  5. #include <initializer_list>
  6. #include <iterator>
  7. #include <type_traits>
  8. namespace al {
  9. template<typename T>
  10. constexpr auto size(const T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size())
  11. { return cont.size(); }
  12. template<typename T, size_t N>
  13. constexpr size_t size(const T (&)[N]) noexcept
  14. { return N; }
  15. template<typename T>
  16. constexpr auto data(T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
  17. { return cont.data(); }
  18. template<typename T>
  19. constexpr auto data(const T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
  20. { return cont.data(); }
  21. template<typename T, size_t N>
  22. constexpr T* data(T (&arr)[N]) noexcept
  23. { return arr; }
  24. template<typename T>
  25. constexpr const T* data(std::initializer_list<T> list) noexcept
  26. { return list.begin(); }
  27. constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
  28. template<typename T, size_t E=dynamic_extent>
  29. class span;
  30. namespace detail_ {
  31. template<typename... Ts>
  32. struct make_void { using type = void; };
  33. template<typename... Ts>
  34. using void_t = typename make_void<Ts...>::type;
  35. template<typename T>
  36. struct is_span_ : std::false_type { };
  37. template<typename T, size_t E>
  38. struct is_span_<span<T,E>> : std::true_type { };
  39. template<typename T>
  40. using is_span = is_span_<std::remove_cv_t<T>>;
  41. template<typename T>
  42. struct is_std_array_ : std::false_type { };
  43. template<typename T, size_t N>
  44. struct is_std_array_<std::array<T,N>> : std::true_type { };
  45. template<typename T>
  46. using is_std_array = is_std_array_<std::remove_cv_t<T>>;
  47. template<typename T, typename = void>
  48. struct has_size_and_data : std::false_type { };
  49. template<typename T>
  50. struct has_size_and_data<T,
  51. void_t<decltype(al::size(std::declval<T>())), decltype(al::data(std::declval<T>()))>>
  52. : std::true_type { };
  53. } // namespace detail_
  54. #define REQUIRES(...) bool rt_=true, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
  55. #define IS_VALID_CONTAINER(C) \
  56. !detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
  57. !std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
  58. std::is_convertible<std::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
  59. template<typename T, size_t E>
  60. class span {
  61. public:
  62. using element_type = T;
  63. using value_type = std::remove_cv_t<T>;
  64. using index_type = size_t;
  65. using difference_type = ptrdiff_t;
  66. using pointer = T*;
  67. using const_pointer = const T*;
  68. using reference = T&;
  69. using const_reference = const T&;
  70. using iterator = pointer;
  71. using const_iterator = const_pointer;
  72. using reverse_iterator = std::reverse_iterator<iterator>;
  73. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  74. static constexpr size_t extent{E};
  75. template<REQUIRES(extent==0)>
  76. constexpr span() noexcept { }
  77. constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { }
  78. constexpr span(pointer first, pointer /*last*/) : mData{first} { }
  79. constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { }
  80. constexpr span(std::array<value_type,E> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
  81. template<REQUIRES(std::is_const<element_type>::value)>
  82. constexpr span(const std::array<value_type,E> &arr) noexcept
  83. : span{al::data(arr), al::size(arr)}
  84. { }
  85. template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
  86. constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
  87. template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
  88. constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
  89. template<typename U, REQUIRES(!std::is_same<element_type,U>::value
  90. && std::is_convertible<U(*)[],element_type(*)[]>::value)>
  91. constexpr span(const span<U,E> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
  92. constexpr span(const span&) noexcept = default;
  93. constexpr span& operator=(const span &rhs) noexcept = default;
  94. constexpr reference front() const { return *mData; }
  95. constexpr reference back() const { return *(mData+E-1); }
  96. constexpr reference operator[](index_type idx) const { return mData[idx]; }
  97. constexpr pointer data() const noexcept { return mData; }
  98. constexpr index_type size() const noexcept { return E; }
  99. constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
  100. constexpr bool empty() const noexcept { return E == 0; }
  101. constexpr iterator begin() const noexcept { return mData; }
  102. constexpr iterator end() const noexcept { return mData+E; }
  103. constexpr const_iterator cbegin() const noexcept { return mData; }
  104. constexpr const_iterator cend() const noexcept { return mData+E; }
  105. constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
  106. constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
  107. constexpr const_reverse_iterator crbegin() const noexcept
  108. { return const_reverse_iterator{cend()}; }
  109. constexpr const_reverse_iterator crend() const noexcept
  110. { return const_reverse_iterator{cbegin()}; }
  111. template<size_t C>
  112. constexpr span<element_type,C> first() const
  113. {
  114. static_assert(E >= C, "New size exceeds original capacity");
  115. return span<element_type,C>{mData, C};
  116. }
  117. template<size_t C>
  118. constexpr span<element_type,C> last() const
  119. {
  120. static_assert(E >= C, "New size exceeds original capacity");
  121. return span<element_type,C>{mData+(E-C), C};
  122. }
  123. template<size_t O, size_t C>
  124. constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
  125. {
  126. static_assert(E >= O, "Offset exceeds extent");
  127. static_assert(E-O >= C, "New size exceeds original capacity");
  128. return span<element_type,C>{mData+O, C};
  129. }
  130. template<size_t O, size_t C=dynamic_extent>
  131. constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,E-O>>
  132. {
  133. static_assert(E >= O, "Offset exceeds extent");
  134. return span<element_type,E-O>{mData+O, E-O};
  135. }
  136. /* NOTE: Can't declare objects of a specialized template class prior to
  137. * defining the specialization. As a result, these methods need to be
  138. * defined later.
  139. */
  140. constexpr span<element_type,dynamic_extent> first(size_t count) const;
  141. constexpr span<element_type,dynamic_extent> last(size_t count) const;
  142. constexpr span<element_type,dynamic_extent> subspan(size_t offset,
  143. size_t count=dynamic_extent) const;
  144. private:
  145. pointer mData{nullptr};
  146. };
  147. template<typename T>
  148. class span<T,dynamic_extent> {
  149. public:
  150. using element_type = T;
  151. using value_type = std::remove_cv_t<T>;
  152. using index_type = size_t;
  153. using difference_type = ptrdiff_t;
  154. using pointer = T*;
  155. using const_pointer = const T*;
  156. using reference = T&;
  157. using const_reference = const T&;
  158. using iterator = pointer;
  159. using const_iterator = const_pointer;
  160. using reverse_iterator = std::reverse_iterator<iterator>;
  161. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  162. static constexpr size_t extent{dynamic_extent};
  163. constexpr span() noexcept = default;
  164. constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { }
  165. constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
  166. template<size_t N>
  167. constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
  168. template<size_t N>
  169. constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
  170. template<size_t N, REQUIRES(std::is_const<element_type>::value)>
  171. constexpr span(const std::array<value_type,N> &arr) noexcept
  172. : span{al::data(arr), al::size(arr)}
  173. { }
  174. template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
  175. constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
  176. template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
  177. constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
  178. template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N)
  179. && std::is_convertible<U(*)[],element_type(*)[]>::value)>
  180. constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
  181. constexpr span(const span&) noexcept = default;
  182. constexpr span& operator=(const span &rhs) noexcept = default;
  183. constexpr reference front() const { return *mData; }
  184. constexpr reference back() const { return *(mDataEnd-1); }
  185. constexpr reference operator[](index_type idx) const { return mData[idx]; }
  186. constexpr pointer data() const noexcept { return mData; }
  187. constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
  188. constexpr index_type size_bytes() const noexcept
  189. { return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
  190. constexpr bool empty() const noexcept { return mData == mDataEnd; }
  191. constexpr iterator begin() const noexcept { return mData; }
  192. constexpr iterator end() const noexcept { return mDataEnd; }
  193. constexpr const_iterator cbegin() const noexcept { return mData; }
  194. constexpr const_iterator cend() const noexcept { return mDataEnd; }
  195. constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
  196. constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
  197. constexpr const_reverse_iterator crbegin() const noexcept
  198. { return const_reverse_iterator{cend()}; }
  199. constexpr const_reverse_iterator crend() const noexcept
  200. { return const_reverse_iterator{cbegin()}; }
  201. template<size_t C>
  202. constexpr span<element_type,C> first() const
  203. { return span<element_type,C>{mData, C}; }
  204. constexpr span first(size_t count) const
  205. { return (count >= size()) ? *this : span{mData, mData+count}; }
  206. template<size_t C>
  207. constexpr span<element_type,C> last() const
  208. { return span<element_type,C>{mDataEnd-C, C}; }
  209. constexpr span last(size_t count) const
  210. { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
  211. template<size_t O, size_t C>
  212. constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
  213. { return span<element_type,C>{mData+O, C}; }
  214. template<size_t O, size_t C=dynamic_extent>
  215. constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,C>>
  216. { return span<element_type,C>{mData+O, mDataEnd}; }
  217. constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
  218. {
  219. return (offset > size()) ? span{} :
  220. (count >= size()-offset) ? span{mData+offset, mDataEnd} :
  221. span{mData+offset, mData+offset+count};
  222. }
  223. private:
  224. pointer mData{nullptr};
  225. pointer mDataEnd{nullptr};
  226. };
  227. template<typename T, size_t E>
  228. constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
  229. {
  230. return (count >= size()) ? span<element_type>{mData, extent} :
  231. span<element_type>{mData, count};
  232. }
  233. template<typename T, size_t E>
  234. constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
  235. {
  236. return (count >= size()) ? span<element_type>{mData, extent} :
  237. span<element_type>{mData+extent-count, count};
  238. }
  239. template<typename T, size_t E>
  240. constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const
  241. -> span<element_type,dynamic_extent>
  242. {
  243. return (offset > size()) ? span<element_type>{} :
  244. (count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
  245. span<element_type>{mData+offset, mData+offset+count};
  246. }
  247. #undef IS_VALID_CONTAINER
  248. #undef REQUIRES
  249. } // namespace al
  250. #endif /* AL_SPAN_H */