MimIR 0.1
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 /// @name Constructors
35 ///@{
36 using Base::Base;
37 explicit(N != D) constexpr Span(std::initializer_list<T> init) noexcept
38 : Base(std::begin(init), std::ranges::distance(init)) {}
39 constexpr Span(std::span<T, N> span) noexcept
40 : Base(span) {}
41 template<Vectorlike Vec>
42 requires(std::is_same_v<typename Vec::value_type, T>)
43 explicit(N != D) constexpr Span(Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
44 : Base(vec.data(), vec.size()) {}
45 template<Vectorlike Vec>
46 requires(std::is_same_v<std::add_const_t<typename Vec::value_type>, std::add_const_t<T>>)
47 explicit(N != D) constexpr Span(const Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
48 : Base(const_cast<T*>(vec.data()), vec.size()) {}
49 constexpr explicit Span(typename Base::pointer p) noexcept
50 : Base(p, N) {
51 static_assert(N != D);
52 }
53 ///@}
54
55 /// @name subspan
56 /// Wrappers for `std::span::subspan` that return a
57 /// `mim::Span`. Example: If `span` points to `0, 1, 2, 3, 4, 5, 6, 7, 8, 9`, then
58 /// * `span.subspan<2, 5>()` and `span.subspan(2, 5)` will point to `2, 3, 4, 5, 6`.
59 /// * `span.subspan<2>()` and `span.subspan(2)` will point to `2, 3, 4, 5, 6, 7, 8, 9`.
60 ///@{
61 [[nodiscard]] constexpr Span<T, D> subspan(size_t i, size_t n = D) const noexcept { return Base::subspan(i, n); }
62
63 template<size_t i, size_t n = D>
64 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> subspan() const noexcept {
65 return Base::template subspan<i, n>();
66 }
67
68 /// Get first `n` elements while keeping track of size statically - useful for structured binding!
69 template<size_t n>
70 [[nodiscard]] constexpr Span<T, n> span() const noexcept {
71 return Base::template subspan<0, n>();
72 }
73 ///@}
74
75 /// @name rsubspan
76 /// Similar to Span::subspan but in *reverse*:
77 ///@{
78 [[nodiscard]] constexpr Span<T, D> rsubspan(size_t i, size_t n = D) const noexcept {
79 return n != D ? subspan(Base::size() - i - n, n) : subspan(0, Base::size() - i);
80 }
81
82 /// `span.rsubspan(3, 5)` removes the last 3 elements and picks 5 elements starting before those.
83 template<size_t i, size_t n = D>
84 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> rsubspan() const noexcept {
85 if constexpr (n != D)
86 return Span<T, n>(Base::data() + Base::size() - i - n);
87 else if constexpr (N != D)
88 return Span<T, N - i>(Base::data());
89 else
90 return Span<T, D>(Base::data(), Base::size() - i);
91 }
92 ///@}
93};
94
95static_assert(std::ranges::contiguous_range<Span<int>>);
96
97template<class T, size_t N = std::dynamic_extent>
99
100/// @name Deduction Guides
101///@{
102// clang-format off
104template<class T, size_t N> Span(T (&)[N]) -> Span< T, N>;
105template<class T, size_t N> Span( std::array<T, N>&) -> Span< T, N>;
106template<class T, size_t N> Span(const std::array<T, N>&) -> Span<const T, N>;
110// clang-format on
111///@}
112
113template<size_t I, class T, size_t N>
114requires(N != std::dynamic_extent)
115constexpr decltype(auto) get(Span<T, N> span) noexcept {
116 static_assert(I < N, "index I out of bound N");
117 return span[I];
118}
119
120} // namespace mim
121
122namespace std {
123/// @name Structured Binding Support for Span
124///@{
125template<class T, size_t N>
126requires(N != std::dynamic_extent)
127struct tuple_size<mim::Span<T, N>> : std::integral_constant<size_t, N> {};
128
129template<size_t I, class T, size_t N>
130requires(N != std::dynamic_extent)
131struct tuple_element<I, mim::Span<T, N>> {
133};
134///@}
135} // 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:61
constexpr Span< T, n > span() const noexcept
Definition span.h:70
constexpr Span(typename Base::pointer p) noexcept
Definition span.h:49
constexpr Span< T, n !=D ? n :(N !=D ? N - i :D)> subspan() const noexcept
Definition span.h:64
constexpr Span< T, D > rsubspan(size_t i, size_t n=D) const noexcept
Definition span.h:78
constexpr Span(std::span< T, N > span) noexcept
Definition span.h:39
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:84
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:98
constexpr decltype(auto) get(Span< T, N > span) noexcept
Definition span.h:115
Definition span.h:122
typename mim::Span< T, N >::reference type
Definition span.h:132