Line data Source code
1 1 :
2 : /// \file
3 : /// Defines functions and classes from the GSL
4 :
5 : #pragma once
6 :
7 : #pragma GCC system_header
8 :
9 : // The code in this file is adapted from Microsoft's GSL that can be found at
10 : // https://github.com/Microsoft/GSL
11 : // The original license and copyright are:
12 : ///////////////////////////////////////////////////////////////////////////////
13 : //
14 : // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
15 : //
16 : // This code is licensed under the MIT License (MIT).
17 : //
18 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : // THE SOFTWARE.
25 : //
26 : ///////////////////////////////////////////////////////////////////////////////
27 : // The code changes are because SpECTRE is not allowed to throw under any
28 : // circumstances that cannot be guaranteed to be caught and so all throw's
29 : // are replaced by hard errors (ERROR).
30 :
31 : #include <algorithm> // for lexicographical_compare
32 : #include <array> // for array
33 : #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
34 : #include <iterator> // for reverse_iterator, distance, random_access_...
35 : #include <limits>
36 : #include <memory> // for std::addressof
37 : #include <stdexcept>
38 : #include <type_traits>
39 : #include <utility>
40 :
41 : #include "Utilities/ErrorHandling/ExpectsAndEnsures.hpp"
42 : #include "Utilities/ForceInline.hpp"
43 : #include "Utilities/Literals.hpp"
44 : #include "Utilities/PrettyType.hpp"
45 : #include "Utilities/Requires.hpp"
46 : #include "Utilities/TMPL.hpp"
47 :
48 : #if defined(__clang__) || defined(__GNUC__)
49 :
50 : /*!
51 : * \ingroup UtilitiesGroup
52 : * The if statement is expected to evaluate true most of the time
53 : */
54 : #define LIKELY(x) __builtin_expect(!!(x), 1)
55 :
56 : /*!
57 : * \ingroup UtilitiesGroup
58 : * The if statement is expected to evaluate false most of the time
59 : */
60 : #define UNLIKELY(x) __builtin_expect(!!(x), 0)
61 :
62 : #else
63 : /*!
64 : * \ingroup UtilitiesGroup
65 : * The if statement is expected to evaluate true most of the time
66 : */
67 1 : #define LIKELY(x) (x)
68 :
69 : /*!
70 : * \ingroup UtilitiesGroup
71 : * The if statement is expected to evaluate false most of the time
72 : */
73 1 : #define UNLIKELY(x) (x)
74 : #endif
75 :
76 : /*!
77 : * \ingroup UtilitiesGroup
78 : * \brief Implementations from the Guideline Support Library
79 : */
80 1 : namespace gsl {
81 :
82 : /*!
83 : * \ingroup UtilitiesGroup
84 : * \brief Cast `u` to a type `T` where the cast may result in narrowing
85 : */
86 : template <class T, class U>
87 1 : SPECTRE_ALWAYS_INLINE constexpr T narrow_cast(U&& u) {
88 : return static_cast<T>(std::forward<U>(u));
89 : }
90 :
91 : namespace gsl_detail {
92 : template <class T, class U>
93 : struct is_same_signedness
94 : : public std::integral_constant<bool, std::is_signed<T>::value ==
95 : std::is_signed<U>::value> {};
96 : } // namespace gsl_detail
97 :
98 : /*!
99 : * \ingroup UtilitiesGroup
100 : * \brief A checked version of narrow_cast() that ERRORs if the cast changed
101 : * the value
102 : */
103 : template <class T, class U>
104 1 : SPECTRE_ALWAYS_INLINE T narrow(U u) {
105 : T t = narrow_cast<T>(u);
106 : if (static_cast<U>(t) != u) {
107 : ERROR("Failed to cast " << u << " of type " << pretty_type::get_name<U>()
108 : << " to type " << pretty_type::get_name<T>());
109 : }
110 : if (not gsl_detail::is_same_signedness<T, U>::value and
111 : ((t < T{}) != (u < U{}))) {
112 : ERROR("Failed to cast " << u << " of type " << pretty_type::get_name<U>()
113 : << " to type " << pretty_type::get_name<T>());
114 : }
115 : return t;
116 : }
117 :
118 : /// @{
119 : /*!
120 : * \ingroup UtilitiesGroup
121 : * \brief Retrieve a entry from a container, with checks in Debug mode that
122 : * the index being retrieved is valid.
123 : */
124 : template <class T, std::size_t N, typename Size>
125 1 : SPECTRE_ALWAYS_INLINE constexpr T& at(std::array<T, N>& arr, Size index) {
126 : Expects(index >= 0 and index < narrow_cast<Size>(N));
127 : return arr[static_cast<std::size_t>(index)];
128 : }
129 :
130 : template <class Cont, typename Size>
131 1 : SPECTRE_ALWAYS_INLINE constexpr const typename Cont::value_type& at(
132 : const Cont& cont, Size index) {
133 : Expects(index >= 0 and index < narrow_cast<Size>(cont.size()));
134 : return cont[static_cast<typename Cont::size_type>(index)];
135 : }
136 :
137 : template <class T, typename Size>
138 1 : SPECTRE_ALWAYS_INLINE constexpr const T& at(std::initializer_list<T> cont,
139 : Size index) {
140 : Expects(index >= 0 and index < narrow_cast<Size>(cont.size()));
141 : return *(cont.begin() + index);
142 : }
143 : /// @}
144 :
145 : namespace detail {
146 : template <class T>
147 : struct owner_impl {
148 : static_assert(std::is_same<T, const owner_impl<int*>&>::value,
149 : "You should not have an owning raw pointer, instead you should "
150 : "use std::unique_ptr or, sparingly, std::shared_ptr. If "
151 : "clang-tidy told you to use gsl::owner, then you should still "
152 : "use std::unique_ptr instead.");
153 : using type = T;
154 : };
155 : } // namespace detail
156 :
157 : /*!
158 : * \ingroup UtilitiesGroup
159 : * \brief Mark a raw pointer as owning its data
160 : *
161 : * \warning You should never actually use `gsl::owner`. Instead you should use
162 : * `std::unique_ptr`, and if shared ownership is required, `std::shared_ptr`.
163 : */
164 : template <class T, Requires<std::is_pointer<T>::value> = nullptr>
165 1 : using owner = typename detail::owner_impl<T>::type;
166 :
167 : /*!
168 : * \ingroup UtilitiesGroup
169 : * \brief Require a pointer to not be a `nullptr`
170 : *
171 : * Restricts a pointer or smart pointer to only hold non-null values.
172 : *
173 : * Has zero size overhead over `T`.
174 : *
175 : * If `T` is a pointer (i.e. `T == U*`) then
176 : * - allow construction from `U*`
177 : * - disallow construction from `nullptr_t`
178 : * - disallow default construction
179 : * - ensure construction from null `U*` fails
180 : * - allow implicit conversion to `U*`
181 : */
182 : template <class T>
183 1 : class not_null {
184 : public:
185 : static_assert(std::is_assignable<T&, std::nullptr_t>::value,
186 : "T cannot be assigned nullptr.");
187 :
188 : template <typename U, Requires<std::is_convertible<U, T>::value> = nullptr>
189 0 : constexpr not_null(U&& u) : ptr_(std::forward<U>(u)) {
190 : Expects(ptr_ != nullptr);
191 : }
192 :
193 : template <typename U, Requires<std::is_convertible<U, T>::value> = nullptr>
194 0 : constexpr not_null(const not_null<U>& other) : not_null(other.get()) {}
195 :
196 0 : not_null(const not_null& other) = default;
197 0 : not_null& operator=(const not_null& other) = default;
198 :
199 0 : constexpr T get() const {
200 : Ensures(ptr_ != nullptr);
201 : return ptr_;
202 : }
203 :
204 0 : constexpr operator T() const { return get(); }
205 0 : constexpr T operator->() const { return get(); }
206 0 : constexpr decltype(auto) operator*() const { return *get(); }
207 :
208 : // prevents compilation when someone attempts to assign a null pointer
209 : // constant
210 0 : not_null(std::nullptr_t) = delete;
211 0 : not_null& operator=(std::nullptr_t) = delete;
212 :
213 : // unwanted operators...pointers only point to single objects!
214 0 : not_null& operator++() = delete;
215 0 : not_null& operator--() = delete;
216 0 : not_null operator++(int) = delete;
217 0 : not_null operator--(int) = delete;
218 0 : not_null& operator+=(std::ptrdiff_t) = delete;
219 0 : not_null& operator-=(std::ptrdiff_t) = delete;
220 0 : void operator[](std::ptrdiff_t) const = delete;
221 :
222 : private:
223 0 : T ptr_;
224 : };
225 :
226 : template <class T>
227 0 : std::ostream& operator<<(std::ostream& os, const not_null<T>& val) {
228 : os << val.get();
229 : return os;
230 : }
231 :
232 : template <class T, class U>
233 0 : auto operator==(const not_null<T>& lhs, const not_null<U>& rhs)
234 : -> decltype(lhs.get() == rhs.get()) {
235 : return lhs.get() == rhs.get();
236 : }
237 :
238 : template <class T, class U>
239 0 : auto operator!=(const not_null<T>& lhs, const not_null<U>& rhs)
240 : -> decltype(lhs.get() != rhs.get()) {
241 : return lhs.get() != rhs.get();
242 : }
243 :
244 : template <class T, class U>
245 0 : auto operator<(const not_null<T>& lhs, const not_null<U>& rhs)
246 : -> decltype(lhs.get() < rhs.get()) {
247 : return lhs.get() < rhs.get();
248 : }
249 :
250 : template <class T, class U>
251 0 : auto operator<=(const not_null<T>& lhs, const not_null<U>& rhs)
252 : -> decltype(lhs.get() <= rhs.get()) {
253 : return lhs.get() <= rhs.get();
254 : }
255 :
256 : template <class T, class U>
257 0 : auto operator>(const not_null<T>& lhs, const not_null<U>& rhs)
258 : -> decltype(lhs.get() > rhs.get()) {
259 : return lhs.get() > rhs.get();
260 : }
261 :
262 : template <class T, class U>
263 0 : auto operator>=(const not_null<T>& lhs, const not_null<U>& rhs)
264 : -> decltype(lhs.get() >= rhs.get()) {
265 : return lhs.get() >= rhs.get();
266 : }
267 :
268 : // more unwanted operators
269 : template <class T, class U>
270 0 : std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
271 : template <class T>
272 0 : not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
273 : template <class T>
274 0 : not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
275 : template <class T>
276 0 : not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
277 :
278 : // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
279 : // While there is a conversion from signed to unsigned, it happens at
280 : // compile time, so the compiler wouldn't have to warn indiscriminently, but
281 : // could check if the source value actually doesn't fit into the target type
282 : // and only warn in those cases.
283 : #if __GNUC__ > 6
284 : #pragma GCC diagnostic push
285 : #pragma GCC diagnostic ignored "-Wsign-conversion"
286 : #endif // __GNUC__ > 6
287 :
288 : // [views.constants], constants
289 0 : constexpr const std::ptrdiff_t dynamic_extent = -1;
290 :
291 : template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
292 : class span;
293 :
294 : // implementation details
295 : namespace detail {
296 : template <class T>
297 : struct is_span_oracle : std::false_type {};
298 :
299 : template <class ElementType, std::ptrdiff_t Extent>
300 : struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type {};
301 :
302 : template <class T>
303 : struct is_span : public is_span_oracle<std::remove_cv_t<T>> {};
304 :
305 : template <class T>
306 : struct is_std_array_oracle : std::false_type {};
307 :
308 : template <class ElementType, std::size_t Extent>
309 : struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type {};
310 :
311 : template <class T>
312 : struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>> {};
313 :
314 : template <std::ptrdiff_t From, std::ptrdiff_t To>
315 : struct is_allowed_extent_conversion
316 : : public std::integral_constant<bool, From == To ||
317 : From == gsl::dynamic_extent ||
318 : To == gsl::dynamic_extent> {};
319 :
320 : template <class From, class To>
321 : struct is_allowed_element_type_conversion
322 : : public std::integral_constant<
323 : bool, std::is_convertible<From (*)[], To (*)[]>::value> {};
324 :
325 : template <class Span, bool IsConst>
326 : class span_iterator {
327 : using element_type_ = typename Span::element_type;
328 :
329 : public:
330 : using iterator_category = std::random_access_iterator_tag;
331 : using value_type = std::remove_cv_t<element_type_>;
332 : using difference_type = typename Span::index_type;
333 :
334 : using reference =
335 : tmpl::conditional_t<IsConst, const element_type_, element_type_>&;
336 : using pointer = std::add_pointer_t<reference>;
337 :
338 : span_iterator() = default;
339 :
340 : constexpr span_iterator(const Span* span, typename Span::index_type idx)
341 : : span_(span), index_(idx) {}
342 :
343 : friend span_iterator<Span, true>;
344 : template <bool B, Requires<!B && IsConst> = nullptr>
345 : constexpr span_iterator(const span_iterator<Span, B>& other)
346 : : span_iterator(other.span_, other.index_) {}
347 :
348 : constexpr reference operator*() const {
349 : Expects(index_ != span_->size());
350 : return *(span_->data() + index_);
351 : }
352 :
353 : constexpr pointer operator->() const {
354 : Expects(index_ != span_->size());
355 : return span_->data() + index_;
356 : }
357 :
358 : constexpr span_iterator& operator++() {
359 : Expects(0 <= index_ && index_ != span_->size());
360 : ++index_;
361 : return *this;
362 : }
363 :
364 : constexpr span_iterator operator++(int) {
365 : auto ret = *this;
366 : ++(*this);
367 : return ret;
368 : }
369 :
370 : constexpr span_iterator& operator--() {
371 : Expects(index_ != 0 && index_ <= span_->size());
372 : --index_;
373 : return *this;
374 : }
375 :
376 : constexpr span_iterator operator--(int) {
377 : auto ret = *this;
378 : --(*this);
379 : return ret;
380 : }
381 :
382 : constexpr span_iterator operator+(difference_type n) const {
383 : auto ret = *this;
384 : return ret += n;
385 : }
386 :
387 : friend constexpr span_iterator operator+(difference_type n,
388 : span_iterator const& rhs) {
389 : return rhs + n;
390 : }
391 :
392 : constexpr span_iterator& operator+=(difference_type n) {
393 : Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
394 : index_ += n;
395 : return *this;
396 : }
397 :
398 : constexpr span_iterator operator-(difference_type n) const {
399 : auto ret = *this;
400 : return ret -= n;
401 : }
402 :
403 : constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }
404 :
405 : constexpr difference_type operator-(span_iterator rhs) const {
406 : Expects(span_ == rhs.span_);
407 : return index_ - rhs.index_;
408 : }
409 :
410 : constexpr reference operator[](difference_type n) const {
411 : return *(*this + n);
412 : }
413 :
414 : constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) {
415 : return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
416 : }
417 :
418 : constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) {
419 : return !(lhs == rhs);
420 : }
421 :
422 : constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) {
423 : return lhs.index_ < rhs.index_;
424 : }
425 :
426 : constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) {
427 : return !(rhs < lhs);
428 : }
429 :
430 : constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) {
431 : return rhs < lhs;
432 : }
433 :
434 : constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) {
435 : return !(rhs > lhs);
436 : }
437 :
438 : protected:
439 : const Span* span_ = nullptr;
440 : std::ptrdiff_t index_ = 0;
441 : };
442 :
443 : template <std::ptrdiff_t Ext>
444 : class extent_type {
445 : public:
446 : using index_type = std::ptrdiff_t;
447 :
448 : static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
449 :
450 : constexpr extent_type() {}
451 :
452 : template <index_type Other>
453 : constexpr extent_type(extent_type<Other> ext) {
454 : static_assert(
455 : Other == Ext || Other == dynamic_extent,
456 : "Mismatch between fixed-size extent and size of initializing data.");
457 : Expects(ext.size() == Ext);
458 : }
459 :
460 : constexpr extent_type(index_type size) { Expects(size == Ext); }
461 :
462 : constexpr index_type size() const { return Ext; }
463 : };
464 :
465 : template <>
466 : class extent_type<dynamic_extent> {
467 : public:
468 : using index_type = std::ptrdiff_t;
469 :
470 : template <index_type Other>
471 : explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) {}
472 :
473 : explicit constexpr extent_type(index_type size) : size_(size) {
474 : Expects(size >= 0);
475 : }
476 :
477 : constexpr index_type size() const { return size_; }
478 :
479 : private:
480 : index_type size_;
481 : };
482 :
483 : template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset,
484 : std::ptrdiff_t Count>
485 : struct calculate_subspan_type {
486 : using type =
487 : span<ElementType,
488 : Count != dynamic_extent
489 : ? Count
490 : : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
491 : };
492 : } // namespace detail
493 :
494 : /*!
495 : * \ingroup UtilitiesGroup
496 : * \brief Create a span/view on a range, which is cheap to copy (one pointer).
497 : */
498 : template <class ElementType, std::ptrdiff_t Extent>
499 1 : class span {
500 : public:
501 : // constants and types
502 0 : using element_type = ElementType;
503 0 : using value_type = std::remove_cv_t<ElementType>;
504 0 : using index_type = size_t;
505 0 : using pointer = element_type*;
506 0 : using reference = element_type&;
507 :
508 0 : using iterator = detail::span_iterator<span<ElementType, Extent>, false>;
509 0 : using const_iterator = detail::span_iterator<span<ElementType, Extent>, true>;
510 0 : using reverse_iterator = std::reverse_iterator<iterator>;
511 0 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
512 :
513 0 : using size_type = index_type;
514 :
515 0 : static constexpr index_type extent{Extent};
516 :
517 : // [span.cons], span constructors, copy, assignment, and destructor
518 : template <bool Dependent = false,
519 : // "Dependent" is needed to make "Requires<Dependent ||
520 : // Extent <= 0>" SFINAE, since "Requires<Extent <= 0>" is
521 : // ill-formed when Extent is greater than 0.
522 : Requires<(Dependent || Extent <= 0)> = nullptr>
523 0 : constexpr span() : storage_(nullptr, detail::extent_type<0>()) {}
524 :
525 0 : constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
526 :
527 0 : constexpr span(pointer firstElem, pointer lastElem)
528 : : storage_(firstElem, std::distance(firstElem, lastElem)) {}
529 :
530 : template <std::size_t N>
531 0 : constexpr span(element_type (&arr)[N])
532 : : storage_(KnownNotNull{std::addressof(arr[0])},
533 : detail::extent_type<N>()) {}
534 :
535 : template <std::size_t N, Requires<(N > 0)> = nullptr>
536 0 : constexpr span(std::array<std::remove_const_t<element_type>, N>& arr)
537 : : storage_(KnownNotNull{arr.data()}, detail::extent_type<N>()) {}
538 :
539 0 : constexpr span(std::array<std::remove_const_t<element_type>, 0>&)
540 : : storage_(static_cast<pointer>(nullptr), detail::extent_type<0>()) {}
541 :
542 : template <std::size_t N, Requires<(N > 0)> = nullptr>
543 0 : constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr)
544 : : storage_(KnownNotNull{arr.data()}, detail::extent_type<N>()) {}
545 :
546 0 : constexpr span(const std::array<std::remove_const_t<element_type>, 0>&)
547 : : storage_(static_cast<pointer>(nullptr), detail::extent_type<0>()) {}
548 :
549 : // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the
550 : // requirement on Container to be a contiguous sequence container.
551 : template <
552 : class Container,
553 : Requires<
554 : !detail::is_span<Container>::value &&
555 : !detail::is_std_array<Container>::value &&
556 : std::is_convertible<typename Container::pointer, pointer>::value &&
557 : std::is_convertible<
558 : typename Container::pointer,
559 : decltype(std::declval<Container>().data())>::value> = nullptr>
560 0 : constexpr span(Container& cont)
561 : : span(cont.data(), narrow<index_type>(cont.size())) {}
562 :
563 : template <
564 : class Container,
565 : Requires<
566 : std::is_const<element_type>::value &&
567 : !detail::is_span<Container>::value &&
568 : std::is_convertible<typename Container::pointer, pointer>::value &&
569 : std::is_convertible<
570 : typename Container::pointer,
571 : decltype(std::declval<Container>().data())>::value> = nullptr>
572 0 : constexpr span(const Container& cont)
573 : : span(cont.data(), narrow<index_type>(cont.size())) {}
574 :
575 0 : constexpr span(const span& other) = default;
576 :
577 : template <class OtherElementType, std::ptrdiff_t OtherExtent,
578 : Requires<detail::is_allowed_extent_conversion<OtherExtent,
579 : Extent>::value &&
580 : detail::is_allowed_element_type_conversion<
581 : OtherElementType, element_type>::value> = nullptr>
582 0 : constexpr span(const span<OtherElementType, OtherExtent>& other)
583 : : storage_(other.data(), detail::extent_type<OtherExtent>(other.size())) {
584 : }
585 :
586 0 : ~span() = default;
587 0 : constexpr span& operator=(const span& other) = default;
588 :
589 : // [span.sub], span subviews
590 : template <std::ptrdiff_t Count>
591 0 : constexpr span<element_type, Count> first() const {
592 : Expects(Count >= 0 && Count <= size());
593 : return {data(), Count};
594 : }
595 :
596 : template <std::ptrdiff_t Count>
597 0 : constexpr span<element_type, Count> last() const {
598 : Expects(Count >= 0 && size() - Count >= 0);
599 : return {data() + (size() - Count), Count};
600 : }
601 :
602 : template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
603 0 : constexpr auto subspan() const ->
604 : typename detail::calculate_subspan_type<ElementType, Extent, Offset,
605 : Count>::type {
606 : Expects(
607 : (Offset >= 0 && size() - Offset >= 0) &&
608 : (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
609 :
610 : return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
611 : }
612 :
613 0 : constexpr span<element_type, dynamic_extent> first(index_type count) const {
614 : Expects(count >= 0 && count <= size());
615 : return {data(), count};
616 : }
617 :
618 0 : constexpr span<element_type, dynamic_extent> last(index_type count) const {
619 : return make_subspan(size() - count, dynamic_extent,
620 : subspan_selector<Extent>{});
621 : }
622 :
623 0 : constexpr span<element_type, dynamic_extent> subspan(
624 : index_type offset, index_type count = dynamic_extent) const {
625 : return make_subspan(offset, count, subspan_selector<Extent>{});
626 : }
627 :
628 : // [span.obs], span observers
629 0 : constexpr index_type size() const { return storage_.size(); }
630 0 : constexpr index_type size_bytes() const {
631 : return size() * narrow_cast<index_type>(sizeof(element_type));
632 : }
633 0 : constexpr bool empty() const { return size() == 0; }
634 :
635 : // [span.elem], span element access
636 0 : constexpr reference operator[](index_type idx) const {
637 : Expects(CheckRange(idx, storage_.size()));
638 : return data()[idx];
639 : }
640 :
641 0 : constexpr reference at(index_type idx) const { return this->operator[](idx); }
642 0 : constexpr reference operator()(index_type idx) const {
643 : return this->operator[](idx);
644 : }
645 0 : constexpr pointer data() const { return storage_.data(); }
646 :
647 : // [span.iter], span iterator support
648 0 : constexpr iterator begin() const { return {this, 0}; }
649 0 : constexpr iterator end() const { return {this, size()}; }
650 :
651 0 : constexpr const_iterator cbegin() const { return {this, 0}; }
652 0 : constexpr const_iterator cend() const { return {this, size()}; }
653 :
654 0 : constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; }
655 0 : constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; }
656 :
657 0 : constexpr const_reverse_iterator crbegin() const {
658 : return const_reverse_iterator{cend()};
659 : }
660 0 : constexpr const_reverse_iterator crend() const {
661 : return const_reverse_iterator{cbegin()};
662 : }
663 :
664 : private:
665 0 : static bool CheckRange(index_type idx, index_type size) {
666 : // Optimization:
667 : //
668 : // idx >= 0 && idx < size
669 : // =>
670 : // static_cast<size_t>(idx) < static_cast<size_t>(size)
671 : //
672 : // because size >=0 by span construction, and negative idx will
673 : // wrap around to a value always greater than size when casted.
674 :
675 : // check if we have enough space to wrap around
676 : if (sizeof(index_type) <= sizeof(size_t)) {
677 : return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
678 : } else {
679 : return idx >= 0 && idx < size;
680 : }
681 : }
682 :
683 : // Needed to remove unnecessary null check in subspans
684 0 : struct KnownNotNull {
685 0 : pointer p;
686 : };
687 :
688 : // this implementation detail class lets us take advantage of the
689 : // empty base class optimization to pay for only storage of a single
690 : // pointer in the case of fixed-size spans
691 : template <class ExtentType>
692 0 : class storage_type : public ExtentType {
693 : public:
694 : // KnownNotNull parameter is needed to remove unnecessary null check
695 : // in subspans and constructors from arrays
696 : template <class OtherExtentType>
697 0 : constexpr storage_type(KnownNotNull data, OtherExtentType ext)
698 : : ExtentType(ext), data_(data.p) {
699 : Expects(ExtentType::size() >= 0);
700 : }
701 :
702 : template <class OtherExtentType>
703 0 : constexpr storage_type(pointer data, OtherExtentType ext)
704 : : ExtentType(ext), data_(data) {
705 : Expects(ExtentType::size() >= 0);
706 : Expects(data || ExtentType::size() == 0);
707 : }
708 :
709 0 : constexpr pointer data() const { return data_; }
710 :
711 : private:
712 0 : pointer data_;
713 : };
714 :
715 0 : storage_type<detail::extent_type<Extent>> storage_;
716 :
717 : // The rest is needed to remove unnecessary null check
718 : // in subspans and constructors from arrays
719 0 : constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
720 :
721 : template <std::ptrdiff_t CallerExtent>
722 0 : class subspan_selector {};
723 :
724 : template <std::ptrdiff_t CallerExtent>
725 0 : span<element_type, dynamic_extent> make_subspan(
726 : index_type offset, index_type count,
727 : subspan_selector<CallerExtent>) const {
728 : const span<element_type, dynamic_extent> tmp(*this);
729 : return tmp.subspan(offset, count);
730 : }
731 :
732 0 : span<element_type, dynamic_extent> make_subspan(
733 : index_type offset, index_type count,
734 : subspan_selector<dynamic_extent>) const {
735 : Expects(offset >= 0 && size() - offset >= 0);
736 :
737 : if (count == dynamic_extent) {
738 : return {KnownNotNull{data() + offset}, size() - offset};
739 : }
740 :
741 : Expects(count >= 0 && size() - offset >= count);
742 : return {KnownNotNull{data() + offset}, count};
743 : }
744 : };
745 :
746 : // [span.comparison], span comparison operators
747 : template <class ElementType, std::ptrdiff_t FirstExtent,
748 : std::ptrdiff_t SecondExtent>
749 0 : constexpr bool operator==(span<ElementType, FirstExtent> l,
750 : span<ElementType, SecondExtent> r) {
751 : return std::equal(l.begin(), l.end(), r.begin(), r.end());
752 : }
753 :
754 : template <class ElementType, std::ptrdiff_t Extent>
755 0 : constexpr bool operator!=(span<ElementType, Extent> l,
756 : span<ElementType, Extent> r) {
757 : return !(l == r);
758 : }
759 :
760 : template <class ElementType, std::ptrdiff_t Extent>
761 0 : constexpr bool operator<(span<ElementType, Extent> l,
762 : span<ElementType, Extent> r) {
763 : return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
764 : }
765 :
766 : template <class ElementType, std::ptrdiff_t Extent>
767 0 : constexpr bool operator<=(span<ElementType, Extent> l,
768 : span<ElementType, Extent> r) {
769 : return !(l > r);
770 : }
771 :
772 : template <class ElementType, std::ptrdiff_t Extent>
773 0 : constexpr bool operator>(span<ElementType, Extent> l,
774 : span<ElementType, Extent> r) {
775 : return r < l;
776 : }
777 :
778 : template <class ElementType, std::ptrdiff_t Extent>
779 0 : constexpr bool operator>=(span<ElementType, Extent> l,
780 : span<ElementType, Extent> r) {
781 : return !(l < r);
782 : }
783 :
784 : /// @{
785 : /// \ingroup UtilitiesGroup
786 : /// Utility function for creating spans
787 : template <class ElementType>
788 1 : constexpr span<ElementType> make_span(
789 : ElementType* ptr, typename span<ElementType>::index_type count) {
790 : return span<ElementType>(ptr, count);
791 : }
792 :
793 : template <class ElementType>
794 1 : constexpr span<ElementType> make_span(ElementType* firstElem,
795 : ElementType* lastElem) {
796 : return span<ElementType>(firstElem, lastElem);
797 : }
798 :
799 : template <class ElementType, std::size_t N>
800 1 : constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) {
801 : return span<ElementType, N>(arr);
802 : }
803 :
804 : template <class Container>
805 1 : constexpr span<typename Container::value_type> make_span(Container& cont) {
806 : return span<typename Container::value_type>(cont);
807 : }
808 :
809 : template <class Container>
810 1 : constexpr span<const typename Container::value_type> make_span(
811 : const Container& cont) {
812 : return span<const typename Container::value_type>(cont);
813 : }
814 :
815 : template <class Ptr>
816 1 : constexpr span<typename Ptr::element_type> make_span(Ptr& cont,
817 : std::ptrdiff_t count) {
818 : return span<typename Ptr::element_type>(cont, count);
819 : }
820 :
821 : template <class Ptr>
822 1 : constexpr span<typename Ptr::element_type> make_span(Ptr& cont) {
823 : return span<typename Ptr::element_type>(cont);
824 : }
825 : /// @}
826 :
827 : // Specialization of gsl::at for span
828 : template <class ElementType, std::ptrdiff_t Extent>
829 0 : constexpr ElementType& at(span<ElementType, Extent> s,
830 : typename span<ElementType, Extent>::index_type i) {
831 : // No bounds checking here because it is done in span::operator[] called below
832 : return s[i];
833 : }
834 :
835 : #if __GNUC__ > 6
836 : #pragma GCC diagnostic pop
837 : #endif // __GNUC__ > 6
838 :
839 : template <class ElementType, std::ptrdiff_t Extent>
840 0 : std::ostream& operator<<(std::ostream& os, const span<ElementType, Extent> t) {
841 : os << "(";
842 : auto it = t.cbegin();
843 : if (it != t.cend()) {
844 : os << *it;
845 : ++it;
846 : for (; it != t.cend(); ++it) {
847 : os << ",";
848 : os << *it;
849 : }
850 : }
851 : return os << ")";
852 : }
853 : } // namespace gsl
854 :
855 : // The remainder of this file is
856 : // Distributed under the MIT License.
857 : // See LICENSE.txt for details.
858 :
859 : /// Construct a not_null from a pointer. Often this will be done as
860 : /// an implicit conversion, but it may be necessary to perform the
861 : /// conversion explicitly when type deduction is desired.
862 : ///
863 : /// \note This is not a standard GSL function, and so is not in the
864 : /// gsl namespace.
865 : template <typename T>
866 1 : constexpr gsl::not_null<T*> make_not_null(T* ptr) {
867 : return gsl::not_null<T*>(ptr);
868 : }
|