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