| /* | |
| * Copyright 2022 Rive | |
| */ | |
| #ifndef _RIVE_SPAN_HPP_ | |
| #define _RIVE_SPAN_HPP_ | |
| #include "rive/rive_types.hpp" | |
| #include <initializer_list> | |
| #include <type_traits> | |
| #include <iterator> | |
| /* | |
| * Span : cheap impl of std::span (which is C++20) | |
| * | |
| * Inspired by Skia's SkSpan | |
| */ | |
| namespace rive | |
| { | |
| namespace internal | |
| { | |
| template <typename T, typename = void> struct IsSpannableImpl : std::false_type | |
| {}; | |
| // A type is "spannable" if it has a data() member that returns a pointer and a | |
| // size() member that returns an integer. This is true for Span, std::span, | |
| // std::vector, etc. | |
| template <typename T> | |
| struct IsSpannableImpl< | |
| T, | |
| std::enable_if_t<std::is_pointer_v<decltype(std::declval<T>().data())> && | |
| std::is_integral_v<decltype(std::declval<T>().size())>, | |
| void>> : std::true_type | |
| {}; | |
| template <typename T> constexpr bool IsSpannable = IsSpannableImpl<T>::value; | |
| template <typename SpannableType, typename ElementType, typename = void> | |
| struct IsTypedSpannableImpl : std::false_type | |
| {}; | |
| template <typename SpannableType, typename ElementType> | |
| struct IsTypedSpannableImpl< | |
| SpannableType, | |
| ElementType, | |
| std::enable_if_t< | |
| std::is_assignable_v<ElementType*&, | |
| decltype(std::declval<SpannableType>().data())>, | |
| void>> : IsSpannableImpl<SpannableType> | |
| {}; | |
| template <typename S, typename E> | |
| constexpr bool IsTypedSpannable = IsTypedSpannableImpl<S, E>::value; | |
| template <typename S, typename = std::enable_if_t<IsSpannable<S>, void>> | |
| using SpannableElementType = | |
| std::remove_pointer_t<decltype(std::declval<S>().data())>; | |
| } // namespace internal | |
| template <typename T> class Span | |
| { | |
| T* m_Ptr; | |
| size_t m_Size; | |
| public: | |
| constexpr Span() : m_Ptr(nullptr), m_Size(0) {} | |
| constexpr Span(T* ptr, size_t size) : m_Ptr(ptr), m_Size(size) | |
| { | |
| assert(ptr <= ptr + size); | |
| } | |
| template <size_t N> constexpr Span(T (&array)[N]) : m_Ptr(array), m_Size(N) | |
| {} | |
| // Handle assignment from any types that have data and size members | |
| template < | |
| typename U, | |
| typename = | |
| typename std::enable_if_t<internal::IsTypedSpannable<U, T>, U>> | |
| constexpr Span(U& that) : Span(that.data(), that.size()) | |
| {} | |
| template <typename U, | |
| typename = typename std:: | |
| enable_if_t<internal::IsTypedSpannable<const U, T>, U>> | |
| constexpr Span(const U& that) : Span(that.data(), that.size()) | |
| {} | |
| T& operator[](size_t index) const | |
| { | |
| assert(index < m_Size); | |
| return m_Ptr[index]; | |
| } | |
| constexpr T* data() const { return m_Ptr; } | |
| constexpr size_t size() const { return m_Size; } | |
| constexpr bool empty() const { return m_Size == 0; } | |
| constexpr T* begin() const { return m_Ptr; } | |
| constexpr T* end() const { return m_Ptr + m_Size; } | |
| constexpr T& front() const { return (*this)[0]; } | |
| constexpr T& back() const { return (*this)[m_Size - 1]; } | |
| // returns byte-size of the entire span | |
| constexpr size_t size_bytes() const { return m_Size * sizeof(T); } | |
| constexpr size_t count() const { return m_Size; } | |
| Span<T> subset(size_t offset, size_t size) const | |
| { | |
| assert(offset <= m_Size); | |
| assert(size <= m_Size - offset); | |
| return {m_Ptr + offset, size}; | |
| } | |
| // Makes rive::Span std::Container compatible | |
| // https://en.cppreference.com/w/cpp/named_req/Container | |
| typedef typename std::remove_cv<T>::type value_type; | |
| typedef T& reference; | |
| typedef T const& const_reference; | |
| typedef T* iterator; | |
| typedef T const* const_iterator; | |
| typedef std::ptrdiff_t difference_type; | |
| typedef size_t size_type; | |
| bool operator!=(const Span<T>& that) const | |
| { | |
| return m_Ptr != that.m_Ptr || m_Size != that.m_Size; | |
| } | |
| bool operator==(const Span<T>& that) const | |
| { | |
| return m_Ptr == that.m_Ptr && m_Size == that.m_Size; | |
| } | |
| }; | |
| // Deduction guides so that spannable types will deduce the template type | |
| // properly. | |
| template <typename T> | |
| Span(const T&) -> Span<internal::SpannableElementType<const T>>; | |
| template <typename T> Span(T&) -> Span<internal::SpannableElementType<const T>>; | |
| // Deduction guide to make array conversions automatic | |
| template <typename T, size_t N> Span(T (&)[N]) -> Span<T>; | |
| template <typename T> Span<T> make_span(T* ptr, size_t size) | |
| { | |
| return Span<T>(ptr, size); | |
| } | |
| template <typename T, size_t N> Span<T> make_span(T (&ptr)[N]) | |
| { | |
| return Span<T>(ptr, N); | |
| } | |
| } // namespace rive | |
| #endif |