Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////////
2 : //
3 : // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4 : //
5 : // This code is licensed under the MIT License (MIT).
6 : //
7 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13 : // THE SOFTWARE.
14 : //
15 : ///////////////////////////////////////////////////////////////////////////////
16 :
17 : // Adapted from https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/span
18 : // and https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/gsl_util
19 :
20 : #ifndef mozilla_Span_h
21 : #define mozilla_Span_h
22 :
23 : #include "mozilla/Array.h"
24 : #include "mozilla/Assertions.h"
25 : #include "mozilla/Casting.h"
26 : #include "mozilla/IntegerTypeTraits.h"
27 : #include "mozilla/Move.h"
28 : #include "mozilla/TypeTraits.h"
29 : #include "mozilla/UniquePtr.h"
30 :
31 : #include <algorithm>
32 : #include <array>
33 : #include <cstring>
34 : #include <iterator>
35 :
36 : // Classifications for reasons why constexpr was removed in C++14 to C++11
37 : // conversion. Once we upgrade compilers, we can try defining each of these
38 : // to constexpr to restore a category of constexprs at a time.
39 : #define MOZ_SPAN_ASSERTION_CONSTEXPR
40 : #define MOZ_SPAN_GCC_CONSTEXPR
41 : #define MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR
42 : #define MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN
43 : #define MOZ_SPAN_NON_CONST_CONSTEXPR
44 :
45 : #ifdef _MSC_VER
46 : #pragma warning(push)
47 :
48 : // turn off some warnings that are noisy about our MOZ_RELEASE_ASSERT statements
49 : #pragma warning(disable : 4127) // conditional expression is constant
50 :
51 : // blanket turn off warnings from CppCoreCheck for now
52 : // so people aren't annoyed by them when running the tool.
53 : // more targeted suppressions will be added in a future update to the GSL
54 : #pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
55 :
56 : #if _MSC_VER < 1910
57 : #pragma push_macro("constexpr")
58 : #define constexpr /*constexpr*/
59 :
60 : #endif // _MSC_VER < 1910
61 : #endif // _MSC_VER
62 :
63 : namespace mozilla {
64 :
65 : // Stuff from gsl_util
66 :
67 : // narrow_cast(): a searchable way to do narrowing casts of values
68 : template<class T, class U>
69 : inline constexpr T
70 129 : narrow_cast(U&& u)
71 : {
72 129 : return static_cast<T>(mozilla::Forward<U>(u));
73 : }
74 :
75 : // end gsl_util
76 :
77 : // [views.constants], constants
78 : // This was -1 in gsl::span, but using size_t for sizes instead of ptrdiff_t
79 : // and reserving a magic value that realistically doesn't occur in
80 : // compile-time-constant Span sizes makes things a lot less messy in terms of
81 : // comparison between signed and unsigned.
82 : constexpr const size_t dynamic_extent = mozilla::MaxValue<size_t>::value;
83 :
84 : template<class ElementType, size_t Extent = dynamic_extent>
85 : class Span;
86 :
87 : // implementation details
88 : namespace span_details {
89 :
90 0 : inline size_t strlen16(const char16_t* aZeroTerminated) {
91 0 : size_t len = 0;
92 0 : while (*(aZeroTerminated++)) {
93 0 : len++;
94 : }
95 0 : return len;
96 : }
97 :
98 : // C++14 types that we don't have because we build as C++11.
99 : template<class T>
100 : using remove_cv_t = typename mozilla::RemoveCV<T>::Type;
101 : template<class T>
102 : using remove_const_t = typename mozilla::RemoveConst<T>::Type;
103 : template<bool B, class T, class F>
104 : using conditional_t = typename mozilla::Conditional<B, T, F>::Type;
105 : template<class T>
106 : using add_pointer_t = typename mozilla::AddPointer<T>::Type;
107 : template<bool B, class T = void>
108 : using enable_if_t = typename mozilla::EnableIf<B, T>::Type;
109 :
110 : template<class T>
111 : struct is_span_oracle : mozilla::FalseType
112 : {
113 : };
114 :
115 : template<class ElementType, size_t Extent>
116 : struct is_span_oracle<mozilla::Span<ElementType, Extent>> : mozilla::TrueType
117 : {
118 : };
119 :
120 : template<class T>
121 : struct is_span : public is_span_oracle<remove_cv_t<T>>
122 : {
123 : };
124 :
125 : template<class T>
126 : struct is_std_array_oracle : mozilla::FalseType
127 : {
128 : };
129 :
130 : template<class ElementType, size_t Extent>
131 : struct is_std_array_oracle<std::array<ElementType, Extent>> : mozilla::TrueType
132 : {
133 : };
134 :
135 : template<class T>
136 : struct is_std_array : public is_std_array_oracle<remove_cv_t<T>>
137 : {
138 : };
139 :
140 : template<size_t From, size_t To>
141 : struct is_allowed_extent_conversion
142 : : public mozilla::IntegralConstant<bool,
143 : From == To ||
144 : From == mozilla::dynamic_extent ||
145 : To == mozilla::dynamic_extent>
146 : {
147 : };
148 :
149 : template<class From, class To>
150 : struct is_allowed_element_type_conversion
151 : : public mozilla::IntegralConstant<bool, mozilla::IsConvertible<From (*)[], To (*)[]>::value>
152 : {
153 : };
154 :
155 : template<class Span, bool IsConst>
156 : class span_iterator
157 : {
158 : using element_type_ = typename Span::element_type;
159 :
160 : public:
161 : using iterator_category = std::random_access_iterator_tag;
162 : using value_type = remove_const_t<element_type_>;
163 : using difference_type = typename Span::index_type;
164 :
165 : using reference = conditional_t<IsConst, const element_type_, element_type_>&;
166 : using pointer = add_pointer_t<reference>;
167 :
168 : constexpr span_iterator() : span_iterator(nullptr, 0) {}
169 :
170 0 : MOZ_SPAN_ASSERTION_CONSTEXPR span_iterator(const Span* span,
171 : typename Span::index_type index)
172 : : span_(span)
173 0 : , index_(index)
174 : {
175 0 : MOZ_RELEASE_ASSERT(span == nullptr ||
176 : (index_ >= 0 && index <= span_->Length()));
177 0 : }
178 :
179 : friend class span_iterator<Span, true>;
180 : constexpr MOZ_IMPLICIT span_iterator(const span_iterator<Span, false>& other)
181 : : span_iterator(other.span_, other.index_)
182 : {
183 : }
184 :
185 : MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR span_iterator<Span, IsConst>&
186 : operator=(const span_iterator<Span, IsConst>&) = default;
187 :
188 0 : MOZ_SPAN_GCC_CONSTEXPR reference operator*() const
189 : {
190 0 : MOZ_RELEASE_ASSERT(span_);
191 0 : return (*span_)[index_];
192 : }
193 :
194 : MOZ_SPAN_GCC_CONSTEXPR pointer operator->() const
195 : {
196 : MOZ_RELEASE_ASSERT(span_);
197 : return &((*span_)[index_]);
198 : }
199 :
200 0 : MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator++()
201 : {
202 0 : MOZ_RELEASE_ASSERT(span_ && index_ >= 0 && index_ < span_->Length());
203 0 : ++index_;
204 0 : return *this;
205 : }
206 :
207 : MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator operator++(int)
208 : {
209 : auto ret = *this;
210 : ++(*this);
211 : return ret;
212 : }
213 :
214 : MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator--()
215 : {
216 : MOZ_RELEASE_ASSERT(span_ && index_ > 0 && index_ <= span_->Length());
217 : --index_;
218 : return *this;
219 : }
220 :
221 : MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator operator--(int)
222 : {
223 : auto ret = *this;
224 : --(*this);
225 : return ret;
226 : }
227 :
228 : MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN span_iterator
229 : operator+(difference_type n) const
230 : {
231 : auto ret = *this;
232 : return ret += n;
233 : }
234 :
235 : MOZ_SPAN_GCC_CONSTEXPR span_iterator& operator+=(difference_type n)
236 : {
237 : MOZ_RELEASE_ASSERT(span_ && (index_ + n) >= 0 &&
238 : (index_ + n) <= span_->Length());
239 : index_ += n;
240 : return *this;
241 : }
242 :
243 : MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN span_iterator
244 : operator-(difference_type n) const
245 : {
246 : auto ret = *this;
247 : return ret -= n;
248 : }
249 :
250 : MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator-=(difference_type n)
251 :
252 : {
253 : return *this += -n;
254 : }
255 :
256 : MOZ_SPAN_GCC_CONSTEXPR difference_type
257 : operator-(const span_iterator& rhs) const
258 : {
259 : MOZ_RELEASE_ASSERT(span_ == rhs.span_);
260 : return index_ - rhs.index_;
261 : }
262 :
263 : constexpr reference operator[](difference_type n) const
264 : {
265 : return *(*this + n);
266 : }
267 :
268 0 : constexpr friend bool operator==(const span_iterator& lhs,
269 : const span_iterator& rhs)
270 : {
271 0 : return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
272 : }
273 :
274 0 : constexpr friend bool operator!=(const span_iterator& lhs,
275 : const span_iterator& rhs)
276 : {
277 0 : return !(lhs == rhs);
278 : }
279 :
280 : MOZ_SPAN_GCC_CONSTEXPR friend bool operator<(const span_iterator& lhs,
281 : const span_iterator& rhs)
282 : {
283 : MOZ_RELEASE_ASSERT(lhs.span_ == rhs.span_);
284 : return lhs.index_ < rhs.index_;
285 : }
286 :
287 : MOZ_SPAN_GCC_CONSTEXPR friend bool operator<=(const span_iterator& lhs,
288 : const span_iterator& rhs)
289 : {
290 : return !(rhs < lhs);
291 : }
292 :
293 : MOZ_SPAN_GCC_CONSTEXPR friend bool operator>(const span_iterator& lhs,
294 : const span_iterator& rhs)
295 : {
296 : return rhs < lhs;
297 : }
298 :
299 : MOZ_SPAN_GCC_CONSTEXPR friend bool operator>=(const span_iterator& lhs,
300 : const span_iterator& rhs)
301 : {
302 : return !(rhs > lhs);
303 : }
304 :
305 : void swap(span_iterator& rhs)
306 : {
307 : std::swap(index_, rhs.index_);
308 : std::swap(span_, rhs.span_);
309 : }
310 :
311 : protected:
312 : const Span* span_;
313 : size_t index_;
314 : };
315 :
316 : template<class Span, bool IsConst>
317 : inline constexpr span_iterator<Span, IsConst>
318 : operator+(typename span_iterator<Span, IsConst>::difference_type n,
319 : const span_iterator<Span, IsConst>& rhs)
320 : {
321 : return rhs + n;
322 : }
323 :
324 : template<size_t Ext>
325 : class extent_type
326 : {
327 : public:
328 : using index_type = size_t;
329 :
330 : static_assert(Ext >= 0, "A fixed-size Span must be >= 0 in size.");
331 :
332 2 : constexpr extent_type() {}
333 :
334 : template<index_type Other>
335 : MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT extent_type(extent_type<Other> ext)
336 : {
337 : static_assert(
338 : Other == Ext || Other == dynamic_extent,
339 : "Mismatch between fixed-size extent and size of initializing data.");
340 : MOZ_RELEASE_ASSERT(ext.size() == Ext);
341 : }
342 :
343 : MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT extent_type(index_type length)
344 : {
345 : MOZ_RELEASE_ASSERT(length == Ext);
346 : }
347 :
348 2 : constexpr index_type size() const { return Ext; }
349 : };
350 :
351 : template<>
352 : class extent_type<dynamic_extent>
353 : {
354 : public:
355 : using index_type = size_t;
356 :
357 : template<index_type Other>
358 2 : explicit constexpr extent_type(extent_type<Other> ext)
359 2 : : size_(ext.size())
360 : {
361 2 : }
362 :
363 5553 : explicit constexpr extent_type(index_type length)
364 5553 : : size_(length)
365 : {
366 5553 : }
367 :
368 11159 : constexpr index_type size() const { return size_; }
369 :
370 : private:
371 : index_type size_;
372 : };
373 : } // namespace span_details
374 :
375 : /**
376 : * Span - slices for C++
377 : *
378 : * Span implements Rust's slice concept for C++. It's called "Span" instead of
379 : * "Slice" to follow the naming used in C++ Core Guidelines.
380 : *
381 : * A Span wraps a pointer and a length that identify a non-owning view to a
382 : * contiguous block of memory of objects of the same type. Various types,
383 : * including (pre-decay) C arrays, XPCOM strings, nsTArray, mozilla::Array,
384 : * mozilla::Range and contiguous standard-library containers, auto-convert
385 : * into Spans when attempting to pass them as arguments to methods that take
386 : * Spans. MakeSpan() functions can be used for explicit conversion in other
387 : * contexts. (Span itself autoconverts into mozilla::Range.)
388 : *
389 : * Like Rust's slices, Span provides safety against out-of-bounds access by
390 : * performing run-time bound checks. However, unlike Rust's slices, Span
391 : * cannot provide safety against use-after-free.
392 : *
393 : * (Note: Span is like Rust's slice only conceptually. Due to the lack of
394 : * ABI guarantees, you should still decompose spans/slices to raw pointer
395 : * and length parts when crossing the FFI. The Elements() and data() methods
396 : * are guaranteed to return a non-null pointer even for zero-length spans,
397 : * so the pointer can be used as a raw part of a Rust slice without further
398 : * checks.)
399 : *
400 : * In addition to having constructors and MakeSpan() functions that take
401 : * various well-known types, a Span for an arbitrary type can be constructed
402 : * (via constructor or MakeSpan()) from a pointer and a length or a pointer
403 : * and another pointer pointing just past the last element.
404 : *
405 : * A Span<const char> or Span<const char16_t> can be obtained for const char*
406 : * or const char16_t pointing to a zero-terminated string using the
407 : * MakeStringSpan() function. Corresponding implicit constructor does not exist
408 : * in order to avoid accidental construction in cases where const char* or
409 : * const char16_t* do not point to a zero-terminated string.
410 : *
411 : * Span has methods that follow the Mozilla naming style and methods that
412 : * don't. The methods that follow the Mozilla naming style are meant to be
413 : * used directly from Mozilla code. The methods that don't are meant for
414 : * integration with C++11 range-based loops and with meta-programming that
415 : * expects the same methods that are found on the standard-library
416 : * containers. For example, to decompose a Span into its parts in Mozilla
417 : * code, use Elements() and Length() (as with nsTArray) instead of data()
418 : * and size() (as with std::vector).
419 : *
420 : * The pointer and length wrapped by a Span cannot be changed after a Span has
421 : * been created. When new values are required, simply create a new Span. Span
422 : * has a method called Subspan() that works analogously to the Substring()
423 : * method of XPCOM strings taking a start index and an optional length. As a
424 : * Mozilla extension (relative to Microsoft's gsl::span that mozilla::Span is
425 : * based on), Span has methods From(start), To(end) and FromTo(start, end)
426 : * that correspond to Rust's &slice[start..], &slice[..end] and
427 : * &slice[start..end], respectively. (That is, the end index is the index of
428 : * the first element not to be included in the new subspan.)
429 : *
430 : * When indicating a Span that's only read from, const goes inside the type
431 : * parameter. Don't put const in front of Span. That is:
432 : * size_t ReadsFromOneSpanAndWritesToAnother(Span<const uint8_t> aReadFrom,
433 : * Span<uint8_t> aWrittenTo);
434 : *
435 : * Any Span<const T> can be viewed as Span<const uint8_t> using the function
436 : * AsBytes(). Any Span<T> can be viewed as Span<uint8_t> using the function
437 : * AsWritableBytes().
438 : */
439 : template<class ElementType, size_t Extent>
440 : class Span
441 : {
442 : public:
443 : // constants and types
444 : using element_type = ElementType;
445 : using index_type = size_t;
446 : using pointer = element_type*;
447 : using reference = element_type&;
448 :
449 : using iterator =
450 : span_details::span_iterator<Span<ElementType, Extent>, false>;
451 : using const_iterator =
452 : span_details::span_iterator<Span<ElementType, Extent>, true>;
453 : using reverse_iterator = std::reverse_iterator<iterator>;
454 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
455 :
456 : constexpr static const index_type extent = Extent;
457 :
458 : // [Span.cons], Span constructors, copy, assignment, and destructor
459 : // "Dependent" is needed to make "span_details::enable_if_t<(Dependent || Extent == 0 || Extent == mozilla::MaxValue<size_t>::value)>" SFINAE,
460 : // since "span_details::enable_if_t<(Extent == 0 || Extent == mozilla::MaxValue<size_t>::value)>" is ill-formed when Extent is neither of the extreme values.
461 : /**
462 : * Constructor with no args.
463 : */
464 : template<
465 : bool Dependent = false,
466 : class = span_details::enable_if_t<
467 : (Dependent || Extent == 0 || Extent == mozilla::MaxValue<size_t>::value)>>
468 2 : constexpr Span()
469 2 : : storage_(nullptr, span_details::extent_type<0>())
470 : {
471 2 : }
472 :
473 : /**
474 : * Constructor for nullptr.
475 : */
476 0 : constexpr MOZ_IMPLICIT Span(std::nullptr_t) : Span() {}
477 :
478 : /**
479 : * Constructor for pointer and length.
480 : */
481 5548 : constexpr Span(pointer aPtr, index_type aLength)
482 5548 : : storage_(aPtr, aLength)
483 : {
484 5548 : }
485 :
486 : /**
487 : * Constructor for start pointer and pointer past end.
488 : */
489 : constexpr Span(pointer aStartPtr, pointer aEndPtr)
490 : : storage_(aStartPtr, std::distance(aStartPtr, aEndPtr))
491 : {
492 : }
493 :
494 : /**
495 : * Constructor for C array.
496 : */
497 : template<size_t N>
498 0 : constexpr MOZ_IMPLICIT Span(element_type (&aArr)[N])
499 0 : : storage_(&aArr[0], span_details::extent_type<N>())
500 : {
501 0 : }
502 :
503 : /**
504 : * Constructor for std::array.
505 : */
506 : template<size_t N,
507 : class ArrayElementType = span_details::remove_const_t<element_type>>
508 : constexpr MOZ_IMPLICIT Span(std::array<ArrayElementType, N>& aArr)
509 : : storage_(&aArr[0], span_details::extent_type<N>())
510 : {
511 : }
512 :
513 : /**
514 : * Constructor for const std::array.
515 : */
516 : template<size_t N>
517 : constexpr MOZ_IMPLICIT Span(
518 : const std::array<span_details::remove_const_t<element_type>, N>& aArr)
519 : : storage_(&aArr[0], span_details::extent_type<N>())
520 : {
521 : }
522 :
523 : /**
524 : * Constructor for mozilla::Array.
525 : */
526 : template<size_t N,
527 : class ArrayElementType = span_details::remove_const_t<element_type>>
528 : constexpr MOZ_IMPLICIT Span(mozilla::Array<ArrayElementType, N>& aArr)
529 : : storage_(&aArr[0], span_details::extent_type<N>())
530 : {
531 : }
532 :
533 : /**
534 : * Constructor for const mozilla::Array.
535 : */
536 : template<size_t N>
537 : constexpr MOZ_IMPLICIT Span(
538 : const mozilla::Array<span_details::remove_const_t<element_type>, N>& aArr)
539 : : storage_(&aArr[0], span_details::extent_type<N>())
540 : {
541 : }
542 :
543 : /**
544 : * Constructor for mozilla::UniquePtr holding an array and length.
545 : */
546 : template<class ArrayElementType = std::add_pointer<element_type>>
547 : constexpr Span(const mozilla::UniquePtr<ArrayElementType>& aPtr,
548 : index_type aLength)
549 : : storage_(aPtr.get(), aLength)
550 : {
551 : }
552 :
553 : // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
554 : // on Container to be a contiguous sequence container.
555 : /**
556 : * Constructor for standard-library containers.
557 : */
558 : template<
559 : class Container,
560 : class = span_details::enable_if_t<
561 : !span_details::is_span<Container>::value &&
562 : !span_details::is_std_array<Container>::value &&
563 : mozilla::IsConvertible<typename Container::pointer, pointer>::value &&
564 : mozilla::IsConvertible<typename Container::pointer,
565 : decltype(mozilla::DeclVal<Container>().data())>::value>>
566 0 : constexpr MOZ_IMPLICIT Span(Container& cont)
567 0 : : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size()))
568 : {
569 0 : }
570 :
571 : /**
572 : * Constructor for standard-library containers (const version).
573 : */
574 : template<
575 : class Container,
576 : class = span_details::enable_if_t<
577 : mozilla::IsConst<element_type>::value &&
578 : !span_details::is_span<Container>::value &&
579 : mozilla::IsConvertible<typename Container::pointer, pointer>::value &&
580 : mozilla::IsConvertible<typename Container::pointer,
581 : decltype(mozilla::DeclVal<Container>().data())>::value>>
582 0 : constexpr MOZ_IMPLICIT Span(const Container& cont)
583 0 : : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size()))
584 : {
585 0 : }
586 :
587 : /**
588 : * Constructor from other Span.
589 : */
590 : constexpr Span(const Span& other) = default;
591 :
592 : /**
593 : * Constructor from other Span.
594 : */
595 : constexpr Span(Span&& other) = default;
596 :
597 : /**
598 : * Constructor from other Span with conversion of element type.
599 : */
600 : template<
601 : class OtherElementType,
602 : size_t OtherExtent,
603 : class = span_details::enable_if_t<
604 : span_details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
605 : span_details::is_allowed_element_type_conversion<OtherElementType,
606 : element_type>::value>>
607 4 : constexpr MOZ_IMPLICIT Span(const Span<OtherElementType, OtherExtent>& other)
608 : : storage_(other.data(),
609 4 : span_details::extent_type<OtherExtent>(other.size()))
610 : {
611 4 : }
612 :
613 : /**
614 : * Constructor from other Span with conversion of element type.
615 : */
616 : template<
617 : class OtherElementType,
618 : size_t OtherExtent,
619 : class = span_details::enable_if_t<
620 : span_details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
621 : span_details::is_allowed_element_type_conversion<OtherElementType,
622 : element_type>::value>>
623 1 : constexpr MOZ_IMPLICIT Span(Span<OtherElementType, OtherExtent>&& other)
624 : : storage_(other.data(),
625 1 : span_details::extent_type<OtherExtent>(other.size()))
626 : {
627 1 : }
628 :
629 : ~Span() = default;
630 : MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(const Span& other)
631 : = default;
632 :
633 : MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(Span&& other)
634 : = default;
635 :
636 : // [Span.sub], Span subviews
637 : /**
638 : * Subspan with first N elements with compile-time N.
639 : */
640 : template<size_t Count>
641 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, Count> First() const
642 : {
643 : MOZ_RELEASE_ASSERT(Count <= size());
644 : return { data(), Count };
645 : }
646 :
647 : /**
648 : * Subspan with last N elements with compile-time N.
649 : */
650 : template<size_t Count>
651 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, Count> Last() const
652 : {
653 : MOZ_RELEASE_ASSERT(Count <= size());
654 : return { data() + (size() - Count), Count };
655 : }
656 :
657 : /**
658 : * Subspan with compile-time start index and length.
659 : */
660 : template<size_t Offset, size_t Count = dynamic_extent>
661 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, Count> Subspan() const
662 : {
663 : MOZ_RELEASE_ASSERT(Offset <= size() &&
664 : (Count == dynamic_extent || (Offset + Count <= size())));
665 : return { data() + Offset,
666 : Count == dynamic_extent ? size() - Offset : Count };
667 : }
668 :
669 : /**
670 : * Subspan with first N elements with run-time N.
671 : */
672 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> First(
673 : index_type aCount) const
674 : {
675 : MOZ_RELEASE_ASSERT(aCount <= size());
676 : return { data(), aCount };
677 : }
678 :
679 : /**
680 : * Subspan with last N elements with run-time N.
681 : */
682 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> Last(
683 : index_type aCount) const
684 : {
685 : MOZ_RELEASE_ASSERT(aCount <= size());
686 : return { data() + (size() - aCount), aCount };
687 : }
688 :
689 : /**
690 : * Subspan with run-time start index and length.
691 : */
692 4 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> Subspan(
693 : index_type aStart,
694 : index_type aLength = dynamic_extent) const
695 : {
696 4 : MOZ_RELEASE_ASSERT(aStart <= size() &&
697 : (aLength == dynamic_extent ||
698 : (aStart + aLength <= size())));
699 4 : return { data() + aStart,
700 4 : aLength == dynamic_extent ? size() - aStart : aLength };
701 : }
702 :
703 : /**
704 : * Subspan with run-time start index. (Rust's &foo[start..])
705 : */
706 4 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> From(
707 : index_type aStart) const
708 : {
709 4 : return Subspan(aStart);
710 : }
711 :
712 : /**
713 : * Subspan with run-time exclusive end index. (Rust's &foo[..end])
714 : */
715 0 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> To(
716 : index_type aEnd) const
717 : {
718 0 : return Subspan(0, aEnd);
719 : }
720 :
721 : /**
722 : * Subspan with run-time start index and exclusive end index.
723 : * (Rust's &foo[start..end])
724 : */
725 : MOZ_SPAN_GCC_CONSTEXPR Span<element_type, dynamic_extent> FromTo(
726 : index_type aStart,
727 : index_type aEnd) const
728 : {
729 : MOZ_RELEASE_ASSERT(aStart <= aEnd);
730 : return Subspan(aStart, aEnd - aStart);
731 : }
732 :
733 : // [Span.obs], Span observers
734 : /**
735 : * Number of elements in the span.
736 : */
737 5462 : constexpr index_type Length() const { return size(); }
738 :
739 : /**
740 : * Number of elements in the span (standard-libray duck typing version).
741 : */
742 5604 : constexpr index_type size() const { return storage_.size(); }
743 :
744 : /**
745 : * Size of the span in bytes.
746 : */
747 : constexpr index_type LengthBytes() const { return size_bytes(); }
748 :
749 : /**
750 : * Size of the span in bytes (standard-library naming style version).
751 : */
752 129 : constexpr index_type size_bytes() const
753 : {
754 129 : return size() * narrow_cast<index_type>(sizeof(element_type));
755 : }
756 :
757 : /**
758 : * Checks if the the length of the span is zero.
759 : */
760 : constexpr bool IsEmpty() const { return empty(); }
761 :
762 : /**
763 : * Checks if the the length of the span is zero (standard-libray duck
764 : * typing version).
765 : */
766 : constexpr bool empty() const { return size() == 0; }
767 :
768 : // [Span.elem], Span element access
769 0 : MOZ_SPAN_GCC_CONSTEXPR reference operator[](index_type idx) const
770 : {
771 0 : MOZ_RELEASE_ASSERT(idx < storage_.size());
772 0 : return data()[idx];
773 : }
774 :
775 : /**
776 : * Access element of span by index (standard-library duck typing version).
777 : */
778 : constexpr reference at(index_type idx) const { return this->operator[](idx); }
779 :
780 : constexpr reference operator()(index_type idx) const
781 : {
782 : return this->operator[](idx);
783 : }
784 :
785 : /**
786 : * Pointer to the first element of the span. The return value is never
787 : * nullptr, not ever for zero-length spans, so it can be passed as-is
788 : * to std::slice::from_raw_parts() in Rust.
789 : */
790 5456 : constexpr pointer Elements() const { return data(); }
791 :
792 : /**
793 : * Pointer to the first element of the span (standard-libray duck typing version).
794 : * The return value is never nullptr, not ever for zero-length spans, so it can
795 : * be passed as-is to std::slice::from_raw_parts() in Rust.
796 : */
797 5594 : constexpr pointer data() const { return storage_.data(); }
798 :
799 : // [Span.iter], Span iterator support
800 0 : iterator begin() const { return { this, 0 }; }
801 0 : iterator end() const { return { this, Length() }; }
802 :
803 : const_iterator cbegin() const { return { this, 0 }; }
804 : const_iterator cend() const { return { this, Length() }; }
805 :
806 : reverse_iterator rbegin() const
807 : {
808 : return reverse_iterator{ end() };
809 : }
810 : reverse_iterator rend() const
811 : {
812 : return reverse_iterator{ begin() };
813 : }
814 :
815 : const_reverse_iterator crbegin() const
816 : {
817 : return const_reverse_iterator{ cend() };
818 : }
819 : const_reverse_iterator crend() const
820 : {
821 : return const_reverse_iterator{ cbegin() };
822 : }
823 :
824 : private:
825 : // this implementation detail class lets us take advantage of the
826 : // empty base class optimization to pay for only storage of a single
827 : // pointer in the case of fixed-size Spans
828 : template<class ExtentType>
829 : class storage_type : public ExtentType
830 : {
831 : public:
832 : template<class OtherExtentType>
833 5555 : MOZ_SPAN_ASSERTION_CONSTEXPR storage_type(pointer elements,
834 : OtherExtentType ext)
835 : : ExtentType(ext)
836 : // Replace nullptr with 0x1 for Rust slice compatibility. See
837 : // https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
838 5555 : , data_(elements ? elements : reinterpret_cast<pointer>(0x1))
839 : {
840 5555 : MOZ_RELEASE_ASSERT(
841 : (!elements && ExtentType::size() == 0) ||
842 : (elements && ExtentType::size() != mozilla::MaxValue<size_t>::value));
843 5555 : }
844 :
845 5594 : constexpr pointer data() const { return data_; }
846 :
847 : private:
848 : pointer data_;
849 : };
850 :
851 : storage_type<span_details::extent_type<Extent>> storage_;
852 : };
853 :
854 : // [Span.comparison], Span comparison operators
855 : template<class ElementType, size_t FirstExtent, size_t SecondExtent>
856 : inline constexpr bool
857 : operator==(const Span<ElementType, FirstExtent>& l,
858 : const Span<ElementType, SecondExtent>& r)
859 : {
860 : return (l.size() == r.size()) && std::equal(l.begin(), l.end(), r.begin());
861 : }
862 :
863 : template<class ElementType, size_t Extent>
864 : inline constexpr bool
865 : operator!=(const Span<ElementType, Extent>& l,
866 : const Span<ElementType, Extent>& r)
867 : {
868 : return !(l == r);
869 : }
870 :
871 : template<class ElementType, size_t Extent>
872 : inline constexpr bool
873 : operator<(const Span<ElementType, Extent>& l,
874 : const Span<ElementType, Extent>& r)
875 : {
876 : return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
877 : }
878 :
879 : template<class ElementType, size_t Extent>
880 : inline constexpr bool
881 : operator<=(const Span<ElementType, Extent>& l,
882 : const Span<ElementType, Extent>& r)
883 : {
884 : return !(l > r);
885 : }
886 :
887 : template<class ElementType, size_t Extent>
888 : inline constexpr bool
889 : operator>(const Span<ElementType, Extent>& l,
890 : const Span<ElementType, Extent>& r)
891 : {
892 : return r < l;
893 : }
894 :
895 : template<class ElementType, size_t Extent>
896 : inline constexpr bool
897 : operator>=(const Span<ElementType, Extent>& l,
898 : const Span<ElementType, Extent>& r)
899 : {
900 : return !(l < r);
901 : }
902 :
903 : namespace span_details {
904 : // if we only supported compilers with good constexpr support then
905 : // this pair of classes could collapse down to a constexpr function
906 :
907 : // we should use a narrow_cast<> to go to size_t, but older compilers may not see it as
908 : // constexpr
909 : // and so will fail compilation of the template
910 : template<class ElementType, size_t Extent>
911 : struct calculate_byte_size
912 : : mozilla::IntegralConstant<size_t,
913 : static_cast<size_t>(sizeof(ElementType) *
914 : static_cast<size_t>(Extent))>
915 : {
916 : };
917 :
918 : template<class ElementType>
919 : struct calculate_byte_size<ElementType, dynamic_extent>
920 : : mozilla::IntegralConstant<size_t, dynamic_extent>
921 : {
922 : };
923 : }
924 :
925 : // [Span.objectrep], views of object representation
926 : /**
927 : * View span as Span<const uint8_t>.
928 : */
929 : template<class ElementType, size_t Extent>
930 : Span<const uint8_t,
931 : span_details::calculate_byte_size<ElementType, Extent>::value>
932 129 : AsBytes(Span<ElementType, Extent> s)
933 : {
934 129 : return { reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes() };
935 : }
936 :
937 : /**
938 : * View span as Span<uint8_t>.
939 : */
940 : template<class ElementType,
941 : size_t Extent,
942 : class = span_details::enable_if_t<!mozilla::IsConst<ElementType>::value>>
943 : Span<uint8_t, span_details::calculate_byte_size<ElementType, Extent>::value>
944 0 : AsWritableBytes(Span<ElementType, Extent> s)
945 : {
946 0 : return { reinterpret_cast<uint8_t*>(s.data()), s.size_bytes() };
947 : }
948 :
949 : //
950 : // MakeSpan() - Utility functions for creating Spans
951 : //
952 : /**
953 : * Create span from pointer and length.
954 : */
955 : template<class ElementType>
956 : Span<ElementType>
957 685 : MakeSpan(ElementType* aPtr, typename Span<ElementType>::index_type aLength)
958 : {
959 685 : return Span<ElementType>(aPtr, aLength);
960 : }
961 :
962 : /**
963 : * Create span from start pointer and pointer past end.
964 : */
965 : template<class ElementType>
966 : Span<ElementType>
967 : MakeSpan(ElementType* aStartPtr, ElementType* aEndPtr)
968 : {
969 : return Span<ElementType>(aStartPtr, aEndPtr);
970 : }
971 :
972 : /**
973 : * Create span from C array.
974 : */
975 : template<class ElementType, size_t N>
976 0 : Span<ElementType> MakeSpan(ElementType (&aArr)[N])
977 : {
978 0 : return Span<ElementType>(aArr);
979 : }
980 :
981 : /**
982 : * Create span from mozilla::Array.
983 : */
984 : template<class ElementType, size_t N>
985 : Span<ElementType>
986 : MakeSpan(mozilla::Array<ElementType, N>& aArr)
987 : {
988 : return aArr;
989 : }
990 :
991 : /**
992 : * Create span from const mozilla::Array.
993 : */
994 : template<class ElementType, size_t N>
995 : Span<const ElementType>
996 : MakeSpan(const mozilla::Array<ElementType, N>& arr)
997 : {
998 : return arr;
999 : }
1000 :
1001 : /**
1002 : * Create span from standard-library container.
1003 : */
1004 : template<class Container>
1005 : Span<typename Container::value_type>
1006 : MakeSpan(Container& cont)
1007 : {
1008 : return Span<typename Container::value_type>(cont);
1009 : }
1010 :
1011 : /**
1012 : * Create span from standard-library container (const version).
1013 : */
1014 : template<class Container>
1015 : Span<const typename Container::value_type>
1016 : MakeSpan(const Container& cont)
1017 : {
1018 : return Span<const typename Container::value_type>(cont);
1019 : }
1020 :
1021 : /**
1022 : * Create span from smart pointer and length.
1023 : */
1024 : template<class Ptr>
1025 : Span<typename Ptr::element_type>
1026 : MakeSpan(Ptr& aPtr, size_t aLength)
1027 : {
1028 : return Span<typename Ptr::element_type>(aPtr, aLength);
1029 : }
1030 :
1031 : /**
1032 : * Create span from C string.
1033 : */
1034 : inline Span<const char>
1035 4724 : MakeStringSpan(const char* aZeroTerminated)
1036 : {
1037 4724 : return Span<const char>(aZeroTerminated, std::strlen(aZeroTerminated));
1038 : }
1039 :
1040 : /**
1041 : * Create span from UTF-16 C string.
1042 : */
1043 : inline Span<const char16_t>
1044 0 : MakeStringSpan(const char16_t* aZeroTerminated)
1045 : {
1046 0 : return Span<const char16_t>(aZeroTerminated, span_details::strlen16(aZeroTerminated));
1047 : }
1048 :
1049 : } // namespace mozilla
1050 :
1051 : #ifdef _MSC_VER
1052 : #if _MSC_VER < 1910
1053 : #undef constexpr
1054 : #pragma pop_macro("constexpr")
1055 :
1056 : #endif // _MSC_VER < 1910
1057 :
1058 : #pragma warning(pop)
1059 : #endif // _MSC_VER
1060 :
1061 : #undef MOZ_SPAN_ASSERTION_CONSTEXPR
1062 : #undef MOZ_SPAN_GCC_CONSTEXPR
1063 : #undef MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR
1064 : #undef MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN
1065 : #undef MOZ_SPAN_NON_CONST_CONSTEXPR
1066 :
1067 : #endif // mozilla_Span_h
|