open62541pp 0.17.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
span.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // equal
4#include <cassert>
5#include <cstdint>
6#include <initializer_list>
7#include <iterator>
8#include <limits>
9#include <stdexcept> // out_of_range
10#include <string>
11#include <type_traits>
12#include <utility> // swap
13
14namespace opcua {
15
16/**
17 * View to a contiguous sequence of objects, similar to `std::span` in C++20.
18 *
19 * Spans are used to pass and return open62541 arrays without copy and to use them with the standard
20 * library algorithms. The view just holds two members: the pointer to `T` and the size, so it's
21 * lightweight and trivially copyable.
22 *
23 * @tparam T Type of the array object, use `const T` for an immutable view
24 *
25 * @see https://en.cppreference.com/w/cpp/container/span
26 */
27template <typename T>
28class Span {
29private:
30 template <typename, typename = void>
31 struct HasSize : std::false_type {};
32
33 template <typename C>
34 struct HasSize<C, std::void_t<decltype(std::size(std::declval<C>()))>> : std::true_type {};
35
36 template <typename, typename = void>
37 struct HasData : std::false_type {};
38
39 template <typename C>
40 struct HasData<C, std::void_t<decltype(std::data(std::declval<C>()))>> : std::true_type {};
41
42 template <typename C>
43 using EnableIfHasSizeAndData =
44 typename std::enable_if_t<HasSize<C>::value && HasData<C>::value>;
45
46public:
47 // clang-format off
48 using element_type = T;
49 using value_type = std::remove_cv_t<T>;
50 using size_type = size_t;
51 using difference_type = std::ptrdiff_t;
52 using pointer = T*;
53 using const_pointer = const T*;
54 using reference = T&;
55 using const_reference = const T&;
58 using reverse_iterator = std::reverse_iterator<iterator>;
59 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
60 // clang-format on
61
62 constexpr Span() noexcept = default;
63
64 constexpr Span(T* data, size_t size) noexcept
65 : size_(size),
66 data_(data) {}
67
68 /**
69 * Implicit constructor from a container like `std::array` or `std::vector`.
70 */
71 template <typename Container, typename = EnableIfHasSizeAndData<Container>>
72 constexpr Span(Container& container) noexcept // NOLINT(hicpp-explicit-conversions)
73 : Span(std::data(container), std::size(container)) {}
74
75 /**
76 * Implicit constructor from a container like `std::array` or `std::vector` (const).
77 */
78 template <typename Container, typename = EnableIfHasSizeAndData<Container>>
79 constexpr Span(const Container& container) noexcept // NOLINT(hicpp-explicit-conversions)
80 : Span(std::data(container), std::size(container)) {}
81
82 /**
83 * Implicit constructor from an initializer list.
84 *
85 * Only safe to use if `std::initializer_list` itself outlives the Span:
86 * @code
87 * void takeView(Span<const int> values);
88 * // ok
89 * takeView({1, 2, 3});
90 * // not ok
91 * Span<const int> values = {1, 2, 3};
92 * takeView(values);
93 * @endcode
94 */
95 constexpr Span(std::initializer_list<value_type> values) noexcept
96 : Span(values.begin(), values.size()) {}
97
98 constexpr void swap(Span& other) noexcept {
99 std::swap(data_, other.data_);
100 std::swap(size_, other.size_);
101 }
102
103 [[nodiscard]] constexpr size_t size() const noexcept {
104 return size_;
105 }
106
107 [[nodiscard]] constexpr bool empty() const noexcept {
108 return size() == 0;
109 }
110
111 [[nodiscard]] constexpr pointer data() const noexcept {
112 return data_;
113 }
114
115 /// Access element by index.
116 [[nodiscard]] constexpr reference operator[](size_t index) const noexcept {
117 assert(index < size());
118 return data()[index];
119 }
120
121 /// Access element by index with bounds checking.
122 /// @exception std::out_of_range If `index` >= size()
123 [[nodiscard]] constexpr reference at(size_t index) const {
124 if (index >= size()) {
125 throw std::out_of_range(
126 std::string("index (") + std::to_string(index) + ") >= size() (" +
127 std::to_string(size()) + ")"
128 );
129 }
130 return data()[index];
131 }
132
133 [[nodiscard]] constexpr reference front() const noexcept {
134 assert(!empty());
135 return *data();
136 }
137
138 [[nodiscard]] constexpr reference back() const noexcept {
139 assert(!empty());
140 return *(data() + size() - 1);
141 }
142
143 [[nodiscard]] constexpr iterator begin() const noexcept {
144 return {data()};
145 }
146
147 [[nodiscard]] constexpr iterator end() const noexcept {
148 return {data() + size()};
149 }
150
151 [[nodiscard]] constexpr const_iterator cbegin() const noexcept {
152 return {data()};
153 }
154
155 [[nodiscard]] constexpr const_iterator cend() const noexcept {
156 return {data() + size()};
157 }
158
159 [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept {
160 return reverse_iterator(end());
161 }
162
163 [[nodiscard]] constexpr reverse_iterator rend() const noexcept {
164 return reverse_iterator(begin());
165 }
166
167 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept {
169 }
170
171 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept {
173 }
174
175 /// Obtain a view over `count` elements of this Span starting at offset `offset`.
176 [[nodiscard]] constexpr Span subview(
177 size_t offset, size_t count = (std::numeric_limits<std::size_t>::max)()
178 ) const noexcept {
179 if (offset >= size()) {
180 return {};
181 }
182 if (count > size() - offset) {
183 count = size() - offset;
184 }
185 return {data() + offset, count};
186 }
187
188 /// Obtain a view over the first `count` elements of this Span.
189 [[nodiscard]] constexpr Span first(size_t count) const noexcept {
190 if (count >= size()) {
191 return *this;
192 }
193 return {data(), count};
194 }
195
196 /// Obtain a view over the last `count` elements of this Span.
197 [[nodiscard]] constexpr Span last(size_t count) const noexcept {
198 if (count >= size()) {
199 return *this;
200 }
201 return {data() + (size() - count), count};
202 }
203
204private:
205 size_t size_{0};
206 T* data_{nullptr};
207};
208
209/* -------------------------------------- Deduction guides -------------------------------------- */
210
211/// @relates Span
212template <typename Container>
214
215/// @relates Span
216template <typename Container>
218
219/* ------------------------------------------- Helper ------------------------------------------- */
220
221namespace detail {
222
223template <typename>
224struct IsSpan : std::false_type {};
225
226template <typename T>
227struct IsSpan<Span<T>> : std::true_type {};
228
229} // namespace detail
230
231/* ----------------------------------------- Comparison ----------------------------------------- */
232
233namespace detail {
234
235template <typename T, typename U>
236using EnableIfEqualityComparable = typename std::enable_if_t<
237 std::is_invocable_v<std::equal_to<>, const T&, const U&> &&
238 std::is_invocable_v<std::not_equal_to<>, const T&, const U&>>;
239
240} // namespace detail
241
242/// @relates Span
243template <typename T, typename U, typename = detail::EnableIfEqualityComparable<T, U>>
244constexpr bool operator==(Span<T> lhs, Span<U> rhs) {
245 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
246}
247
248/// @relates Span
249template <typename T, typename U, typename = detail::EnableIfEqualityComparable<T, U>>
250constexpr bool operator!=(Span<T> lhs, Span<U> rhs) {
251 return !(lhs == rhs);
252}
253
254} // namespace opcua
View to a contiguous sequence of objects, similar to std::span in C++20.
Definition span.hpp:28
constexpr const_reverse_iterator crend() const noexcept
Definition span.hpp:171
std::remove_cv_t< T > value_type
Definition span.hpp:49
T element_type
Definition span.hpp:48
T * pointer
Definition span.hpp:52
const T * const_pointer
Definition span.hpp:53
const T & const_reference
Definition span.hpp:55
constexpr Span last(size_t count) const noexcept
Obtain a view over the last count elements of this Span.
Definition span.hpp:197
constexpr reverse_iterator rend() const noexcept
Definition span.hpp:163
constexpr reference operator[](size_t index) const noexcept
Access element by index.
Definition span.hpp:116
constexpr reference at(size_t index) const
Access element by index with bounds checking.
Definition span.hpp:123
constexpr const_iterator cbegin() const noexcept
Definition span.hpp:151
constexpr iterator begin() const noexcept
Definition span.hpp:143
constexpr Span() noexcept=default
constexpr bool operator==(Span< T > lhs, Span< U > rhs)
Definition span.hpp:244
constexpr Span(std::initializer_list< value_type > values) noexcept
Implicit constructor from an initializer list.
Definition span.hpp:95
constexpr bool empty() const noexcept
Definition span.hpp:107
constexpr bool operator!=(Span< T > lhs, Span< U > rhs)
Definition span.hpp:250
constexpr void swap(Span &other) noexcept
Definition span.hpp:98
T & reference
Definition span.hpp:54
constexpr Span subview(size_t offset, size_t count=(std::numeric_limits< std::size_t >::max)()) const noexcept
Obtain a view over count elements of this Span starting at offset offset.
Definition span.hpp:176
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition span.hpp:59
pointer iterator
Definition span.hpp:56
constexpr const_reverse_iterator crbegin() const noexcept
Definition span.hpp:167
constexpr size_t size() const noexcept
Definition span.hpp:103
Span(Container &) -> Span< typename Container::value_type >
constexpr reference front() const noexcept
Definition span.hpp:133
constexpr Span(Container &container) noexcept
Implicit constructor from a container like std::array or std::vector.
Definition span.hpp:72
std::reverse_iterator< iterator > reverse_iterator
Definition span.hpp:58
Span(const Container &) -> Span< const typename Container::value_type >
constexpr reverse_iterator rbegin() const noexcept
Definition span.hpp:159
constexpr reference back() const noexcept
Definition span.hpp:138
const_pointer const_iterator
Definition span.hpp:57
std::ptrdiff_t difference_type
Definition span.hpp:51
size_t size_type
Definition span.hpp:50
constexpr iterator end() const noexcept
Definition span.hpp:147
constexpr const_iterator cend() const noexcept
Definition span.hpp:155
constexpr pointer data() const noexcept
Definition span.hpp:111
constexpr Span(const Container &container) noexcept
Implicit constructor from a container like std::array or std::vector (const).
Definition span.hpp:79
constexpr Span first(size_t count) const noexcept
Obtain a view over the first count elements of this Span.
Definition span.hpp:189