alspan.h 11 KB

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