| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef DDKTL_SPAN_H_ |
| #define DDKTL_SPAN_H_ |
| |
| #include <zircon/assert.h> |
| |
| #include <cstddef> |
| #include <type_traits> |
| |
| namespace ddktl { |
| |
| template <typename T> |
| class __POINTER(T) Span { |
| public: |
| using element_type = T; |
| using value_type = std::remove_cv_t<T>; |
| using index_type = size_t; |
| using difference_type = ptrdiff_t; |
| using pointer = T*; |
| using const_pointer = const T*; |
| using reference = T&; |
| using const_reference = const T&; |
| using iterator = T*; |
| using const_iterator = const T*; |
| |
| constexpr Span() : ptr_(nullptr), size_(0) {} |
| |
| template <typename U, typename = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>> |
| constexpr Span(Span<U> other) : ptr_(other.data()), size_(other.size()) {} |
| |
| constexpr Span(T* ptr, size_t size) : ptr_(ptr), size_(size) {} |
| |
| constexpr Span(T* first, T* last) : ptr_(first), size_(last - first) { |
| ZX_DEBUG_ASSERT(first <= last); |
| } |
| |
| template <size_t N> |
| constexpr Span(T (&arr)[N]) : ptr_(arr), size_(N) {} |
| |
| template <size_t N, typename U = std::remove_const_t<T>, |
| typename = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>> |
| constexpr Span(U (&arr)[N]) : ptr_(arr), size_(N) {} |
| |
| template <typename C, typename = std::enable_if_t< |
| std::is_convertible_v<typename C::value_type (*)[], T (*)[]>>> |
| constexpr Span(const C& container) : ptr_(container.data()), size_(container.size()) {} |
| |
| template <typename C, typename = std::enable_if_t< |
| std::is_convertible_v<typename C::value_type (*)[], T (*)[]>>> |
| constexpr Span(C& container) : ptr_(container.data()), size_(container.size()) {} |
| |
| constexpr pointer data() const { return ptr_; } |
| |
| constexpr size_t size() const { return size_; } |
| |
| constexpr size_t size_bytes() const { return size_ * sizeof(T); } |
| |
| constexpr bool empty() const { return size() == 0; } |
| |
| constexpr reference operator[](size_t index) const { |
| ZX_DEBUG_ASSERT(index < size_); |
| return ptr_[index]; |
| } |
| |
| constexpr reference front() const { |
| ZX_DEBUG_ASSERT(size_ != 0); |
| return ptr_[0]; |
| } |
| |
| constexpr reference back() const { |
| ZX_DEBUG_ASSERT(size_ != 0); |
| return ptr_[size_ - 1]; |
| } |
| |
| constexpr iterator begin() const { return ptr_; } |
| |
| constexpr iterator end() const { return ptr_ + size_; } |
| |
| constexpr const_iterator cbegin() const { return ptr_; } |
| |
| constexpr const_iterator cend() const { return ptr_ + size_; } |
| |
| constexpr Span<T> subspan(size_t offset) const { |
| ZX_DEBUG_ASSERT(offset <= size_); |
| return Span(ptr_ + offset, size_ - offset); |
| } |
| |
| constexpr Span<T> subspan(size_t offset, size_t length) const { |
| ZX_DEBUG_ASSERT((length <= size_) && (offset <= (size_ - length))); |
| return Span(ptr_ + offset, length); |
| } |
| |
| private: |
| T* ptr_; |
| size_t size_; |
| }; |
| |
| template <typename T> |
| Span<const std::byte> as_bytes(Span<T> s) { |
| return Span(reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()); |
| } |
| |
| template <typename T, typename = std::enable_if_t<!std::is_const_v<T>>> |
| Span<std::byte> as_writable_bytes(Span<T> s) { |
| return Span(reinterpret_cast<std::byte*>(s.data()), s.size_bytes()); |
| } |
| |
| } // namespace ddktl |
| |
| #endif // DDKTL_SPAN_H_ |
| |