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