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