alspan.h 12 KB

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