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> class Span : public std::span<T, N> {
29public:
30 using Base = std::span<T, N>;
31 constexpr static auto D = std::dynamic_extent;
32
33 /// @name Constructors
34 ///@{
35 using Base::Base;
36 explicit(N != D) constexpr Span(std::initializer_list<T> init) noexcept
37 : Base(std::begin(init), std::ranges::distance(init)) {}
38 constexpr Span(std::span<T, N> span) noexcept
39 : Base(span) {}
40 template<Vectorlike Vec> requires(std::is_same_v<typename Vec::value_type, T>)
41 explicit(N != D) constexpr Span(Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
42 : Base(vec.data(), vec.size()) {}
43 template<Vectorlike Vec> requires(std::is_same_v<std::add_const_t<typename Vec::value_type>, std::add_const_t<T>>)
44 explicit(N != D) constexpr Span(const Vec& vec) noexcept(noexcept(vec.data()) && noexcept(vec.size()))
45 : Base(const_cast<T*>(vec.data()), vec.size()) {}
46 constexpr explicit Span(typename Base::pointer p) noexcept
47 : Base(p, N) {
48 static_assert(N != D);
49 }
50 ///@}
51
52 /// @name subspan
53 /// Wrappers for `std::span::subspan` that return a
54 /// `mim::Span`. Example: If `span` points to `0, 1, 2, 3, 4, 5, 6, 7, 8, 9`, then
55 /// * `span.subspan<2, 5>()` and `span.subspan(2, 5)` will point to `2, 3, 4, 5, 6`.
56 /// * `span.subspan<2>()` and `span.subspan(2)` will point to `2, 3, 4, 5, 6, 7, 8, 9`.
57 ///@{
58 [[nodiscard]] constexpr Span<T, D> subspan(size_t i, size_t n = D) const noexcept { return Base::subspan(i, n); }
59
60 template<size_t i, size_t n = D>
61 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> subspan() const noexcept {
62 return Base::template subspan<i, n>();
63 }
64 ///@}
65
66 /// @name rsubspan
67 /// Similar to Span::subspan but in *reverse*:
68 ///@{
69 [[nodiscard]] constexpr Span<T, D> rsubspan(size_t i, size_t n = D) const noexcept {
70 return n != D ? subspan(Base::size() - i - n, n) : subspan(0, Base::size() - i);
71 }
72
73 /// `span.rsubspan(3, 5)` removes the last 3 elements and picks 5 elements starting before those.
74 template<size_t i, size_t n = D>
75 [[nodiscard]] constexpr Span<T, n != D ? n : (N != D ? N - i : D)> rsubspan() const noexcept {
76 if constexpr (n != D)
77 return Span<T, n>(Base::data() + Base::size() - i - n);
78 else if constexpr (N != D)
79 return Span<T, N - i>(Base::data());
80 else
81 return Span<T, D>(Base::data(), Base::size() - i);
82 }
83 ///@}
84};
85
86static_assert(std::ranges::contiguous_range<Span<int>>);
87
88template<class T, size_t N = std::dynamic_extent> using View = Span<const T, N>;
89
90/// @name Deduction Guides
91///@{
92template<class I, class E> Span(I, E) -> Span<std::remove_reference_t<std::iter_reference_t<I>>>;
93template<class T, size_t N> Span(T (&)[N]) -> Span<T, N>;
94template<class T, size_t N> Span(std::array<T, N>&) -> Span<T, N>;
95template<class T, size_t N> Span(const std::array<T, N>&) -> Span<const T, N>;
99///@}
100
101template<size_t I, class T, size_t N> requires(N != std::dynamic_extent)
102constexpr decltype(auto) get(Span<T, N> span) noexcept {
103 static_assert(I < N, "index I out of bound N");
104 return span[I];
105}
106
107} // namespace mim
108
109namespace std {
110/// @name Structured Binding Support for Span
111///@{
112template<class T, size_t N> requires(N != std::dynamic_extent)
113struct tuple_size<mim::Span<T, N>> : std::integral_constant<size_t, N> {};
114
115template<size_t I, class T, size_t N> requires(N != std::dynamic_extent)
116struct tuple_element<I, mim::Span<T, N>> {
118};
119///@}
120} // namespace std
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
constexpr Span< T, D > subspan(size_t i, size_t n=D) const noexcept
Definition span.h:58
constexpr Span(typename Base::pointer p) noexcept
Definition span.h:46
constexpr Span< T, n !=D ? n :(N !=D ? N - i :D)> subspan() const noexcept
Definition span.h:61
constexpr Span< T, D > rsubspan(size_t i, size_t n=D) const noexcept
Definition span.h:69
constexpr Span(std::span< T, N > span) noexcept
Definition span.h:38
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:75
static constexpr auto D
Definition span.h:31
std::span< T, N > Base
Definition span.h:30
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:88
constexpr decltype(auto) get(Span< T, N > span) noexcept
Definition span.h:102
Definition span.h:109
typename mim::Span< T, N >::reference type
Definition span.h:117