util/span.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | #pragma once | ||
| 3 | |||
| 4 | #include <array> | ||
| 5 | #include <cstddef> | ||
| 6 | #include <cstring> | ||
| 7 | #include <iterator> | ||
| 8 | #include <type_traits> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #if __has_include(<version>) | ||
| 13 | #include <version> | ||
| 14 | #endif | ||
| 15 | #ifdef __cpp_lib_ranges | ||
| 16 | #include <ranges> | ||
| 17 | #endif | ||
| 18 | #ifdef __cpp_lib_span | ||
| 19 | #include <span> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | namespace chrono::batch_render { | ||
| 23 | |||
| 24 | template <class T> class Span { | ||
| 25 | template <class Container> | ||
| 26 | using Element = std::remove_pointer_t<decltype(std::data(std::declval<Container&>()))>; | ||
| 27 | |||
| 28 | template <class Container> | ||
| 29 | using FromContainer = std::enable_if_t< | ||
| 30 | !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Container>>, Span> && | ||
| 31 | (std::is_lvalue_reference_v<Container> || std::is_const_v<T>) && | ||
| 32 | std::is_convertible_v<Element<Container> (*)[], T (*)[]> && | ||
| 33 | std::is_convertible_v<decltype(std::size(std::declval<Container&>())), size_t>>; | ||
| 34 | |||
| 35 | public: | ||
| 36 | using element_type = T; | ||
| 37 | using value_type = std::remove_cv_t<T>; | ||
| 38 | using size_type = size_t; | ||
| 39 | using difference_type = ptrdiff_t; | ||
| 40 | using pointer = T*; | ||
| 41 | using const_pointer = const T*; | ||
| 42 | using reference = T&; | ||
| 43 | using const_reference = const T&; | ||
| 44 | using iterator = T*; | ||
| 45 | |||
| 46 | 9 | constexpr Span() noexcept = default; | |
| 47 | |||
| 48 | 274536 | constexpr Span(T* data, size_t size) noexcept : m_data(data), m_size(size) {} | |
| 49 | |||
| 50 | 1 | constexpr Span(T* first, T* last) noexcept | |
| 51 | 1 | : m_data(first), m_size(static_cast<size_t>(last - first)) {} | |
| 52 | |||
| 53 | 18 | template <size_t N> constexpr Span(T (&array)[N]) noexcept : m_data(array), m_size(N) {} | |
| 54 | |||
| 55 | template <class Container, class = FromContainer<Container>> | ||
| 56 | 724785 | constexpr Span(Container&& container) noexcept(noexcept(std::data(container))) | |
| 57 | 724772 | : m_data(std::data(container)), m_size(std::size(container)) {} | |
| 58 | |||
| 59 | template <class U, class = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>> | ||
| 60 | 1 | constexpr Span(Span<U> other) noexcept : m_data(other.data()), m_size(other.size()) {} | |
| 61 | |||
| 62 | 374230 | constexpr T* data() const noexcept { | |
| 63 | 362151 | return m_data; | |
| 64 | } | ||
| 65 | |||
| 66 | 822480 | constexpr size_t size() const noexcept { | |
| 67 | 814697 | return m_size; | |
| 68 | } | ||
| 69 | |||
| 70 | 16389 | constexpr size_t size_bytes() const noexcept { | |
| 71 | 16288 | return m_size * sizeof(T); | |
| 72 | } | ||
| 73 | |||
| 74 | 465820 | [[nodiscard]] constexpr bool empty() const noexcept { | |
| 75 | 465817 | return m_size == 0; | |
| 76 | } | ||
| 77 | |||
| 78 | 1681 | constexpr T* begin() const noexcept { | |
| 79 | 1646 | return m_data; | |
| 80 | } | ||
| 81 | |||
| 82 | 32597 | constexpr T* end() const noexcept { | |
| 83 | 32594 | return m_data + m_size; | |
| 84 | } | ||
| 85 | |||
| 86 | 4604405 | constexpr T& operator[](size_t index) const noexcept { | |
| 87 | 5465426 | return m_data[index]; | |
| 88 | } | ||
| 89 | |||
| 90 | constexpr T& front() const noexcept { | ||
| 91 | return m_data[0]; | ||
| 92 | } | ||
| 93 | |||
| 94 | 139389 | constexpr T& back() const noexcept { | |
| 95 | 138207 | return m_data[m_size - 1]; | |
| 96 | } | ||
| 97 | |||
| 98 | 3 | constexpr Span first(size_t count) const noexcept { | |
| 99 | 3 | return {m_data, count}; | |
| 100 | } | ||
| 101 | |||
| 102 | 1 | constexpr Span last(size_t count) const noexcept { | |
| 103 | 1 | return {m_data + m_size - count, count}; | |
| 104 | } | ||
| 105 | |||
| 106 | 649316 | constexpr Span subspan(size_t offset, size_t count = size_t(-1)) const noexcept { | |
| 107 | 648591 | return {m_data + offset, count == size_t(-1) ? m_size - offset : count}; | |
| 108 | } | ||
| 109 | |||
| 110 | private: | ||
| 111 | T* m_data = nullptr; | ||
| 112 | size_t m_size = 0; | ||
| 113 | }; | ||
| 114 | |||
| 115 | template <class T, size_t N> Span(T (&)[N]) -> Span<T>; | ||
| 116 | template <class T, size_t N> Span(std::array<T, N>&) -> Span<T>; | ||
| 117 | template <class T, size_t N> Span(const std::array<T, N>&) -> Span<const T>; | ||
| 118 | template <class Container> | ||
| 119 | Span(Container&) -> Span<std::remove_pointer_t<decltype(std::data(std::declval<Container&>()))>>; | ||
| 120 | |||
| 121 | 16300 | template <class T> Span<const std::byte> AsBytes(Span<T> span) noexcept { | |
| 122 | 16300 | return {reinterpret_cast<const std::byte*>(span.data()), span.size_bytes()}; | |
| 123 | } | ||
| 124 | |||
| 125 | 20783 | template <class T> std::vector<T> Items(Span<const std::byte> bytes) { | |
| 126 | 20783 | std::vector<T> items(bytes.size() / sizeof(T)); | |
| 127 | 20783 | if (!items.empty()) { | |
| 128 | 16452 | std::memcpy(items.data(), bytes.data(), items.size() * sizeof(T)); | |
| 129 | } | ||
| 130 | 20783 | return items; | |
| 131 | } | ||
| 132 | |||
| 133 | } | ||
| 134 | |||
| 135 | #ifdef __cpp_lib_ranges | ||
| 136 | template <class T> | ||
| 137 | inline constexpr bool std::ranges::enable_borrowed_range<chrono::batch_render::Span<T>> = true; | ||
| 138 | #endif | ||
| 139 |