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