• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BASE_SPAN_H_
6 #define THIRD_PARTY_BASE_SPAN_H_
7 
8 #include <stddef.h>
9 
10 #include <algorithm>
11 #include <array>
12 #include <iterator>
13 #include <type_traits>
14 #include <utility>
15 
16 #include "core/fxcrt/unowned_ptr.h"
17 #include "third_party/base/logging.h"
18 
19 namespace pdfium {
20 
21 template <typename T>
22 class span;
23 
24 namespace internal {
25 
26 template <typename T>
27 struct IsSpanImpl : std::false_type {};
28 
29 template <typename T>
30 struct IsSpanImpl<span<T>> : std::true_type {};
31 
32 template <typename T>
33 using IsSpan = IsSpanImpl<typename std::decay<T>::type>;
34 
35 template <typename T>
36 struct IsStdArrayImpl : std::false_type {};
37 
38 template <typename T, size_t N>
39 struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
40 
41 template <typename T>
42 using IsStdArray = IsStdArrayImpl<typename std::decay<T>::type>;
43 
44 template <typename From, typename To>
45 using IsLegalSpanConversion = std::is_convertible<From*, To*>;
46 
47 template <typename Container, typename T>
48 using ContainerHasConvertibleData =
49     IsLegalSpanConversion<typename std::remove_pointer<decltype(
50                               std::declval<Container>().data())>::type,
51                           T>;
52 template <typename Container>
53 using ContainerHasIntegralSize =
54     std::is_integral<decltype(std::declval<Container>().size())>;
55 
56 template <typename From, typename To>
57 using EnableIfLegalSpanConversion =
58     typename std::enable_if<IsLegalSpanConversion<From, To>::value>::type;
59 
60 // SFINAE check if Container can be converted to a span<T>. Note that the
61 // implementation details of this check differ slightly from the requirements in
62 // the working group proposal: in particular, the proposal also requires that
63 // the container conversion constructor participate in overload resolution only
64 // if two additional conditions are true:
65 //
66 //   1. Container implements operator[].
67 //   2. Container::value_type matches remove_const_t<element_type>.
68 //
69 // The requirements are relaxed slightly here: in particular, not requiring (2)
70 // means that an immutable span can be easily constructed from a mutable
71 // container.
72 template <typename Container, typename T>
73 using EnableIfSpanCompatibleContainer =
74     typename std::enable_if<!internal::IsSpan<Container>::value &&
75                             !internal::IsStdArray<Container>::value &&
76                             ContainerHasConvertibleData<Container, T>::value &&
77                             ContainerHasIntegralSize<Container>::value>::type;
78 
79 template <typename Container, typename T>
80 using EnableIfConstSpanCompatibleContainer =
81     typename std::enable_if<std::is_const<T>::value &&
82                             !internal::IsSpan<Container>::value &&
83                             !internal::IsStdArray<Container>::value &&
84                             ContainerHasConvertibleData<Container, T>::value &&
85                             ContainerHasIntegralSize<Container>::value>::type;
86 
87 }  // namespace internal
88 
89 // A span is a value type that represents an array of elements of type T. Since
90 // it only consists of a pointer to memory with an associated size, it is very
91 // light-weight. It is cheap to construct, copy, move and use spans, so that
92 // users are encouraged to use it as a pass-by-value parameter. A span does not
93 // own the underlying memory, so care must be taken to ensure that a span does
94 // not outlive the backing store.
95 //
96 // span is somewhat analogous to StringPiece, but with arbitrary element types,
97 // allowing mutation if T is non-const.
98 //
99 // span is implicitly convertible from C++ arrays, as well as most [1]
100 // container-like types that provide a data() and size() method (such as
101 // std::vector<T>). A mutable span<T> can also be implicitly converted to an
102 // immutable span<const T>.
103 //
104 // Consider using a span for functions that take a data pointer and size
105 // parameter: it allows the function to still act on an array-like type, while
106 // allowing the caller code to be a bit more concise.
107 //
108 // For read-only data access pass a span<const T>: the caller can supply either
109 // a span<const T> or a span<T>, while the callee will have a read-only view.
110 // For read-write access a mutable span<T> is required.
111 //
112 // Without span:
113 //   Read-Only:
114 //     // std::string HexEncode(const uint8_t* data, size_t size);
115 //     std::vector<uint8_t> data_buffer = GenerateData();
116 //     std::string r = HexEncode(data_buffer.data(), data_buffer.size());
117 //
118 //  Mutable:
119 //     // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
120 //     char str_buffer[100];
121 //     SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
122 //
123 // With span:
124 //   Read-Only:
125 //     // std::string HexEncode(base::span<const uint8_t> data);
126 //     std::vector<uint8_t> data_buffer = GenerateData();
127 //     std::string r = HexEncode(data_buffer);
128 //
129 //  Mutable:
130 //     // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
131 //     char str_buffer[100];
132 //     SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
133 //
134 // Spans with "const" and pointers
135 // -------------------------------
136 //
137 // Const and pointers can get confusing. Here are vectors of pointers and their
138 // corresponding spans (you can always make the span "more const" too):
139 //
140 //   const std::vector<int*>        =>  base::span<int* const>
141 //   std::vector<const int*>        =>  base::span<const int*>
142 //   const std::vector<const int*>  =>  base::span<const int* const>
143 //
144 // Differences from the working group proposal
145 // -------------------------------------------
146 //
147 // https://wg21.link/P0122 is the latest working group proposal, Chromium
148 // currently implements R6. The biggest difference is span does not support a
149 // static extent template parameter. Other differences are documented in
150 // subsections below.
151 //
152 // Differences from [views.constants]:
153 // - no dynamic_extent constant
154 //
155 // Differences in constants and types:
156 // - no element_type type alias
157 // - no index_type type alias
158 // - no different_type type alias
159 // - no extent constant
160 //
161 // Differences from [span.cons]:
162 // - no constructor from a pointer range
163 // - no constructor from std::array
164 //
165 // Differences from [span.sub]:
166 // - no templated first()
167 // - no templated last()
168 // - no templated subspan()
169 // - using size_t instead of ptrdiff_t for indexing
170 //
171 // Differences from [span.obs]:
172 // - using size_t instead of ptrdiff_t to represent size()
173 //
174 // Differences from [span.elem]:
175 // - no operator ()()
176 // - using size_t instead of ptrdiff_t for indexing
177 
178 // [span], class template span
179 template <typename T>
180 class span {
181  public:
182   using value_type = typename std::remove_cv<T>::type;
183   using pointer = T*;
184   using reference = T&;
185   using iterator = T*;
186   using const_iterator = const T*;
187   using reverse_iterator = std::reverse_iterator<iterator>;
188   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
189 
190   // [span.cons], span constructors, copy, assignment, and destructor
191   constexpr span() noexcept : data_(nullptr), size_(0) {}
192   constexpr span(T* data, size_t size) noexcept : data_(data), size_(size) {}
193 
194   // TODO(dcheng): Implement construction from a |begin| and |end| pointer.
195   template <size_t N>
196   constexpr span(T (&array)[N]) noexcept : span(array, N) {}
197   // TODO(dcheng): Implement construction from std::array.
198   // Conversion from a container that provides |T* data()| and |integral_type
199   // size()|.
200   template <typename Container,
201             typename = internal::EnableIfSpanCompatibleContainer<Container, T>>
202   constexpr span(Container& container)
203       : span(container.data(), container.size()) {}
204   template <
205       typename Container,
206       typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>>
207   span(const Container& container) : span(container.data(), container.size()) {}
208   constexpr span(const span& other) noexcept = default;
209   // Conversions from spans of compatible types: this allows a span<T> to be
210   // seamlessly used as a span<const T>, but not the other way around.
211   template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>>
212   constexpr span(const span<U>& other) : span(other.data(), other.size()) {}
213   span& operator=(const span& other) noexcept = default;
214   ~span() noexcept {
215     if (!size_) {
216       // Empty spans might point to byte N+1 of a N-byte object, legal for
217       // C pointers but not UnownedPtrs.
218       data_.ReleaseBadPointer();
219     }
220   }
221 
222   // [span.sub], span subviews
223   const span first(size_t count) const {
224     CHECK(count <= size_);
225     return span(data_.Get(), count);
226   }
227 
228   const span last(size_t count) const {
229     CHECK(count <= size_);
230     return span(data_.Get() + (size_ - count), count);
231   }
232 
233   const span subspan(size_t pos, size_t count = -1) const {
234     const auto npos = static_cast<size_t>(-1);
235     CHECK(pos <= size_);
236     CHECK(count == npos || count <= size_ - pos);
237     return span(data_.Get() + pos, count == npos ? size_ - pos : count);
238   }
239 
240   // [span.obs], span observers
241   constexpr size_t size() const noexcept { return size_; }
242   constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
243   constexpr bool empty() const noexcept { return size_ == 0; }
244 
245   // [span.elem], span element access
246   T& operator[](size_t index) const noexcept {
247     CHECK(index < size_);
248     return data_.Get()[index];
249   }
250   constexpr T* data() const noexcept { return data_.Get(); }
251 
252   // [span.iter], span iterator support
253   constexpr iterator begin() const noexcept { return data_.Get(); }
254   constexpr iterator end() const noexcept { return data_.Get() + size_; }
255 
256   constexpr const_iterator cbegin() const noexcept { return begin(); }
257   constexpr const_iterator cend() const noexcept { return end(); }
258 
259   constexpr reverse_iterator rbegin() const noexcept {
260     return reverse_iterator(end());
261   }
262   constexpr reverse_iterator rend() const noexcept {
263     return reverse_iterator(begin());
264   }
265 
266   constexpr const_reverse_iterator crbegin() const noexcept {
267     return const_reverse_iterator(cend());
268   }
269   constexpr const_reverse_iterator crend() const noexcept {
270     return const_reverse_iterator(cbegin());
271   }
272 
273  private:
274   UnownedPtr<T> data_;
275   size_t size_;
276 };
277 
278 // [span.comparison], span comparison operators
279 // Relational operators. Equality is a element-wise comparison.
280 template <typename T>
281 constexpr bool operator==(span<T> lhs, span<T> rhs) noexcept {
282   return lhs.size() == rhs.size() &&
283          std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
284 }
285 
286 template <typename T>
287 constexpr bool operator!=(span<T> lhs, span<T> rhs) noexcept {
288   return !(lhs == rhs);
289 }
290 
291 template <typename T>
292 constexpr bool operator<(span<T> lhs, span<T> rhs) noexcept {
293   return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(),
294                                       rhs.cend());
295 }
296 
297 template <typename T>
298 constexpr bool operator<=(span<T> lhs, span<T> rhs) noexcept {
299   return !(rhs < lhs);
300 }
301 
302 template <typename T>
303 constexpr bool operator>(span<T> lhs, span<T> rhs) noexcept {
304   return rhs < lhs;
305 }
306 
307 template <typename T>
308 constexpr bool operator>=(span<T> lhs, span<T> rhs) noexcept {
309   return !(lhs < rhs);
310 }
311 
312 // [span.objectrep], views of object representation
313 template <typename T>
314 span<const uint8_t> as_bytes(span<T> s) noexcept {
315   return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
316 }
317 
318 template <typename T,
319           typename U = typename std::enable_if<!std::is_const<T>::value>::type>
320 span<uint8_t> as_writable_bytes(span<T> s) noexcept {
321   return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
322 }
323 
324 // Type-deducing helpers for constructing a span.
325 template <typename T>
326 constexpr span<T> make_span(T* data, size_t size) noexcept {
327   return span<T>(data, size);
328 }
329 
330 template <typename T, size_t N>
331 constexpr span<T> make_span(T (&array)[N]) noexcept {
332   return span<T>(array);
333 }
334 
335 template <typename Container,
336           typename T = typename Container::value_type,
337           typename = internal::EnableIfSpanCompatibleContainer<Container, T>>
338 constexpr span<T> make_span(Container& container) {
339   return span<T>(container);
340 }
341 
342 template <
343     typename Container,
344     typename T = typename std::add_const<typename Container::value_type>::type,
345     typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>>
346 constexpr span<T> make_span(const Container& container) {
347   return span<T>(container);
348 }
349 
350 }  // namespace pdfium
351 
352 #endif  // THIRD_PARTY_BASE_SPAN_H_
353