MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
span.h
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
5namespace mim {
6
7/// Something which behaves like `std::vector` or `std::array`.
8template<class Vec>
9concept Vectorlike = requires(Vec vec) {
10 typename Vec::value_type;
11 vec.size();
12 vec.data();
13};
14
15/// This is a thin wrapper for [`std::span<T, N>`](https://en.cppreference.com/w/cpp/container/span)
16/// with the following additional features:
17/// * Constructor with `std::initializer_list` (C++26 will get this ...)
18/// * Constructor for any compatible Vectorlike argument
19/// * rsubspan (reverse subspan)
20/// * structured binding, if `N != std::dynamic_extent:`
21/// ```
22/// void f(Span<int, 3> span) {
23/// auto& [a, b, c] = span;
24/// b = 23;
25/// // ...
26/// }
27/// ```
28template<class T, size_t N = std::dynamic_extent>
29class Span : public std::span<T, N> {
30public:
31 using Base = std::span<T, N>;
32 constexpr static auto D = std::dynamic_extent;
33
34 using Base::data;
35 using Base::empty;
36 using Base::size;
37
38 /// @name Constructors
39 ///@{
40 using Base::Base;
41 explicit(N != D) constexpr Span(std::initializer_list<T> init) noexcept
42 : Base(std::begin(init), std::ranges::distance(init)) {}
43 constexpr Span(std::span<T, N> span) noexcept
44 : Base(span) {}
45 template<Vectorlike Vec>
46 requires(std::is_same_v<typename Vec::value_type, T>)
47 explicit(N != D) constexpr Span(Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
48 : Base(vec.data(), vec.size()) {}
49 template<Vectorlike Vec>
50 requires(std::is_same_v<std::add_const_t<typename Vec::value_type>, std::add_const_t<T>>)
51 explicit(N != D) constexpr Span(const Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
52 : Base(const_cast<T*>(vec.data()), vec.size()) {}
53 constexpr explicit Span(typename Base::pointer p) noexcept
54 : Base(p, N) {
55 static_assert(N != D);
56 }
57 ///@}
58
59 /// @name subspan
60 /// Wrappers for `std::span::subspan` that return a
61 /// `mim::Span`. Example: If `span` points to `0, 1, 2, 3, 4, 5, 6, 7, 8, 9`, then
62 /// * `span.subspan<2, 5>()` and `span.subspan(2, 5)` will point to `2, 3, 4, 5, 6`.
63 /// * `span.subspan<2>()` and `span.subspan(2)` will point to `2, 3, 4, 5, 6, 7, 8, 9`.
64 ///@{
65 [[nodiscard]] constexpr Span<T, D> subspan(size_t i, size_t n = D) const noexcept { return Base::subspan(i, n); }
66
67 template<size_t i, size_t n = D>
68 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> subspan() const noexcept {
69 return Base::template subspan<i, n>();
70 }
71
72 /// Get first `n` elements while keeping track of size statically - useful for structured binding!
73 template<size_t n>
74 [[nodiscard]] constexpr Span<T, n> span() const noexcept {
75 return Base::template subspan<0, n>();
76 }
77 ///@}
78
79 /// @name rsubspan
80 /// Similar to Span::subspan but in *reverse*:
81 ///@{
82 [[nodiscard]] constexpr Span<T, D> rsubspan(size_t i, size_t n = D) const noexcept {
83 return n != D ? subspan(size() - i - n, n) : subspan(0, size() - i);
84 }
85
86 /// `span.rsubspan(3, 5)` removes the last 3 elements and picks 5 elements starting before those.
87 template<size_t i, size_t n = D>
88 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> rsubspan() const noexcept {
89 if constexpr (n != D)
90 return Span<T, n>(data() + size() - i - n);
91 else if constexpr (N != D)
92 return Span<T, N - i>(data());
93 else
94 return Span<T, D>(data(), size() - i);
95 }
96 ///@}
97};
98
99static_assert(std::ranges::contiguous_range<Span<int>>);
100
101template<class T, size_t N = std::dynamic_extent>
103
104/// @name Deduction Guides
105///@{
106// clang-format off
108template<class T, size_t N> Span(T (&)[N]) -> Span< T, N>;
109template<class T, size_t N> Span( std::array<T, N>&) -> Span< T, N>;
110template<class T, size_t N> Span(const std::array<T, N>&) -> Span<const T, N>;
114// clang-format on
115///@}
116
117template<size_t I, class T, size_t N>
118requires(N != std::dynamic_extent)
119constexpr decltype(auto) get(Span<T, N> span) noexcept {
120 static_assert(I < N, "index I out of bound N");
121 return span[I];
122}
123
124} // namespace mim
125
126namespace std {
127/// @name Structured Binding Support for Span
128///@{
129template<class T, size_t N>
130requires(N != std::dynamic_extent)
131struct tuple_size<mim::Span<T, N>> : std::integral_constant<size_t, N> {};
132
133template<size_t I, class T, size_t N>
134requires(N != std::dynamic_extent)
135struct tuple_element<I, mim::Span<T, N>> {
137};
138///@}
139} // namespace std
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:29
constexpr Span< T, D > subspan(size_t i, size_t n=D) const noexcept
Definition span.h:65
constexpr Span< T, n > span() const noexcept
Definition span.h:74
constexpr Span(typename Base::pointer p) noexcept
Definition span.h:53
constexpr Span< T, n !=D ? n :(N !=D ? N - i :D)> subspan() const noexcept
Definition span.h:68
constexpr Span< T, D > rsubspan(size_t i, size_t n=D) const noexcept
Definition span.h:82
constexpr Span(std::span< T, N > span) noexcept
Definition span.h:43
constexpr Span< T, n !=D ? n :(N !=D ? N - i :D)> rsubspan() const noexcept
span.rsubspan(3, 5) removes the last 3 elements and picks 5 elements starting before those.
Definition span.h:88
static constexpr auto D
Definition span.h:32
std::span< T, N > Base
Definition span.h:31
Something which behaves like std::vector or std::array.
Definition span.h:9
Definition ast.h:14
Span(I, E) -> Span< std::remove_reference_t< std::iter_reference_t< I > > >
Span< const T, N > View
Definition span.h:102
constexpr decltype(auto) get(Span< T, N > span) noexcept
Definition span.h:119
Definition span.h:126
typename mim::Span< T, N >::reference type
Definition span.h:136