span.h (7855B)
1 // Copyright 2017 The BoringSSL Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef OPENSSL_HEADER_SSL_SPAN_H 16 #define OPENSSL_HEADER_SSL_SPAN_H 17 18 #include <openssl/base.h> // IWYU pragma: export 19 20 #if !defined(BORINGSSL_NO_CXX) 21 22 extern "C++" { 23 24 #include <stdlib.h> 25 26 #include <algorithm> 27 #include <string_view> 28 #include <type_traits> 29 30 #if __has_include(<version>) 31 #include <version> 32 #endif 33 34 #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L 35 #include <ranges> 36 BSSL_NAMESPACE_BEGIN 37 template <typename T> 38 class Span; 39 BSSL_NAMESPACE_END 40 41 // Mark `Span` as satisfying the `view` and `borrowed_range` concepts. This 42 // should be done before the definition of `Span`, so that any inlined calls to 43 // range functionality use the correct specializations. 44 template <typename T> 45 inline constexpr bool std::ranges::enable_view<bssl::Span<T>> = true; 46 template <typename T> 47 inline constexpr bool std::ranges::enable_borrowed_range<bssl::Span<T>> = true; 48 #endif 49 50 BSSL_NAMESPACE_BEGIN 51 52 template <typename T> 53 class Span; 54 55 namespace internal { 56 template <typename T> 57 class SpanBase { 58 // Put comparison operator implementations into a base class with const T, so 59 // they can be used with any type that implicitly converts into a Span. 60 static_assert(std::is_const<T>::value, 61 "Span<T> must be derived from SpanBase<const T>"); 62 63 friend bool operator==(Span<T> lhs, Span<T> rhs) { 64 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); 65 } 66 67 friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); } 68 }; 69 70 // Heuristically test whether C is a container type that can be converted into 71 // a Span<T> by checking for data() and size() member functions. 72 template <typename C, typename T> 73 using EnableIfContainer = std::enable_if_t< 74 std::is_convertible_v<decltype(std::declval<C>().data()), T *> && 75 std::is_integral_v<decltype(std::declval<C>().size())>>; 76 77 } // namespace internal 78 79 // A Span<T> is a non-owning reference to a contiguous array of objects of type 80 // |T|. Conceptually, a Span is a simple a pointer to |T| and a count of 81 // elements accessible via that pointer. The elements referenced by the Span can 82 // be mutated if |T| is mutable. 83 // 84 // A Span can be constructed from container types implementing |data()| and 85 // |size()| methods. If |T| is constant, construction from a container type is 86 // implicit. This allows writing methods that accept data from some unspecified 87 // container type: 88 // 89 // // Foo views data referenced by v. 90 // void Foo(bssl::Span<const uint8_t> v) { ... } 91 // 92 // std::vector<uint8_t> vec; 93 // Foo(vec); 94 // 95 // For mutable Spans, conversion is explicit: 96 // 97 // // FooMutate mutates data referenced by v. 98 // void FooMutate(bssl::Span<uint8_t> v) { ... } 99 // 100 // FooMutate(bssl::Span<uint8_t>(vec)); 101 // 102 // You can also use C++17 class template argument deduction to construct Spans 103 // in order to deduce the type of the Span automatically. 104 // 105 // FooMutate(bssl::Span(vec)); 106 // 107 // Note that Spans have value type sematics. They are cheap to construct and 108 // copy, and should be passed by value whenever a method would otherwise accept 109 // a reference or pointer to a container or array. 110 template <typename T> 111 class Span : private internal::SpanBase<const T> { 112 public: 113 static const size_t npos = static_cast<size_t>(-1); 114 115 using element_type = T; 116 using value_type = std::remove_cv_t<T>; 117 using size_type = size_t; 118 using difference_type = ptrdiff_t; 119 using pointer = T *; 120 using const_pointer = const T *; 121 using reference = T &; 122 using const_reference = const T &; 123 using iterator = T *; 124 using const_iterator = const T *; 125 126 constexpr Span() : Span(nullptr, 0) {} 127 constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {} 128 129 template <size_t N> 130 constexpr Span(T (&array)[N]) : Span(array, N) {} 131 132 template <typename C, typename = internal::EnableIfContainer<C, T>, 133 typename = std::enable_if_t<std::is_const<T>::value, C>> 134 constexpr Span(const C &container) 135 : data_(container.data()), size_(container.size()) {} 136 137 template <typename C, typename = internal::EnableIfContainer<C, T>, 138 typename = std::enable_if_t<!std::is_const<T>::value, C>> 139 constexpr explicit Span(C &container) 140 : data_(container.data()), size_(container.size()) {} 141 142 constexpr T *data() const { return data_; } 143 constexpr size_t size() const { return size_; } 144 constexpr bool empty() const { return size_ == 0; } 145 146 constexpr iterator begin() const { return data_; } 147 constexpr const_iterator cbegin() const { return data_; } 148 constexpr iterator end() const { return data_ + size_; } 149 constexpr const_iterator cend() const { return end(); } 150 151 constexpr T &front() const { 152 if (size_ == 0) { 153 abort(); 154 } 155 return data_[0]; 156 } 157 constexpr T &back() const { 158 if (size_ == 0) { 159 abort(); 160 } 161 return data_[size_ - 1]; 162 } 163 164 constexpr T &operator[](size_t i) const { 165 if (i >= size_) { 166 abort(); 167 } 168 return data_[i]; 169 } 170 T &at(size_t i) const { return (*this)[i]; } 171 172 constexpr Span subspan(size_t pos = 0, size_t len = npos) const { 173 if (pos > size_) { 174 // absl::Span throws an exception here. Note std::span and Chromium 175 // base::span additionally forbid pos + len being out of range, with a 176 // special case at npos/dynamic_extent, while absl::Span::subspan clips 177 // the span. For now, we align with absl::Span in case we switch to it in 178 // the future. 179 abort(); 180 } 181 return Span(data_ + pos, std::min(size_ - pos, len)); 182 } 183 184 constexpr Span first(size_t len) const { 185 if (len > size_) { 186 abort(); 187 } 188 return Span(data_, len); 189 } 190 191 constexpr Span last(size_t len) const { 192 if (len > size_) { 193 abort(); 194 } 195 return Span(data_ + size_ - len, len); 196 } 197 198 private: 199 T *data_; 200 size_t size_; 201 }; 202 203 template <typename T> 204 const size_t Span<T>::npos; 205 206 template <typename T> 207 Span(T *, size_t) -> Span<T>; 208 template <typename T, size_t size> 209 Span(T (&array)[size]) -> Span<T>; 210 template < 211 typename C, 212 typename T = std::remove_pointer_t<decltype(std::declval<C>().data())>, 213 typename = internal::EnableIfContainer<C, T>> 214 Span(C &) -> Span<T>; 215 216 template <typename T> 217 constexpr Span<T> MakeSpan(T *ptr, size_t size) { 218 return Span<T>(ptr, size); 219 } 220 221 template <typename C> 222 constexpr auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) { 223 return MakeSpan(c.data(), c.size()); 224 } 225 226 template <typename T, size_t N> 227 constexpr Span<T> MakeSpan(T (&array)[N]) { 228 return Span<T>(array, N); 229 } 230 231 template <typename T> 232 constexpr Span<const T> MakeConstSpan(T *ptr, size_t size) { 233 return Span<const T>(ptr, size); 234 } 235 236 template <typename C> 237 constexpr auto MakeConstSpan(const C &c) 238 -> decltype(MakeConstSpan(c.data(), c.size())) { 239 return MakeConstSpan(c.data(), c.size()); 240 } 241 242 template <typename T, size_t size> 243 constexpr Span<const T> MakeConstSpan(T (&array)[size]) { 244 return array; 245 } 246 247 inline Span<const uint8_t> StringAsBytes(std::string_view s) { 248 return MakeConstSpan(reinterpret_cast<const uint8_t *>(s.data()), s.size()); 249 } 250 251 inline std::string_view BytesAsStringView(bssl::Span<const uint8_t> b) { 252 return std::string_view(reinterpret_cast<const char *>(b.data()), b.size()); 253 } 254 255 BSSL_NAMESPACE_END 256 257 } // extern C++ 258 259 #endif // !defined(BORINGSSL_NO_CXX) 260 261 #endif // OPENSSL_HEADER_SSL_SPAN_H