Reference documentation for deal.II version Git d3aed38b93 2021-10-28 13:33:27 +0200
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
array_view.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2004 - 2021 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_array_view_h
17 #define dealii_array_view_h
18 
19 #include <deal.II/base/config.h>
20 
24 #include <deal.II/base/tensor.h>
25 
26 #include <type_traits>
27 #include <vector>
28 
30 
31 // Forward declaration
32 template <int N, typename T>
33 class Table;
34 
35 template <typename number>
37 
38 
80 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
81 class ArrayView
82 {
83 public:
89 
93  using iterator = value_type *;
94 
98  using const_iterator = const ElementType *;
99 
103  ArrayView();
104 
124  ArrayView(value_type *starting_element, const std::size_t n_elements);
125 
135  ArrayView(const ArrayView<typename std::remove_cv<value_type>::type,
136  MemorySpaceType> &view);
137 
142  explicit ArrayView(value_type &element);
143 
158  ArrayView(
159  const std::vector<typename std::remove_cv<value_type>::type> &vector);
160 
175  ArrayView(std::vector<typename std::remove_cv<value_type>::type> &vector);
176 
191  template <std::size_t N>
192  ArrayView(value_type (&array)[N]);
193 
202  template <std::size_t N>
203  ArrayView(
204  const std::array<typename std::remove_cv<value_type>::type, N> &vector);
205 
214  template <std::size_t N>
215  ArrayView(std::array<typename std::remove_cv<value_type>::type, N> &vector);
216 
236  void
237  reinit(value_type *starting_element, const std::size_t n_elements);
238 
244  bool
245  operator==(
246  const ArrayView<const value_type, MemorySpaceType> &other_view) const;
247 
253  bool
254  operator==(const ArrayView<typename std::remove_cv<value_type>::type,
255  MemorySpaceType> &other_view) const;
256 
262  bool
263  operator!=(
264  const ArrayView<const value_type, MemorySpaceType> &other_view) const;
265 
271  bool
272  operator!=(const ArrayView<typename std::remove_cv<value_type>::type,
273  MemorySpaceType> &other_view) const;
274 
279  std::size_t
280  size() const;
281 
286  value_type *
287  data() const noexcept;
288 
292  iterator
293  begin() const;
294 
298  iterator
299  end() const;
300 
305  cbegin() const;
306 
311  cend() const;
312 
325  value_type &
326  operator[](const std::size_t i) const;
327 
328 private:
334 
338  std::size_t n_elements;
339 
340  friend class ArrayView<const ElementType, MemorySpaceType>;
341 };
342 
343 
344 
345 //---------------------------------------------------------------------------
346 
347 
348 namespace internal
349 {
350  namespace ArrayViewHelper
351  {
352  template <typename MemorySpaceType>
353  inline bool
354  is_in_correct_memory_space(const void *const ptr)
355  {
356 #ifndef DEAL_II_COMPILER_CUDA_AWARE
357  (void)ptr;
358  static_assert(std::is_same<MemorySpaceType, MemorySpace::Host>::value,
359  "If the compiler doesn't understand CUDA code, "
360  "the only possible memory space is 'MemorySpace::Host'!");
361  return true;
362 #else
363  cudaPointerAttributes attributes;
364  const cudaError_t cuda_error = cudaPointerGetAttributes(&attributes, ptr);
365  if (cuda_error != cudaErrorInvalidValue)
366  {
367  AssertCuda(cuda_error);
368  if (std::is_same<MemorySpaceType, MemorySpace::Host>::value)
369  return (attributes.type == cudaMemoryTypeHost) ||
370  (attributes.type == cudaMemoryTypeUnregistered);
371  else
372  return attributes.type == cudaMemoryTypeDevice;
373  }
374  else
375  {
376  // ignore and reset the error since host pointers produce an error
377  cudaGetLastError();
378  return std::is_same<MemorySpaceType, MemorySpace::Host>::value;
379  }
380 #endif
381  }
382  } // namespace ArrayViewHelper
383 } // namespace internal
384 
385 
386 
387 template <typename ElementType, typename MemorySpaceType>
389  : starting_element(nullptr)
390  , n_elements(0)
391 {}
392 
393 
394 
395 template <typename ElementType, typename MemorySpaceType>
398  const std::size_t n_elements)
399  : starting_element(starting_element)
400  , n_elements(n_elements)
401 {
402  Assert(
403  n_elements == 0 ||
404  internal::ArrayViewHelper::is_in_correct_memory_space<MemorySpaceType>(
405  starting_element),
406  ExcMessage("The memory space indicated by the template parameter "
407  "and the one derived from the pointer value do not match!"));
408 }
409 
410 
411 
412 template <typename ElementType, typename MemorySpaceType>
413 inline void
415  const std::size_t n_elements)
416 {
417  *this = ArrayView(starting_element, n_elements);
418 }
419 
420 
421 
422 template <typename ElementType, typename MemorySpaceType>
424  : starting_element(&element)
425  , n_elements(1)
426 {}
427 
428 
429 
430 template <typename ElementType, typename MemorySpaceType>
432  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
433  &view)
435  , n_elements(view.n_elements)
436 {}
437 
438 
439 
440 template <typename ElementType, typename MemorySpaceType>
442  const std::vector<typename std::remove_cv<value_type>::type> &vector)
443  : // use delegating constructor
444  ArrayView(vector.data(), vector.size())
445 {
446  // the following static_assert is not strictly necessary because,
447  // if we got a const std::vector reference argument but ElementType
448  // is not itself const, then the call to the forwarding constructor
449  // above will already have failed: vector.data() will have returned
450  // a const pointer, but we need a non-const pointer.
451  //
452  // nevertheless, leave the static_assert in since it provides a
453  // more descriptive error message that will simply come after the first
454  // error produced above
455  static_assert(std::is_const<value_type>::value == true,
456  "This constructor may only be called if the ArrayView "
457  "object has a const value_type. In other words, you can "
458  "only create an ArrayView to const values from a const "
459  "std::vector.");
460 }
461 
462 
463 
464 template <typename ElementType, typename MemorySpaceType>
466  std::vector<typename std::remove_cv<value_type>::type> &vector)
467  : // use delegating constructor
468  ArrayView(vector.data(), vector.size())
469 {}
470 
471 
472 
473 template <typename ElementType, typename MemorySpaceType>
474 template <std::size_t N>
476  const std::array<typename std::remove_cv<value_type>::type, N> &vector)
477  : // use delegating constructor
478  ArrayView(vector.data(), vector.size())
479 {
480  // the following static_assert is not strictly necessary because,
481  // if we got a const std::array reference argument but ElementType
482  // is not itself const, then the call to the forwarding constructor
483  // above will already have failed: vector.data() will have returned
484  // a const pointer, but we need a non-const pointer.
485  //
486  // nevertheless, leave the static_assert in since it provides a
487  // more descriptive error message that will simply come after the first
488  // error produced above
489  static_assert(std::is_const<value_type>::value == true,
490  "This constructor may only be called if the ArrayView "
491  "object has a const value_type. In other words, you can "
492  "only create an ArrayView to const values from a const "
493  "std::array.");
494 }
495 
496 
497 
498 template <typename ElementType, typename MemorySpaceType>
499 template <std::size_t N>
501  ElementType (&array)[N])
502  : ArrayView(&array[0], N)
503 {}
504 
505 
506 
507 template <typename ElementType, typename MemorySpaceType>
508 template <std::size_t N>
510  std::array<typename std::remove_cv<value_type>::type, N> &vector)
511  : // use delegating constructor
512  ArrayView(vector.data(), vector.size())
513 {}
514 
515 
516 
517 template <typename ElementType, typename MemorySpaceType>
518 inline bool
520  const ArrayView<const value_type, MemorySpaceType> &other_view) const
521 {
522  return (other_view.data() == starting_element) &&
523  (other_view.size() == n_elements);
524 }
525 
526 
527 
528 template <typename ElementType, typename MemorySpaceType>
529 inline bool
531  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
532  &other_view) const
533 {
534  return (other_view.data() == starting_element) &&
535  (other_view.size() == n_elements);
536 }
537 
538 
539 
540 template <typename ElementType, typename MemorySpaceType>
541 inline bool
543  const ArrayView<const value_type, MemorySpaceType> &other_view) const
544 {
545  return !(*this == other_view);
546 }
547 
548 
549 
550 template <typename ElementType, typename MemorySpaceType>
553 {
554  if (n_elements == 0)
555  return nullptr;
556  else
557  return starting_element;
558 }
559 
560 
561 
562 template <typename ElementType, typename MemorySpaceType>
563 inline bool
565  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
566  &other_view) const
567 {
568  return !(*this == other_view);
569 }
570 
571 
572 
573 template <typename ElementType, typename MemorySpaceType>
574 inline std::size_t
576 {
577  return n_elements;
578 }
579 
580 
581 
582 template <typename ElementType, typename MemorySpaceType>
585 {
586  return starting_element;
587 }
588 
589 
590 
591 template <typename ElementType, typename MemorySpaceType>
594 {
595  return starting_element + n_elements;
596 }
597 
598 
599 
600 template <typename ElementType, typename MemorySpaceType>
603 {
604  return starting_element;
605 }
606 
607 
608 
609 template <typename ElementType, typename MemorySpaceType>
612 {
613  return starting_element + n_elements;
614 }
615 
616 
617 
618 template <typename ElementType, typename MemorySpaceType>
621 {
623  Assert(
624  (std::is_same<MemorySpaceType, MemorySpace::Host>::value),
625  ExcMessage(
626  "Accessing elements is only allowed if the data is stored in CPU memory!"));
627 
628  return *(starting_element + i);
629 }
630 
631 
632 
633 #ifndef DOXYGEN
634 namespace internal
635 {
636  namespace ArrayViewHelper
637  {
643  template <class Iterator>
644  bool
645  is_contiguous(const Iterator &first, const Iterator &last)
646  {
647  const auto n = std::distance(first, last);
648  for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
649  if (std::addressof(*(std::next(first, i))) !=
650  std::next(std::addressof(*first), i))
651  return false;
652  return true;
653  }
654 
655 
666  template <class T>
667  constexpr bool
668  is_contiguous(T *, T *)
669  {
670  return true;
671  }
672  } // namespace ArrayViewHelper
673 } // namespace internal
674 #endif
675 
676 
677 
694 template <typename Iterator, typename MemorySpaceType = MemorySpace::Host>
695 ArrayView<typename std::remove_reference<
696  typename std::iterator_traits<Iterator>::reference>::type,
697  MemorySpaceType>
698 make_array_view(const Iterator begin, const Iterator end)
699 {
700  static_assert(
701  std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
702  typename std::random_access_iterator_tag>::value,
703  "The provided iterator should be a random access iterator.");
704  Assert(begin <= end,
705  ExcMessage(
706  "The beginning of the array view should be before the end."));
707  Assert(internal::ArrayViewHelper::is_contiguous(begin, end),
708  ExcMessage("The provided range isn't contiguous in memory!"));
709  // the reference type, not the value type, knows the constness of the iterator
710  return ArrayView<typename std::remove_reference<
711  typename std::iterator_traits<Iterator>::reference>::type,
712  MemorySpaceType>(std::addressof(*begin), end - begin);
713 }
714 
715 
716 
726 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
729 {
730  Assert(begin <= end,
731  ExcMessage(
732  "The beginning of the array view should be before the end."));
734 }
735 
736 
737 
748 template <typename Number, typename MemorySpaceType>
751 {
752  return make_array_view(array_view.cbegin(), array_view.cend());
753 }
754 
755 
756 
767 template <typename Number, typename MemorySpaceType>
770 {
771  return make_array_view(array_view.begin(), array_view.end());
772 }
773 
774 
775 
797 template <int rank, int dim, typename Number>
798 DEAL_II_DEPRECATED_EARLY inline ArrayView<const Number>
800 {
801  return make_array_view(tensor.begin_raw(), tensor.end_raw());
802 }
803 
804 
805 
827 template <int rank, int dim, typename Number>
828 DEAL_II_DEPRECATED_EARLY inline ArrayView<Number>
830 {
831  return make_array_view(tensor.begin_raw(), tensor.end_raw());
832 }
833 
834 
835 
857 template <int rank, int dim, typename Number>
858 DEAL_II_DEPRECATED_EARLY inline ArrayView<const Number>
860 {
861  return make_array_view(tensor.begin_raw(), tensor.end_raw());
862 }
863 
864 
865 
888 template <int rank, int dim, typename Number>
889 DEAL_II_DEPRECATED_EARLY inline ArrayView<Number>
891 {
892  return make_array_view(tensor.begin_raw(), tensor.end_raw());
893 }
894 
895 
896 
910 template <typename ElementType, int N>
912 {
913  return ArrayView<ElementType>(array, N);
914 }
915 
916 
917 
932 template <typename ElementType>
934 make_array_view(Vector<ElementType> &vector)
935 {
936  return ArrayView<ElementType>(vector.begin(), vector.size());
937 }
938 
939 
940 
955 template <typename ElementType>
957 make_array_view(const Vector<ElementType> &vector)
958 {
959  return ArrayView<const ElementType>(vector.begin(), vector.size());
960 }
961 
962 
963 
978 template <typename ElementType>
980 make_array_view(std::vector<ElementType> &vector)
981 {
982  return ArrayView<ElementType>(vector.data(), vector.size());
983 }
984 
985 
986 
1001 template <typename ElementType>
1003 make_array_view(const std::vector<ElementType> &vector)
1004 {
1005  return ArrayView<const ElementType>(vector.data(), vector.size());
1006 }
1007 
1008 
1009 
1029 template <typename ElementType>
1031 make_array_view(std::vector<ElementType> &vector,
1032  const std::size_t starting_index,
1033  const std::size_t size_of_view)
1034 {
1035  Assert(starting_index + size_of_view <= vector.size(),
1036  ExcMessage("The starting index and size of the view you want to "
1037  "create would lead to a view that extends beyond the end "
1038  "of the given vector."));
1039  return ArrayView<ElementType>(&vector[starting_index], size_of_view);
1040 }
1041 
1042 
1043 
1063 template <typename ElementType>
1065 make_array_view(const std::vector<ElementType> &vector,
1066  const std::size_t starting_index,
1067  const std::size_t size_of_view)
1068 {
1069  Assert(starting_index + size_of_view <= vector.size(),
1070  ExcMessage("The starting index and size of the view you want to "
1071  "create would lead to a view that extends beyond the end "
1072  "of the given vector."));
1073  return ArrayView<const ElementType>(&vector[starting_index], size_of_view);
1074 }
1075 
1076 
1077 
1094 template <typename ElementType>
1097  const typename Table<2, ElementType>::size_type row)
1098 {
1099  AssertIndexRange(row, table.size()[0]);
1100  return ArrayView<ElementType>(&table[row][0], table.size()[1]);
1101 }
1102 
1103 
1104 
1121 template <typename ElementType>
1124 {
1125  return ArrayView<ElementType>(&table[0][0], table.n_elements());
1126 }
1127 
1128 
1129 
1146 template <typename ElementType>
1149 {
1150  return ArrayView<const ElementType>(&table[0][0], table.n_elements());
1151 }
1152 
1153 
1171 template <typename ElementType>
1174 {
1175  return ArrayView<ElementType>(&matrix(0, 0), matrix.n_elements());
1176 }
1177 
1178 
1179 
1196 template <typename ElementType>
1199 {
1200  return ArrayView<const ElementType>(&matrix(0, 0), matrix.n_elements());
1201 }
1202 
1203 
1204 
1221 template <typename ElementType>
1224  const typename Table<2, ElementType>::size_type row)
1225 {
1226  AssertIndexRange(row, table.size()[0]);
1227  return ArrayView<const ElementType>(&table[row][0], table.size()[1]);
1228 }
1229 
1230 
1231 
1251 template <typename ElementType>
1254  const typename Table<2, ElementType>::size_type row,
1255  const typename Table<2, ElementType>::size_type starting_column,
1256  const std::size_t size_of_view)
1257 {
1258  AssertIndexRange(row, table.size()[0]);
1259  AssertIndexRange(starting_column, table.size()[1]);
1260  Assert(starting_column + size_of_view <= table.size()[1],
1261  ExcMessage("The starting index and size of the view you want to "
1262  "create would lead to a view that extends beyond the end "
1263  "of a column of the given table."));
1264  return ArrayView<ElementType>(&table[row][starting_column], size_of_view);
1265 }
1266 
1267 
1268 
1288 template <typename ElementType>
1291  const typename Table<2, ElementType>::size_type row,
1292  const typename Table<2, ElementType>::size_type starting_column,
1293  const std::size_t size_of_view)
1294 {
1295  AssertIndexRange(row, table.size()[0]);
1296  AssertIndexRange(starting_column, table.size()[1]);
1297  Assert(starting_column + size_of_view <= table.size()[1],
1298  ExcMessage("The starting index and size of the view you want to "
1299  "create would lead to a view that extends beyond the end "
1300  "of a column of the given table."));
1301  return ArrayView<const ElementType>(&table[row][starting_column],
1302  size_of_view);
1303 }
1304 
1305 
1306 
1307 /*
1308  * Create a view that doesn't allow the container it points to to be modified.
1309  * This is useful if the object passed in is not `const` already and a function
1310  * requires a view to constant memory in its signature.
1311  *
1312  * This function returns an object of type `ArrayView<const T>` where `T` is the
1313  * element type of the container.
1314  *
1315  * @relatesalso ArrayView
1316  */
1317 template <typename Container>
1318 inline auto
1319 make_const_array_view(const Container &container)
1320  -> decltype(make_array_view(container))
1321 {
1322  return make_array_view(container);
1323 }
1324 
1325 
1327 
1328 #endif
bool is_in_correct_memory_space(const void *const ptr)
Definition: array_view.h:354
Number * begin_raw()
auto make_const_array_view(const Container &container) -> decltype(make_array_view(container))
Definition: array_view.h:1319
Contents is actually a matrix.
const_iterator cbegin() const
Definition: array_view.h:602
iterator end() const
Definition: array_view.h:593
#define AssertIndexRange(index, range)
Definition: exceptions.h:1720
STL namespace.
size_type n_elements() const
bool operator==(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:519
std::size_t size() const
Definition: array_view.h:575
std::size_t n_elements
Definition: array_view.h:338
const const Number * const_iterator
Definition: array_view.h:98
Number * end_raw()
static ::ExceptionBase & ExcMessage(std::string arg1)
value_type & operator[](const std::size_t i) const
Definition: array_view.h:620
static const char T
void reinit(value_type *starting_element, const std::size_t n_elements)
Definition: array_view.h:414
Number * begin_raw()
const Number value_type
Definition: array_view.h:88
#define Assert(cond, exc)
Definition: exceptions.h:1461
#define AssertCuda(error_code)
Definition: exceptions.h:1804
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:401
Number * end_raw()
value_type * data() const noexcept
Definition: array_view.h:552
Point< 2 > first
Definition: grid_out.cc:4586
bool operator!=(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:542
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:400
static const char N
value_type * starting_element
Definition: array_view.h:333
ArrayView< typename std::remove_reference< typename std::iterator_traits< Iterator >::reference >::type, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
Definition: array_view.h:698
iterator begin() const
Definition: array_view.h:584
const_iterator cend() const
Definition: array_view.h:611