123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- #pragma once
- #include <util/generic/iterator.h>
- #include <util/generic/yexception.h>
- #include <algorithm>
- #include <initializer_list>
- #include <iterator>
- /**
- * `TArrayRef` works pretty much like `std::span` with dynamic extent, presenting
- * an array-like interface into a contiguous sequence of objects.
- *
- * It can be used at interface boundaries instead of `TVector` or
- * pointer-size pairs, and is actually a preferred way to pass contiguous data
- * into functions.
- *
- * Note that `TArrayRef` can be auto-constructed from any contiguous container
- * (with `size` and `data` members), and thus you don't have to change client code
- * when switching over from passing `TVector` to `TArrayRef`.
- *
- * Note that `TArrayRef` has the same const-semantics as raw pointers:
- * - `TArrayRef<T>` is a non-const reference to non-const data (like `T*`);
- * - `TArrayRef<const T>` is a non-const reference to const data (like `const T*`);
- * - `const TArrayRef<T>` is a const reference to non-const data (like `T* const`);
- * - `const TArrayRef<const T>` is a const reference to const data (like `const T* const`).
- */
- template <class T>
- class TArrayRef {
- public:
- using iterator = T*;
- using const_iterator = const T*;
- using reference = T&;
- using const_reference = const T&;
- using value_type = T;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- constexpr inline TArrayRef() noexcept
- : T_(nullptr)
- , S_(0)
- {
- }
- constexpr inline TArrayRef(T* data Y_LIFETIME_BOUND, size_t len) noexcept
- : T_(data)
- , S_(len)
- {
- }
- constexpr inline TArrayRef(T* begin Y_LIFETIME_BOUND, T* end Y_LIFETIME_BOUND) noexcept
- : T_(begin)
- , S_(NonNegativeDistance(begin, end))
- {
- }
- constexpr inline TArrayRef(std::initializer_list<T> list Y_LIFETIME_BOUND) noexcept
- : T_(list.begin())
- , S_(list.size())
- {
- }
- template <class Container>
- constexpr inline TArrayRef(Container&& container, decltype(std::declval<T*&>() = container.data(), nullptr) = nullptr) noexcept
- : T_(container.data())
- , S_(container.size())
- {
- static_assert(
- sizeof(decltype(*container.data())) == sizeof(T),
- "Attempt to create TArrayRef from a container of elements with a different size");
- }
- template <size_t N>
- constexpr inline TArrayRef(T (&array)[N] Y_LIFETIME_BOUND) noexcept
- : T_(array)
- , S_(N)
- {
- }
- template <class TT, typename = std::enable_if_t<std::is_same<std::remove_const_t<T>, std::remove_const_t<TT>>::value>>
- bool operator==(const TArrayRef<TT>& other) const {
- return (S_ == other.size()) && std::equal(begin(), end(), other.begin());
- }
- constexpr inline T* data() const noexcept {
- return T_;
- }
- constexpr inline size_t size() const noexcept {
- return S_;
- }
- constexpr size_t size_bytes() const noexcept {
- return (size() * sizeof(T));
- }
- constexpr inline bool empty() const noexcept {
- return (S_ == 0);
- }
- constexpr inline iterator begin() const noexcept {
- return T_;
- }
- constexpr inline iterator end() const noexcept {
- return (T_ + S_);
- }
- constexpr inline const_iterator cbegin() const noexcept {
- return T_;
- }
- constexpr inline const_iterator cend() const noexcept {
- return (T_ + S_);
- }
- constexpr inline reverse_iterator rbegin() const noexcept {
- return reverse_iterator(T_ + S_);
- }
- constexpr inline reverse_iterator rend() const noexcept {
- return reverse_iterator(T_);
- }
- constexpr inline const_reverse_iterator crbegin() const noexcept {
- return const_reverse_iterator(T_ + S_);
- }
- constexpr inline const_reverse_iterator crend() const noexcept {
- return const_reverse_iterator(T_);
- }
- constexpr inline reference front() const noexcept {
- Y_ASSERT(S_ > 0);
- return *T_;
- }
- inline reference back() const noexcept {
- Y_ASSERT(S_ > 0);
- return *(end() - 1);
- }
- inline reference operator[](size_t n) const noexcept {
- Y_ASSERT(n < S_);
- return *(T_ + n);
- }
- inline reference at(size_t n) const {
- if (n >= S_) {
- throw std::out_of_range("array ref range error");
- }
- return (*this)[n];
- }
- constexpr inline explicit operator bool() const noexcept {
- return (S_ > 0);
- }
- /**
- * Obtains a ref that is a view over the first `count` elements of this TArrayRef.
- *
- * The behavior is undefined if count > size().
- */
- TArrayRef first(size_t count) const {
- Y_ASSERT(count <= size());
- return TArrayRef(data(), count);
- }
- /**
- * Obtains a ref that is a view over the last `count` elements of this TArrayRef.
- *
- * The behavior is undefined if count > size().
- */
- TArrayRef last(size_t count) const {
- Y_ASSERT(count <= size());
- return TArrayRef(end() - count, end());
- }
- /**
- * Obtains a ref that is a view over the `count` elements of this TArrayRef starting at `offset`.
- *
- * The behavior is undefined in either offset or count is out of range.
- */
- TArrayRef subspan(size_t offset) const {
- Y_ASSERT(offset <= size());
- return TArrayRef(data() + offset, size() - offset);
- }
- TArrayRef subspan(size_t offset, size_t count) const {
- Y_ASSERT(offset + count <= size());
- return TArrayRef(data() + offset, count);
- }
- TArrayRef Slice(size_t offset) const {
- return subspan(offset);
- }
- TArrayRef Slice(size_t offset, size_t size) const {
- return subspan(offset, size);
- }
- /* FIXME:
- * This method is placed here for backward compatibility only and should be removed.
- * Keep in mind that it's behavior is different from Slice():
- * SubRegion() never throws. It returns empty TArrayRef in case of invalid input.
- *
- * DEPRECATED. DO NOT USE.
- */
- TArrayRef SubRegion(size_t offset, size_t size) const noexcept {
- if (size == 0 || offset >= S_) {
- return TArrayRef();
- }
- if (size > S_ - offset) {
- size = S_ - offset;
- }
- return TArrayRef(T_ + offset, size);
- }
- constexpr inline yssize_t ysize() const noexcept {
- return static_cast<yssize_t>(this->size());
- }
- private:
- T* T_;
- size_t S_;
- };
- /**
- * Obtains a view to the object representation of the elements of the TArrayRef arrayRef.
- *
- * Named as its std counterparts, std::as_bytes.
- */
- template <typename T>
- TArrayRef<const char> as_bytes(TArrayRef<T> arrayRef Y_LIFETIME_BOUND) noexcept {
- return TArrayRef<const char>(
- reinterpret_cast<const char*>(arrayRef.data()),
- arrayRef.size_bytes());
- }
- /**
- * Obtains a view to the writable object representation of the elements of the TArrayRef arrayRef.
- *
- * Named as its std counterparts, std::as_writable_bytes.
- */
- template <typename T>
- TArrayRef<char> as_writable_bytes(TArrayRef<T> arrayRef Y_LIFETIME_BOUND) noexcept {
- return TArrayRef<char>(
- reinterpret_cast<char*>(arrayRef.data()),
- arrayRef.size_bytes());
- }
- template <class Range>
- constexpr TArrayRef<const typename Range::value_type> MakeArrayRef(const Range& range) noexcept {
- return TArrayRef<const typename Range::value_type>(range);
- }
- template <class Range>
- constexpr TArrayRef<typename Range::value_type> MakeArrayRef(Range& range) noexcept {
- return TArrayRef<typename Range::value_type>(range);
- }
- template <class Range>
- constexpr TArrayRef<const typename Range::value_type> MakeConstArrayRef(const Range& range) noexcept {
- return TArrayRef<const typename Range::value_type>(range);
- }
- template <class Range>
- constexpr TArrayRef<const typename Range::value_type> MakeConstArrayRef(Range& range) noexcept {
- return TArrayRef<const typename Range::value_type>(range);
- }
- template <class T>
- constexpr TArrayRef<T> MakeArrayRef(T* data Y_LIFETIME_BOUND, size_t size) noexcept {
- return TArrayRef<T>(data, size);
- }
- template <class T>
- constexpr TArrayRef<T> MakeArrayRef(T* begin Y_LIFETIME_BOUND, T* end Y_LIFETIME_BOUND) noexcept {
- return TArrayRef<T>(begin, end);
- }
|