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 |
17 | |
18 | #include <openssl/base.h> |
19 | |
20 | #if !defined(BORINGSSL_NO_CXX) |
21 | |
22 | extern "C++" { |
23 | |
24 | #include <algorithm> |
25 | #include <cstdlib> |
26 | #include <type_traits> |
27 | |
28 | BSSL_NAMESPACE_BEGIN |
29 | |
30 | template <typename T> |
31 | class Span; |
32 | |
33 | namespace internal { |
34 | template <typename T> |
35 | class SpanBase { |
36 | // Put comparison operator implementations into a base class with const T, so |
37 | // they can be used with any type that implicitly converts into a Span. |
38 | static_assert(std::is_const<T>::value, |
39 | "Span<T> must be derived from SpanBase<const T>" ); |
40 | |
41 | friend bool operator==(Span<T> lhs, Span<T> rhs) { |
42 | // MSVC issues warning C4996 because std::equal is unsafe. The pragma to |
43 | // suppress the warning mysteriously has no effect, hence this |
44 | // implementation. See |
45 | // https://msdn.microsoft.com/en-us/library/aa985974.aspx. |
46 | if (lhs.size() != rhs.size()) { |
47 | return false; |
48 | } |
49 | for (T *l = lhs.begin(), *r = rhs.begin(); l != lhs.end() && r != rhs.end(); |
50 | ++l, ++r) { |
51 | if (*l != *r) { |
52 | return false; |
53 | } |
54 | } |
55 | return true; |
56 | } |
57 | |
58 | friend bool operator!=(Span<T> lhs, Span<T> rhs) { return !(lhs == rhs); } |
59 | }; |
60 | } // namespace internal |
61 | |
62 | // A Span<T> is a non-owning reference to a contiguous array of objects of type |
63 | // |T|. Conceptually, a Span is a simple a pointer to |T| and a count of |
64 | // elements accessible via that pointer. The elements referenced by the Span can |
65 | // be mutated if |T| is mutable. |
66 | // |
67 | // A Span can be constructed from container types implementing |data()| and |
68 | // |size()| methods. If |T| is constant, construction from a container type is |
69 | // implicit. This allows writing methods that accept data from some unspecified |
70 | // container type: |
71 | // |
72 | // // Foo views data referenced by v. |
73 | // void Foo(bssl::Span<const uint8_t> v) { ... } |
74 | // |
75 | // std::vector<uint8_t> vec; |
76 | // Foo(vec); |
77 | // |
78 | // For mutable Spans, conversion is explicit: |
79 | // |
80 | // // FooMutate mutates data referenced by v. |
81 | // void FooMutate(bssl::Span<uint8_t> v) { ... } |
82 | // |
83 | // FooMutate(bssl::Span<uint8_t>(vec)); |
84 | // |
85 | // You can also use the |MakeSpan| and |MakeConstSpan| factory methods to |
86 | // construct Spans in order to deduce the type of the Span automatically. |
87 | // |
88 | // FooMutate(bssl::MakeSpan(vec)); |
89 | // |
90 | // Note that Spans have value type sematics. They are cheap to construct and |
91 | // copy, and should be passed by value whenever a method would otherwise accept |
92 | // a reference or pointer to a container or array. |
93 | template <typename T> |
94 | class Span : private internal::SpanBase<const T> { |
95 | private: |
96 | // Heuristically test whether C is a container type that can be converted into |
97 | // a Span by checking for data() and size() member functions. |
98 | // |
99 | // TODO(davidben): Switch everything to std::enable_if_t when we remove |
100 | // support for MSVC 2015. Although we could write our own enable_if_t and MSVC |
101 | // 2015 has std::enable_if_t anyway, MSVC 2015's SFINAE implementation is |
102 | // problematic and does not work below unless we write the ::type at use. |
103 | template <typename C> |
104 | using EnableIfContainer = std::enable_if< |
105 | std::is_convertible<decltype(std::declval<C>().data()), T *>::value && |
106 | std::is_integral<decltype(std::declval<C>().size())>::value>; |
107 | |
108 | static const size_t npos = static_cast<size_t>(-1); |
109 | |
110 | public: |
111 | constexpr Span() : Span(nullptr, 0) {} |
112 | constexpr Span(T *ptr, size_t len) : data_(ptr), size_(len) {} |
113 | |
114 | template <size_t N> |
115 | constexpr Span(T (&array)[N]) : Span(array, N) {} |
116 | |
117 | template < |
118 | typename C, typename = typename EnableIfContainer<C>::type, |
119 | typename = typename std::enable_if<std::is_const<T>::value, C>::type> |
120 | Span(const C &container) : data_(container.data()), size_(container.size()) {} |
121 | |
122 | template < |
123 | typename C, typename = typename EnableIfContainer<C>::type, |
124 | typename = typename std::enable_if<!std::is_const<T>::value, C>::type> |
125 | explicit Span(C &container) |
126 | : data_(container.data()), size_(container.size()) {} |
127 | |
128 | T *data() const { return data_; } |
129 | size_t size() const { return size_; } |
130 | bool empty() const { return size_ == 0; } |
131 | |
132 | T *begin() const { return data_; } |
133 | const T *cbegin() const { return data_; } |
134 | T *end() const { return data_ + size_; } |
135 | const T *cend() const { return end(); } |
136 | |
137 | T &front() const { |
138 | if (size_ == 0) { |
139 | abort(); |
140 | } |
141 | return data_[0]; |
142 | } |
143 | T &back() const { |
144 | if (size_ == 0) { |
145 | abort(); |
146 | } |
147 | return data_[size_ - 1]; |
148 | } |
149 | |
150 | T &operator[](size_t i) const { |
151 | if (i >= size_) { |
152 | abort(); |
153 | } |
154 | return data_[i]; |
155 | } |
156 | T &at(size_t i) const { return (*this)[i]; } |
157 | |
158 | Span subspan(size_t pos = 0, size_t len = npos) const { |
159 | if (pos > size_) { |
160 | abort(); // absl::Span throws an exception here. |
161 | } |
162 | return Span(data_ + pos, std::min(size_ - pos, len)); |
163 | } |
164 | |
165 | private: |
166 | T *data_; |
167 | size_t size_; |
168 | }; |
169 | |
170 | template <typename T> |
171 | const size_t Span<T>::npos; |
172 | |
173 | template <typename T> |
174 | Span<T> MakeSpan(T *ptr, size_t size) { |
175 | return Span<T>(ptr, size); |
176 | } |
177 | |
178 | template <typename C> |
179 | auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) { |
180 | return MakeSpan(c.data(), c.size()); |
181 | } |
182 | |
183 | template <typename T> |
184 | Span<const T> MakeConstSpan(T *ptr, size_t size) { |
185 | return Span<const T>(ptr, size); |
186 | } |
187 | |
188 | template <typename C> |
189 | auto MakeConstSpan(const C &c) -> decltype(MakeConstSpan(c.data(), c.size())) { |
190 | return MakeConstSpan(c.data(), c.size()); |
191 | } |
192 | |
193 | BSSL_NAMESPACE_END |
194 | |
195 | } // extern C++ |
196 | |
197 | #endif // !defined(BORINGSSL_NO_CXX) |
198 | |
199 | #endif // OPENSSL_HEADER_SSL_SPAN_H |
200 | |