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