Coverage Report

Created: 2024-11-21 07:03

/src/boringssl/include/openssl/span.h
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2017, Google Inc.
2
 *
3
 * Permission to use, copy, modify, and/or distribute this software for any
4
 * purpose with or without fee is hereby granted, provided that the above
5
 * copyright notice and this permission notice appear in all copies.
6
 *
7
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15
#ifndef OPENSSL_HEADER_SSL_SPAN_H
16
#define OPENSSL_HEADER_SSL_SPAN_H
17
18
#include <openssl/base.h>
19
20
#if !defined(BORINGSSL_NO_CXX)
21
22
extern "C++" {
23
24
#include <stdlib.h>
25
26
#include <algorithm>
27
#include <type_traits>
28
29
#if __cplusplus >= 201703L
30
#include <string_view>
31
#endif
32
33
#if defined(__has_include)
34
#if __has_include(<version>)
35
#include <version>
36
#endif
37
#endif
38
39
#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L
40
#include <ranges>
41
BSSL_NAMESPACE_BEGIN
42
template <typename T>
43
class Span;
44
BSSL_NAMESPACE_END
45
46
// Mark `Span` as satisfying the `view` and `borrowed_range` concepts. This
47
// should be done before the definition of `Span`, so that any inlined calls to
48
// range functionality use the correct specializations.
49
template <typename T>
50
inline constexpr bool std::ranges::enable_view<bssl::Span<T>> = true;
51
template <typename T>
52
inline constexpr bool std::ranges::enable_borrowed_range<bssl::Span<T>> = true;
53
#endif
54
55
BSSL_NAMESPACE_BEGIN
56
57
template <typename T>
58
class Span;
59
60
namespace internal {
61
template <typename T>
62
class SpanBase {
63
  // Put comparison operator implementations into a base class with const T, so
64
  // they can be used with any type that implicitly converts into a Span.
65
  static_assert(std::is_const<T>::value,
66
                "Span<T> must be derived from SpanBase<const T>");
67
68
  friend bool operator==(Span<T> lhs, Span<T> rhs) {
69
    return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
70
  }
71
72
  friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); }
73
};
74
75
// Heuristically test whether C is a container type that can be converted into
76
// a Span<T> by checking for data() and size() member functions.
77
//
78
// TODO(davidben): Require C++17 support for std::is_convertible_v, etc.
79
template <typename C, typename T>
80
using EnableIfContainer = std::enable_if_t<
81
    std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
82
    std::is_integral<decltype(std::declval<C>().size())>::value>;
83
84
}  // namespace internal
85
86
// A Span<T> is a non-owning reference to a contiguous array of objects of type
87
// |T|. Conceptually, a Span is a simple a pointer to |T| and a count of
88
// elements accessible via that pointer. The elements referenced by the Span can
89
// be mutated if |T| is mutable.
90
//
91
// A Span can be constructed from container types implementing |data()| and
92
// |size()| methods. If |T| is constant, construction from a container type is
93
// implicit. This allows writing methods that accept data from some unspecified
94
// container type:
95
//
96
// // Foo views data referenced by v.
97
// void Foo(bssl::Span<const uint8_t> v) { ... }
98
//
99
// std::vector<uint8_t> vec;
100
// Foo(vec);
101
//
102
// For mutable Spans, conversion is explicit:
103
//
104
// // FooMutate mutates data referenced by v.
105
// void FooMutate(bssl::Span<uint8_t> v) { ... }
106
//
107
// FooMutate(bssl::Span<uint8_t>(vec));
108
//
109
// You can also use the |MakeSpan| and |MakeConstSpan| factory methods to
110
// construct Spans in order to deduce the type of the Span automatically.
111
//
112
// FooMutate(bssl::MakeSpan(vec));
113
//
114
// Note that Spans have value type sematics. They are cheap to construct and
115
// copy, and should be passed by value whenever a method would otherwise accept
116
// a reference or pointer to a container or array.
117
template <typename T>
118
class Span : private internal::SpanBase<const T> {
119
 public:
120
  static const size_t npos = static_cast<size_t>(-1);
121
122
  using element_type = T;
123
  using value_type = std::remove_cv_t<T>;
124
  using size_type = size_t;
125
  using difference_type = ptrdiff_t;
126
  using pointer = T *;
127
  using const_pointer = const T *;
128
  using reference = T &;
129
  using const_reference = const T &;
130
  using iterator = T *;
131
  using const_iterator = const T *;
132
133
  constexpr Span() : Span(nullptr, 0) {}
134
  constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {}
135
136
  template <size_t N>
137
  constexpr Span(T (&array)[N]) : Span(array, N) {}
138
139
  template <typename C, typename = internal::EnableIfContainer<C, T>,
140
            typename = std::enable_if_t<std::is_const<T>::value, C>>
141
  constexpr Span(const C &container)
142
      : data_(container.data()), size_(container.size()) {}
143
144
  template <typename C, typename = internal::EnableIfContainer<C, T>,
145
            typename = std::enable_if_t<!std::is_const<T>::value, C>>
146
  constexpr explicit Span(C &container)
147
      : data_(container.data()), size_(container.size()) {}
148
149
0
  constexpr T *data() const { return data_; }
150
0
  constexpr size_t size() const { return size_; }
151
  constexpr bool empty() const { return size_ == 0; }
152
153
  constexpr iterator begin() const { return data_; }
154
  constexpr const_iterator cbegin() const { return data_; }
155
  constexpr iterator end() const { return data_ + size_; }
156
  constexpr const_iterator cend() const { return end(); }
157
158
  constexpr T &front() const {
159
    if (size_ == 0) {
160
      abort();
161
    }
162
    return data_[0];
163
  }
164
  constexpr T &back() const {
165
    if (size_ == 0) {
166
      abort();
167
    }
168
    return data_[size_ - 1];
169
  }
170
171
  constexpr T &operator[](size_t i) const {
172
    if (i >= size_) {
173
      abort();
174
    }
175
    return data_[i];
176
  }
177
  T &at(size_t i) const { return (*this)[i]; }
178
179
  constexpr Span subspan(size_t pos = 0, size_t len = npos) const {
180
    if (pos > size_) {
181
      // absl::Span throws an exception here. Note std::span and Chromium
182
      // base::span additionally forbid pos + len being out of range, with a
183
      // special case at npos/dynamic_extent, while absl::Span::subspan clips
184
      // the span. For now, we align with absl::Span in case we switch to it in
185
      // the future.
186
      abort();
187
    }
188
    return Span(data_ + pos, std::min(size_ - pos, len));
189
  }
190
191
  constexpr Span first(size_t len) const {
192
    if (len > size_) {
193
      abort();
194
    }
195
    return Span(data_, len);
196
  }
197
198
  constexpr Span last(size_t len) const {
199
    if (len > size_) {
200
      abort();
201
    }
202
    return Span(data_ + size_ - len, len);
203
  }
204
205
 private:
206
  T *data_;
207
  size_t size_;
208
};
209
210
template <typename T>
211
const size_t Span<T>::npos;
212
213
#if __cplusplus >= 201703L
214
template <typename T>
215
Span(T *, size_t) -> Span<T>;
216
template <typename T, size_t size>
217
Span(T (&array)[size]) -> Span<T>;
218
template <
219
    typename C,
220
    typename T = std::remove_pointer_t<decltype(std::declval<C>().data())>,
221
    typename = internal::EnableIfContainer<C, T>>
222
Span(C &) -> Span<T>;
223
#endif
224
225
// C++17 callers can instead rely on CTAD and the deduction guides defined
226
// above.
227
template <typename T>
228
constexpr Span<T> MakeSpan(T *ptr, size_t size) {
229
  return Span<T>(ptr, size);
230
}
231
232
template <typename C>
233
constexpr auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
234
  return MakeSpan(c.data(), c.size());
235
}
236
237
template <typename T, size_t N>
238
constexpr Span<T> MakeSpan(T (&array)[N]) {
239
  return Span<T>(array, N);
240
}
241
242
template <typename T>
243
0
constexpr Span<const T> MakeConstSpan(T *ptr, size_t size) {
244
0
  return Span<const T>(ptr, size);
245
0
}
246
247
template <typename C>
248
constexpr auto MakeConstSpan(const C &c)
249
    -> decltype(MakeConstSpan(c.data(), c.size())) {
250
  return MakeConstSpan(c.data(), c.size());
251
}
252
253
template <typename T, size_t size>
254
constexpr Span<const T> MakeConstSpan(T (&array)[size]) {
255
  return array;
256
}
257
258
#if __cplusplus >= 201703L
259
0
inline Span<const uint8_t> StringAsBytes(std::string_view s) {
260
0
  return MakeConstSpan(reinterpret_cast<const uint8_t *>(s.data()), s.size());
261
0
}
262
263
0
inline std::string_view BytesAsStringView(bssl::Span<const uint8_t> b) {
264
0
  return std::string_view(reinterpret_cast<const char *>(b.data()), b.size());
265
0
}
266
#endif
267
268
BSSL_NAMESPACE_END
269
270
}  // extern C++
271
272
#endif  // !defined(BORINGSSL_NO_CXX)
273
274
#endif  // OPENSSL_HEADER_SSL_SPAN_H