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