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