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