WPILibC++ 2025.1.1
Loading...
Searching...
No Matches
rotated_span.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <array>
8#include <cstddef>
9#include <iterator>
10#include <span>
11#include <type_traits>
12
13namespace wpi {
14
15/**
16 * This is a simple rotated span view. Indexed/iterated access provides a
17 * continuous view of the underlying span that wraps at the span size. An
18 * internal offset determines the starting location.
19 *
20 * Constructors take a "rotation" value--if positive, the offset is the same as
21 * the rotation; if negative, the offset is set relative to the end of the
22 * array.
23 *
24 * For example, given an array of 5 values, providing a rotation value of 2
25 * will result in an index of 0 accessing underlying span index 2, index 2
26 * accessing underlying span index 4, and index 4 accessing underlying span
27 * index 1.
28 *
29 * Similarly, providing a rotation value of -2 will result in index 0 accessing
30 * underlying span index 3 (5-2), index 2 accessing underlying span index 0,
31 * and index 4 accessing underlying span index 2.
32 *
33 * @tparam T element type
34 * @tparam Extent static sized extent, or std::dynamic_extent
35 */
36template <typename T, size_t Extent = std::dynamic_extent>
38 public:
39 using element_type = T;
40 using value_type = std::remove_cv_t<T>;
41 using size_type = size_t;
42 using difference_type = std::ptrdiff_t;
43 using pointer = T*;
44 using const_pointer = const T*;
47
48 // member constants
49 static constexpr size_t extent = Extent;
50
51 // constructors, copy and assignment
52
54 requires(Extent == std::dynamic_extent || Extent == 0)
55 = default;
56
57 constexpr /*implicit*/ rotated_span(std::span<T, Extent> data, // NOLINT
58 int rotation = 0)
59 : m_data{data}, m_offset{MakeOffset(data.size(), rotation)} {}
60
61 template <std::contiguous_iterator It>
62 constexpr explicit(extent != std::dynamic_extent)
64 : rotated_span{std::span<T, Extent>{first, count}, rotation} {}
65
66 template <std::contiguous_iterator It, std::sized_sentinel_for<It> End>
67 requires(!std::is_convertible_v<End, size_type>)
68 constexpr explicit(extent != std::dynamic_extent)
69 rotated_span(It first, End last,
70 int rotation = 0) noexcept(noexcept(std::span<T, Extent>{
71 first, last}))
72 : rotated_span{std::span<T, Extent>{first, last}, rotation} {}
73
74 template <size_t ArrayExtent>
75 requires(Extent == std::dynamic_extent || ArrayExtent == Extent)
76 constexpr rotated_span( // NOLINT
77 std::type_identity_t<element_type> (&arr)[ArrayExtent],
78 int rotation = 0) noexcept
79 : rotated_span{std::span<T, Extent>{arr}, rotation} {}
80
81 template <typename Tp, size_t ArrayExtent>
82 constexpr rotated_span(std::array<Tp, ArrayExtent>& arr, // NOLINT
83 int rotation = 0) noexcept
84 : rotated_span{std::span<T, Extent>{arr}, rotation} {}
85
86 template <typename Tp, size_t ArrayExtent>
87 constexpr rotated_span(const std::array<Tp, ArrayExtent>& arr, // NOLINT
88 int rotation = 0) noexcept
89 : rotated_span{std::span<T, Extent>{arr}, rotation} {}
90
91 template <typename OType, size_t OExtent>
92 requires(Extent == std::dynamic_extent || OExtent == std::dynamic_extent ||
93 Extent == OExtent)
94 constexpr explicit(extent != std::dynamic_extent &&
95 OExtent == std::dynamic_extent)
97 int rotation) noexcept
98 : m_data{other.m_data},
99 m_offset{MakeOffset(other.m_data.size(), other.m_offset + rotation)} {}
100
101 template <typename OType, size_t OExtent>
102 requires(Extent == std::dynamic_extent || OExtent == std::dynamic_extent ||
103 Extent == OExtent)
104 constexpr explicit(extent != std::dynamic_extent &&
105 OExtent == std::dynamic_extent) rotated_span( // NOLINT
106 const rotated_span<OType, OExtent>& other) noexcept
107 : m_data{other.m_data}, m_offset{other.m_offset} {}
108 constexpr rotated_span& operator=(const rotated_span&) noexcept = default;
109 constexpr rotated_span(rotated_span&&) noexcept = default;
110 constexpr rotated_span& operator=(rotated_span&&) noexcept = default;
111
112 ~rotated_span() noexcept = default;
113
114 // observers
115
116 constexpr std::span<T, Extent> data() const noexcept { return m_data; }
117
118 constexpr size_type offset() const noexcept { return m_offset; }
119
120 constexpr size_type size() const noexcept { return m_data.size(); }
121
122 constexpr size_type size_bytes() const noexcept {
123 return m_data.size_bytes();
124 }
125
126 constexpr bool empty() const noexcept { return m_data.empty(); }
127
128 // element access
129
130 [[nodiscard]]
131 constexpr reference front() const noexcept {
132 return m_data[m_offset];
133 }
134
135 [[nodiscard]]
136 constexpr reference back() const noexcept {
137 return m_data[(m_offset + m_data.size() - 1) % m_data.size()];
138 }
139
140 [[nodiscard]]
141 constexpr reference operator[](size_type idx) const noexcept {
142 return m_data[(m_offset + idx) % m_data.size()];
143 }
144
145 // iterator support
146
147 class iterator {
148 public:
149 using iterator_category = std::forward_iterator_tag;
154
155 constexpr iterator(const rotated_span* obj, size_type idx) noexcept
156 : m_obj{obj}, m_idx{idx} {}
157
158 constexpr iterator& operator++() noexcept {
159 ++m_idx;
160 return *this;
161 }
162 constexpr iterator operator++(int) noexcept {
163 iterator retval = *this;
164 ++(*this);
165 return retval;
166 }
167 constexpr bool operator==(const iterator&) const = default;
168 constexpr reference operator*() { return (*m_obj)[m_idx]; }
169
170 private:
171 const rotated_span* m_obj;
172 size_type m_idx;
173 };
174
175 using reverse_iterator = std::reverse_iterator<iterator>;
176
177 [[nodiscard]]
178 constexpr iterator begin() const noexcept {
179 return iterator(this, 0);
180 }
181
182 [[nodiscard]]
183 constexpr iterator end() const noexcept {
184 return iterator(this, size());
185 }
186
187 [[nodiscard]]
188 constexpr reverse_iterator rbegin() const noexcept {
189 return reverse_iterator(end());
190 }
191
192 [[nodiscard]]
193 constexpr reverse_iterator rend() const noexcept {
194 return reverse_iterator(begin());
195 }
196
197 // subviews
198 [[nodiscard]]
199 constexpr rotated_span rotate(int amt) const noexcept {
200 return rotated_span{*this, amt};
201 }
202
203 private:
204 std::span<T, Extent> m_data;
205 size_type m_offset;
206
207 static constexpr size_type MakeOffset(size_t size, int rotation) {
208 if (size == 0) {
209 return 0;
210 }
211 if (rotation >= 0) {
212 return rotation % size;
213 } else {
214 // The usual arithmetic conversions mean that rotation is converted to
215 // size_t, which is unsigned. Converting negative values to unsigned
216 // integer types produces large numbers with useless remainders, so
217 // instead make rotation positive before doing the modulo arithmetic.
218 return size - (-rotation % size);
219 }
220 }
221};
222
223// deduction guides
224
225template <typename Type, size_t ArrayExtent>
227
228template <typename Type, size_t ArrayExtent>
229rotated_span(std::array<Type, ArrayExtent>&) -> rotated_span<Type, ArrayExtent>;
230
231template <std::contiguous_iterator It, typename End>
234
235template <typename Type, size_t Extent>
236[[nodiscard]]
237inline rotated_span<const std::byte, Extent == std::dynamic_extent
238 ? std::dynamic_extent
239 : Extent * sizeof(Type)>
241 return {std::as_bytes(sp.data()), sp.offset() * sizeof(Type)};
242}
243
244template <typename Type, size_t Extent>
245 requires(!std::is_const_v<Type>)
246[[nodiscard]]
247inline rotated_span<std::byte, Extent == std::dynamic_extent
248 ? std::dynamic_extent
249 : Extent * sizeof(Type)>
250as_writable_bytes(rotated_span<Type, Extent> sp) noexcept {
251 return {std::as_writable_bytes(sp.data()), sp.offset() * sizeof(Type)};
252}
253
254} // namespace wpi
Definition rotated_span.h:147
constexpr reference operator*()
Definition rotated_span.h:168
rotated_span::value_type value_type
Definition rotated_span.h:150
rotated_span::pointer pointer
Definition rotated_span.h:152
rotated_span::reference reference
Definition rotated_span.h:153
constexpr bool operator==(const iterator &) const =default
std::forward_iterator_tag iterator_category
Definition rotated_span.h:149
rotated_span::difference_type difference_type
Definition rotated_span.h:151
constexpr iterator operator++(int) noexcept
Definition rotated_span.h:162
constexpr iterator(const rotated_span *obj, size_type idx) noexcept
Definition rotated_span.h:155
constexpr iterator & operator++() noexcept
Definition rotated_span.h:158
This is a simple rotated span view.
Definition rotated_span.h:37
constexpr size_type size_bytes() const noexcept
Definition rotated_span.h:122
constexpr std::span< T, Extent > data() const noexcept
Definition rotated_span.h:116
constexpr size_type count
Definition rotated_span.h:63
constexpr iterator end() const noexcept
Definition rotated_span.h:183
constexpr size_type size() const noexcept
Definition rotated_span.h:120
element_type & reference
Definition rotated_span.h:45
constexpr size_type int std::sized_sentinel_for< It > End constexpr End last
Definition rotated_span.h:69
constexpr iterator begin() const noexcept
Definition rotated_span.h:178
constexpr size_type offset() const noexcept
Definition rotated_span.h:118
constexpr reverse_iterator rend() const noexcept
Definition rotated_span.h:193
std::reverse_iterator< iterator > reverse_iterator
Definition rotated_span.h:175
constexpr reverse_iterator rbegin() const noexcept
Definition rotated_span.h:188
constexpr bool empty() const noexcept
Definition rotated_span.h:126
constexpr reference front() const noexcept
Definition rotated_span.h:131
T * pointer
Definition rotated_span.h:43
constexpr size_type int std::sized_sentinel_for< It > End constexpr End int size_t ArrayExtent constexpr rotated_span(std::array< Tp, ArrayExtent > &arr, int rotation=0) noexcept
Definition rotated_span.h:82
size_t size_type
Definition rotated_span.h:41
constexpr OExtent int rotation m_offset
Definition rotated_span.h:99
std::remove_cv_t< T > value_type
Definition rotated_span.h:40
constexpr rotated_span(const std::array< Tp, ArrayExtent > &arr, int rotation=0) noexcept
Definition rotated_span.h:87
constexpr rotated_span() noexcept=default
constexpr reference operator[](size_type idx) const noexcept
Definition rotated_span.h:141
constexpr OExtent int rotation noexcept
Definition rotated_span.h:98
T element_type
Definition rotated_span.h:39
constexpr size_type int rotation
Definition rotated_span.h:63
std::ptrdiff_t difference_type
Definition rotated_span.h:42
static constexpr size_t extent
Definition rotated_span.h:49
constexpr rotated_span rotate(int amt) const noexcept
Definition rotated_span.h:199
const T * const_pointer
Definition rotated_span.h:44
constexpr rotated_span(rotated_span &&) noexcept=default
constexpr reference back() const noexcept
Definition rotated_span.h:136
const element_type & const_reference
Definition rotated_span.h:46
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
Foonathan namespace.
Definition ntcore_cpp.h:26
rotated_span(Type(&)[ArrayExtent]) -> rotated_span< Type, ArrayExtent >
rotated_span< const std::byte, Extent==std::dynamic_extent ? std::dynamic_extent :Extent *sizeof(Type)> as_bytes(rotated_span< Type, Extent > sp) noexcept
Definition rotated_span.h:240
rotated_span< std::byte, Extent==std::dynamic_extent ? std::dynamic_extent :Extent *sizeof(Type)> as_writable_bytes(rotated_span< Type, Extent > sp) noexcept
Definition rotated_span.h:250