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