1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
/* Copyright (c) 2017, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_SSL_SPAN_H
#define OPENSSL_HEADER_SSL_SPAN_H
#include "CCryptoBoringSSL_base.h"
#if !defined(BORINGSSL_NO_CXX)
extern "C++" {
#include <stdlib.h>
#include <algorithm>
#include <type_traits>
BSSL_NAMESPACE_BEGIN
template <typename T>
class Span;
namespace internal {
template <typename T>
class SpanBase {
// Put comparison operator implementations into a base class with const T, so
// they can be used with any type that implicitly converts into a Span.
static_assert(std::is_const<T>::value,
"Span<T> must be derived from SpanBase<const T>");
friend bool operator==(Span<T> lhs, Span<T> rhs) {
// MSVC issues warning C4996 because std::equal is unsafe. The pragma to
// suppress the warning mysteriously has no effect, hence this
// implementation. See
// https://msdn.microsoft.com/en-us/library/aa985974.aspx.
if (lhs.size() != rhs.size()) {
return false;
}
for (T *l = lhs.begin(), *r = rhs.begin(); l != lhs.end() && r != rhs.end();
++l, ++r) {
if (*l != *r) {
return false;
}
}
return true;
}
friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); }
};
} // namespace internal
// A Span<T> is a non-owning reference to a contiguous array of objects of type
// |T|. Conceptually, a Span is a simple a pointer to |T| and a count of
// elements accessible via that pointer. The elements referenced by the Span can
// be mutated if |T| is mutable.
//
// A Span can be constructed from container types implementing |data()| and
// |size()| methods. If |T| is constant, construction from a container type is
// implicit. This allows writing methods that accept data from some unspecified
// container type:
//
// // Foo views data referenced by v.
// void Foo(bssl::Span<const uint8_t> v) { ... }
//
// std::vector<uint8_t> vec;
// Foo(vec);
//
// For mutable Spans, conversion is explicit:
//
// // FooMutate mutates data referenced by v.
// void FooMutate(bssl::Span<uint8_t> v) { ... }
//
// FooMutate(bssl::Span<uint8_t>(vec));
//
// You can also use the |MakeSpan| and |MakeConstSpan| factory methods to
// construct Spans in order to deduce the type of the Span automatically.
//
// FooMutate(bssl::MakeSpan(vec));
//
// Note that Spans have value type sematics. They are cheap to construct and
// copy, and should be passed by value whenever a method would otherwise accept
// a reference or pointer to a container or array.
template <typename T>
class Span : private internal::SpanBase<const T> {
private:
static const size_t npos = static_cast<size_t>(-1);
// Heuristically test whether C is a container type that can be converted into
// a Span by checking for data() and size() member functions.
//
// TODO(davidben): Require C++17 support for std::is_convertible_v, etc.
template <typename C>
using EnableIfContainer = std::enable_if_t<
std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
std::is_integral<decltype(std::declval<C>().size())>::value>;
public:
constexpr Span() : Span(nullptr, 0) {}
constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {}
template <size_t N>
constexpr Span(T (&array)[N]) : Span(array, N) {}
template <typename C, typename = EnableIfContainer<C>,
typename = std::enable_if_t<std::is_const<T>::value, C>>
constexpr Span(const C &container)
: data_(container.data()), size_(container.size()) {}
template <typename C, typename = EnableIfContainer<C>,
typename = std::enable_if_t<!std::is_const<T>::value, C>>
constexpr explicit Span(C &container)
: data_(container.data()), size_(container.size()) {}
constexpr T *data() const { return data_; }
constexpr size_t size() const { return size_; }
constexpr bool empty() const { return size_ == 0; }
constexpr T *begin() const { return data_; }
constexpr const T *cbegin() const { return data_; }
constexpr T *end() const { return data_ + size_; }
constexpr const T *cend() const { return end(); }
constexpr T &front() const {
if (size_ == 0) {
abort();
}
return data_[0];
}
constexpr T &back() const {
if (size_ == 0) {
abort();
}
return data_[size_ - 1];
}
constexpr T &operator[](size_t i) const {
if (i >= size_) {
abort();
}
return data_[i];
}
T &at(size_t i) const { return (*this)[i]; }
constexpr Span subspan(size_t pos = 0, size_t len = npos) const {
if (pos > size_) {
// absl::Span throws an exception here. Note std::span and Chromium
// base::span additionally forbid pos + len being out of range, with a
// special case at npos/dynamic_extent, while absl::Span::subspan clips
// the span. For now, we align with absl::Span in case we switch to it in
// the future.
abort();
}
return Span(data_ + pos, std::min(size_ - pos, len));
}
constexpr Span first(size_t len) const {
if (len > size_) {
abort();
}
return Span(data_, len);
}
constexpr Span last(size_t len) const {
if (len > size_) {
abort();
}
return Span(data_ + size_ - len, len);
}
private:
T *data_;
size_t size_;
};
template <typename T>
const size_t Span<T>::npos;
template <typename T>
constexpr Span<T> MakeSpan(T *ptr, size_t size) {
return Span<T>(ptr, size);
}
template <typename C>
constexpr auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
return MakeSpan(c.data(), c.size());
}
template <typename T>
constexpr Span<const T> MakeConstSpan(T *ptr, size_t size) {
return Span<const T>(ptr, size);
}
template <typename C>
constexpr auto MakeConstSpan(const C &c)
-> decltype(MakeConstSpan(c.data(), c.size())) {
return MakeConstSpan(c.data(), c.size());
}
template <typename T, size_t size>
constexpr Span<const T> MakeConstSpan(T (&array)[size]) {
return array;
}
BSSL_NAMESPACE_END
} // extern C++
#endif // !defined(BORINGSSL_NO_CXX)
#endif // OPENSSL_HEADER_SSL_SPAN_H
|