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