1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4
5 #pragma once
6
7 #include <array>
8 #include <type_traits>
9
10 #include "caf/byte.hpp"
11 #include "caf/detail/type_traits.hpp"
12
13 namespace caf {
14
15 /// A C++11/14 drop-in replacement for C++20's `std::span` without support for
16 /// static extents.
17 template <class T>
18 class span {
19 public:
20 // -- member types -----------------------------------------------------------
21
22 using element_type = T;
23
24 using value_type = typename std::remove_cv<T>::type;
25
26 using index_type = size_t;
27
28 using difference_type = ptrdiff_t;
29
30 using pointer = T*;
31
32 using const_pointer = const T*;
33
34 using reference = T&;
35
36 using const_reference = T&;
37
38 using iterator = pointer;
39
40 using const_iterator = const_pointer;
41
42 using reverse_iterator = std::reverse_iterator<iterator>;
43
44 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
45
46 // -- constructors, destructors, and assignment operators --------------------
47
span()48 constexpr span() noexcept : begin_(nullptr), size_(0) {
49 // nop
50 }
51
span(pointer ptr,size_t size)52 constexpr span(pointer ptr, size_t size) : begin_(ptr), size_(size) {
53 // nop
54 }
55
span(pointer first,pointer last)56 constexpr span(pointer first, pointer last)
57 : begin_(first), size_(static_cast<size_t>(last - first)) {
58 // nop
59 }
60
61 template <size_t Size>
span(element_type (& arr)[Size])62 constexpr span(element_type (&arr)[Size]) noexcept
63 : begin_(arr), size_(Size) {
64 // nop
65 }
66
67 template <class C,
68 class = std::enable_if_t<
69 detail::has_convertible_data_member<C, value_type>::value>>
span(C & xs)70 span(C& xs) noexcept : begin_(xs.data()), size_(xs.size()) {
71 // nop
72 }
73
74 template <class C,
75 class = std::enable_if_t<
76 detail::has_convertible_data_member<C, value_type>::value>>
span(const C & xs)77 span(const C& xs) noexcept : begin_(xs.data()), size_(xs.size()) {
78 // nop
79 }
80
81 constexpr span(const span&) noexcept = default;
82
83 span& operator=(const span&) noexcept = default;
84
85 // -- iterators --------------------------------------------------------------
86
begin() const87 constexpr iterator begin() const noexcept {
88 return begin_;
89 }
90
cbegin() const91 constexpr const_iterator cbegin() const noexcept {
92 return begin_;
93 }
94
end() const95 constexpr iterator end() const noexcept {
96 return begin() + size_;
97 }
98
cend() const99 constexpr const_iterator cend() const noexcept {
100 return cbegin() + size_;
101 }
102
rbegin() const103 constexpr reverse_iterator rbegin() const noexcept {
104 return reverse_iterator{end()};
105 }
106
crbegin() const107 constexpr const_reverse_iterator crbegin() const noexcept {
108 return const_reverse_iterator{end()};
109 }
110
rend() const111 constexpr reverse_iterator rend() const noexcept {
112 return reverse_iterator{begin()};
113 }
114
crend() const115 constexpr const_reverse_iterator crend() const noexcept {
116 return const_reverse_iterator{begin()};
117 }
118
119 // -- element access ---------------------------------------------------------
120
operator [](size_t index) const121 constexpr reference operator[](size_t index) const noexcept {
122 return begin_[index];
123 }
124
front() const125 constexpr reference front() const noexcept {
126 return *begin_;
127 }
128
back() const129 constexpr reference back() const noexcept {
130 return (*this)[size_ - 1];
131 }
132
133 // -- properties -------------------------------------------------------------
134
size() const135 constexpr size_t size() const noexcept {
136 return size_;
137 }
138
size_bytes() const139 constexpr size_t size_bytes() const noexcept {
140 return size_ * sizeof(element_type);
141 }
142
empty() const143 constexpr bool empty() const noexcept {
144 return size_ == 0;
145 }
146
data() const147 constexpr pointer data() const noexcept {
148 return begin_;
149 }
150
151 // -- subviews ---------------------------------------------------------------
152
subspan(size_t offset,size_t num_bytes) const153 constexpr span subspan(size_t offset, size_t num_bytes) const {
154 return {begin_ + offset, num_bytes};
155 }
156
subspan(size_t offset) const157 constexpr span subspan(size_t offset) const {
158 return {begin_ + offset, size_ - offset};
159 }
160
first(size_t num_bytes) const161 constexpr span first(size_t num_bytes) const {
162 return {begin_, num_bytes};
163 }
164
last(size_t num_bytes) const165 constexpr span last(size_t num_bytes) const {
166 return subspan(size_ - num_bytes, num_bytes);
167 }
168
169 private:
170 // -- member variables -------------------------------------------------------
171
172 /// Points to the first element in the contiguous memory block.
173 pointer begin_;
174
175 /// Stores the number of elements in the contiguous memory block.
176 size_t size_;
177 };
178
179 template <class T>
begin(const span<T> & xs)180 auto begin(const span<T>& xs) -> decltype(xs.begin()) {
181 return xs.begin();
182 }
183
184 template <class T>
cbegin(const span<T> & xs)185 auto cbegin(const span<T>& xs) -> decltype(xs.cbegin()) {
186 return xs.cbegin();
187 }
188
189 template <class T>
end(const span<T> & xs)190 auto end(const span<T>& xs) -> decltype(xs.end()) {
191 return xs.end();
192 }
193
194 template <class T>
cend(const span<T> & xs)195 auto cend(const span<T>& xs) -> decltype(xs.cend()) {
196 return xs.cend();
197 }
198
199 template <class T>
as_bytes(span<T> xs)200 span<const byte> as_bytes(span<T> xs) {
201 return {reinterpret_cast<const byte*>(xs.data()), xs.size_bytes()};
202 }
203
204 template <class T>
as_writable_bytes(span<T> xs)205 span<byte> as_writable_bytes(span<T> xs) {
206 return {reinterpret_cast<byte*>(xs.data()), xs.size_bytes()};
207 }
208
209 /// Convenience function to make using `caf::span` more convenient without the
210 /// deduction guides.
211 template <class T>
make_span(T & xs)212 auto make_span(T& xs) -> span<detail::remove_reference_t<decltype(xs[0])>> {
213 return {xs.data(), xs.size()};
214 }
215
216 /// Convenience function to make using `caf::span` more convenient without the
217 /// deduction guides.
218 template <class T, size_t N>
make_span(T (& xs)[N])219 span<T> make_span(T (&xs)[N]) {
220 return {xs, N};
221 }
222
223 /// Convenience function to make using `caf::span` more convenient without the
224 /// deduction guides.
225 template <class T>
make_span(T * first,size_t size)226 span<T> make_span(T* first, size_t size) {
227 return {first, size};
228 }
229
230 /// Convenience function to make using `caf::span` more convenient without the
231 /// deduction guides.
232 template <class T>
make_span(T * first,T * last)233 span<T> make_span(T* first, T* last) {
234 return {first, last};
235 }
236
237 } // namespace caf
238