array_ref.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #pragma once
  2. #include <util/generic/iterator.h>
  3. #include <util/generic/yexception.h>
  4. #include <algorithm>
  5. #include <initializer_list>
  6. #include <iterator>
  7. /**
  8. * `TArrayRef` works pretty much like `std::span` with dynamic extent, presenting
  9. * an array-like interface into a contiguous sequence of objects.
  10. *
  11. * It can be used at interface boundaries instead of `TVector` or
  12. * pointer-size pairs, and is actually a preferred way to pass contiguous data
  13. * into functions.
  14. *
  15. * Note that `TArrayRef` can be auto-constructed from any contiguous container
  16. * (with `size` and `data` members), and thus you don't have to change client code
  17. * when switching over from passing `TVector` to `TArrayRef`.
  18. *
  19. * Note that `TArrayRef` has the same const-semantics as raw pointers:
  20. * - `TArrayRef<T>` is a non-const reference to non-const data (like `T*`);
  21. * - `TArrayRef<const T>` is a non-const reference to const data (like `const T*`);
  22. * - `const TArrayRef<T>` is a const reference to non-const data (like `T* const`);
  23. * - `const TArrayRef<const T>` is a const reference to const data (like `const T* const`).
  24. */
  25. template <class T>
  26. class TArrayRef {
  27. public:
  28. using iterator = T*;
  29. using const_iterator = const T*;
  30. using reference = T&;
  31. using const_reference = const T&;
  32. using value_type = T;
  33. using reverse_iterator = std::reverse_iterator<iterator>;
  34. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  35. constexpr inline TArrayRef() noexcept
  36. : T_(nullptr)
  37. , S_(0)
  38. {
  39. }
  40. constexpr inline TArrayRef(T* data Y_LIFETIME_BOUND, size_t len) noexcept
  41. : T_(data)
  42. , S_(len)
  43. {
  44. }
  45. constexpr inline TArrayRef(T* begin Y_LIFETIME_BOUND, T* end Y_LIFETIME_BOUND) noexcept
  46. : T_(begin)
  47. , S_(NonNegativeDistance(begin, end))
  48. {
  49. }
  50. constexpr inline TArrayRef(std::initializer_list<T> list Y_LIFETIME_BOUND) noexcept
  51. : T_(list.begin())
  52. , S_(list.size())
  53. {
  54. }
  55. template <class Container>
  56. constexpr inline TArrayRef(Container&& container, decltype(std::declval<T*&>() = container.data(), nullptr) = nullptr) noexcept
  57. : T_(container.data())
  58. , S_(container.size())
  59. {
  60. static_assert(
  61. sizeof(decltype(*container.data())) == sizeof(T),
  62. "Attempt to create TArrayRef from a container of elements with a different size");
  63. }
  64. template <size_t N>
  65. constexpr inline TArrayRef(T (&array)[N] Y_LIFETIME_BOUND) noexcept
  66. : T_(array)
  67. , S_(N)
  68. {
  69. }
  70. template <class TT, typename = std::enable_if_t<std::is_same<std::remove_const_t<T>, std::remove_const_t<TT>>::value>>
  71. bool operator==(const TArrayRef<TT>& other) const {
  72. return (S_ == other.size()) && std::equal(begin(), end(), other.begin());
  73. }
  74. constexpr inline T* data() const noexcept {
  75. return T_;
  76. }
  77. constexpr inline size_t size() const noexcept {
  78. return S_;
  79. }
  80. constexpr size_t size_bytes() const noexcept {
  81. return (size() * sizeof(T));
  82. }
  83. constexpr inline bool empty() const noexcept {
  84. return (S_ == 0);
  85. }
  86. constexpr inline iterator begin() const noexcept {
  87. return T_;
  88. }
  89. constexpr inline iterator end() const noexcept {
  90. return (T_ + S_);
  91. }
  92. constexpr inline const_iterator cbegin() const noexcept {
  93. return T_;
  94. }
  95. constexpr inline const_iterator cend() const noexcept {
  96. return (T_ + S_);
  97. }
  98. constexpr inline reverse_iterator rbegin() const noexcept {
  99. return reverse_iterator(T_ + S_);
  100. }
  101. constexpr inline reverse_iterator rend() const noexcept {
  102. return reverse_iterator(T_);
  103. }
  104. constexpr inline const_reverse_iterator crbegin() const noexcept {
  105. return const_reverse_iterator(T_ + S_);
  106. }
  107. constexpr inline const_reverse_iterator crend() const noexcept {
  108. return const_reverse_iterator(T_);
  109. }
  110. constexpr inline reference front() const noexcept {
  111. Y_ASSERT(S_ > 0);
  112. return *T_;
  113. }
  114. inline reference back() const noexcept {
  115. Y_ASSERT(S_ > 0);
  116. return *(end() - 1);
  117. }
  118. inline reference operator[](size_t n) const noexcept {
  119. Y_ASSERT(n < S_);
  120. return *(T_ + n);
  121. }
  122. inline reference at(size_t n) const {
  123. if (n >= S_) {
  124. throw std::out_of_range("array ref range error");
  125. }
  126. return (*this)[n];
  127. }
  128. constexpr inline explicit operator bool() const noexcept {
  129. return (S_ > 0);
  130. }
  131. /**
  132. * Obtains a ref that is a view over the first `count` elements of this TArrayRef.
  133. *
  134. * The behavior is undefined if count > size().
  135. */
  136. TArrayRef first(size_t count) const {
  137. Y_ASSERT(count <= size());
  138. return TArrayRef(data(), count);
  139. }
  140. /**
  141. * Obtains a ref that is a view over the last `count` elements of this TArrayRef.
  142. *
  143. * The behavior is undefined if count > size().
  144. */
  145. TArrayRef last(size_t count) const {
  146. Y_ASSERT(count <= size());
  147. return TArrayRef(end() - count, end());
  148. }
  149. /**
  150. * Obtains a ref that is a view over the `count` elements of this TArrayRef starting at `offset`.
  151. *
  152. * The behavior is undefined in either offset or count is out of range.
  153. */
  154. TArrayRef subspan(size_t offset) const {
  155. Y_ASSERT(offset <= size());
  156. return TArrayRef(data() + offset, size() - offset);
  157. }
  158. TArrayRef subspan(size_t offset, size_t count) const {
  159. Y_ASSERT(offset + count <= size());
  160. return TArrayRef(data() + offset, count);
  161. }
  162. TArrayRef Slice(size_t offset) const {
  163. return subspan(offset);
  164. }
  165. TArrayRef Slice(size_t offset, size_t size) const {
  166. return subspan(offset, size);
  167. }
  168. /* FIXME:
  169. * This method is placed here for backward compatibility only and should be removed.
  170. * Keep in mind that it's behavior is different from Slice():
  171. * SubRegion() never throws. It returns empty TArrayRef in case of invalid input.
  172. *
  173. * DEPRECATED. DO NOT USE.
  174. */
  175. TArrayRef SubRegion(size_t offset, size_t size) const noexcept {
  176. if (size == 0 || offset >= S_) {
  177. return TArrayRef();
  178. }
  179. if (size > S_ - offset) {
  180. size = S_ - offset;
  181. }
  182. return TArrayRef(T_ + offset, size);
  183. }
  184. constexpr inline yssize_t ysize() const noexcept {
  185. return static_cast<yssize_t>(this->size());
  186. }
  187. private:
  188. T* T_;
  189. size_t S_;
  190. };
  191. /**
  192. * Obtains a view to the object representation of the elements of the TArrayRef arrayRef.
  193. *
  194. * Named as its std counterparts, std::as_bytes.
  195. */
  196. template <typename T>
  197. TArrayRef<const char> as_bytes(TArrayRef<T> arrayRef Y_LIFETIME_BOUND) noexcept {
  198. return TArrayRef<const char>(
  199. reinterpret_cast<const char*>(arrayRef.data()),
  200. arrayRef.size_bytes());
  201. }
  202. /**
  203. * Obtains a view to the writable object representation of the elements of the TArrayRef arrayRef.
  204. *
  205. * Named as its std counterparts, std::as_writable_bytes.
  206. */
  207. template <typename T>
  208. TArrayRef<char> as_writable_bytes(TArrayRef<T> arrayRef Y_LIFETIME_BOUND) noexcept {
  209. return TArrayRef<char>(
  210. reinterpret_cast<char*>(arrayRef.data()),
  211. arrayRef.size_bytes());
  212. }
  213. template <class Range>
  214. constexpr TArrayRef<const typename Range::value_type> MakeArrayRef(const Range& range) noexcept {
  215. return TArrayRef<const typename Range::value_type>(range);
  216. }
  217. template <class Range>
  218. constexpr TArrayRef<typename Range::value_type> MakeArrayRef(Range& range) noexcept {
  219. return TArrayRef<typename Range::value_type>(range);
  220. }
  221. template <class Range>
  222. constexpr TArrayRef<const typename Range::value_type> MakeConstArrayRef(const Range& range) noexcept {
  223. return TArrayRef<const typename Range::value_type>(range);
  224. }
  225. template <class Range>
  226. constexpr TArrayRef<const typename Range::value_type> MakeConstArrayRef(Range& range) noexcept {
  227. return TArrayRef<const typename Range::value_type>(range);
  228. }
  229. template <class T>
  230. constexpr TArrayRef<T> MakeArrayRef(T* data Y_LIFETIME_BOUND, size_t size) noexcept {
  231. return TArrayRef<T>(data, size);
  232. }
  233. template <class T>
  234. constexpr TArrayRef<T> MakeArrayRef(T* begin Y_LIFETIME_BOUND, T* end Y_LIFETIME_BOUND) noexcept {
  235. return TArrayRef<T>(begin, end);
  236. }