Reference documentation for deal.II version 9.3.0
\(\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 &operator[](const std::size_t i) const;
326 
327 private:
333 
337  std::size_t n_elements;
338 
339  friend class ArrayView<const ElementType, MemorySpaceType>;
340 };
341 
342 
343 
344 //---------------------------------------------------------------------------
345 
346 
347 namespace internal
348 {
349  namespace ArrayViewHelper
350  {
351  template <typename MemorySpaceType>
352  inline bool
353  is_in_correct_memory_space(const void *const ptr)
354  {
355 #ifndef DEAL_II_COMPILER_CUDA_AWARE
356  (void)ptr;
357  static_assert(std::is_same<MemorySpaceType, MemorySpace::Host>::value,
358  "If the compiler doesn't understand CUDA code, "
359  "the only possible memory space is 'MemorySpace::Host'!");
360  return true;
361 #else
362  cudaPointerAttributes attributes;
363  const cudaError_t cuda_error = cudaPointerGetAttributes(&attributes, ptr);
364  if (cuda_error != cudaErrorInvalidValue)
365  {
366  AssertCuda(cuda_error);
367  if (std::is_same<MemorySpaceType, MemorySpace::Host>::value)
368  return (attributes.type == cudaMemoryTypeHost) ||
369  (attributes.type == cudaMemoryTypeUnregistered);
370  else
371  return attributes.type == cudaMemoryTypeDevice;
372  }
373  else
374  {
375  // ignore and reset the error since host pointers produce an error
376  cudaGetLastError();
377  return std::is_same<MemorySpaceType, MemorySpace::Host>::value;
378  }
379 #endif
380  }
381  } // namespace ArrayViewHelper
382 } // namespace internal
383 
384 
385 
386 template <typename ElementType, typename MemorySpaceType>
388  : starting_element(nullptr)
389  , n_elements(0)
390 {}
391 
392 
393 
394 template <typename ElementType, typename MemorySpaceType>
397  const std::size_t n_elements)
398  : starting_element(starting_element)
399  , n_elements(n_elements)
400 {
401  Assert(
402  n_elements == 0 ||
403  internal::ArrayViewHelper::is_in_correct_memory_space<MemorySpaceType>(
404  starting_element),
405  ExcMessage("The memory space indicated by the template parameter "
406  "and the one derived from the pointer value do not match!"));
407 }
408 
409 
410 
411 template <typename ElementType, typename MemorySpaceType>
412 inline void
414  const std::size_t n_elements)
415 {
416  *this = ArrayView(starting_element, n_elements);
417 }
418 
419 
420 
421 template <typename ElementType, typename MemorySpaceType>
423  : starting_element(&element)
424  , n_elements(1)
425 {}
426 
427 
428 
429 template <typename ElementType, typename MemorySpaceType>
431  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
432  &view)
434  , n_elements(view.n_elements)
435 {}
436 
437 
438 
439 template <typename ElementType, typename MemorySpaceType>
441  const std::vector<typename std::remove_cv<value_type>::type> &vector)
442  : // use delegating constructor
443  ArrayView(vector.data(), vector.size())
444 {
445  // the following static_assert is not strictly necessary because,
446  // if we got a const std::vector reference argument but ElementType
447  // is not itself const, then the call to the forwarding constructor
448  // above will already have failed: vector.data() will have returned
449  // a const pointer, but we need a non-const pointer.
450  //
451  // nevertheless, leave the static_assert in since it provides a
452  // more descriptive error message that will simply come after the first
453  // error produced above
454  static_assert(std::is_const<value_type>::value == true,
455  "This constructor may only be called if the ArrayView "
456  "object has a const value_type. In other words, you can "
457  "only create an ArrayView to const values from a const "
458  "std::vector.");
459 }
460 
461 
462 
463 template <typename ElementType, typename MemorySpaceType>
465  std::vector<typename std::remove_cv<value_type>::type> &vector)
466  : // use delegating constructor
467  ArrayView(vector.data(), vector.size())
468 {}
469 
470 
471 
472 template <typename ElementType, typename MemorySpaceType>
473 template <std::size_t N>
475  const std::array<typename std::remove_cv<value_type>::type, N> &vector)
476  : // use delegating constructor
477  ArrayView(vector.data(), vector.size())
478 {
479  // the following static_assert is not strictly necessary because,
480  // if we got a const std::array reference argument but ElementType
481  // is not itself const, then the call to the forwarding constructor
482  // above will already have failed: vector.data() will have returned
483  // a const pointer, but we need a non-const pointer.
484  //
485  // nevertheless, leave the static_assert in since it provides a
486  // more descriptive error message that will simply come after the first
487  // error produced above
488  static_assert(std::is_const<value_type>::value == true,
489  "This constructor may only be called if the ArrayView "
490  "object has a const value_type. In other words, you can "
491  "only create an ArrayView to const values from a const "
492  "std::array.");
493 }
494 
495 
496 
497 template <typename ElementType, typename MemorySpaceType>
498 template <std::size_t N>
500  ElementType (&array)[N])
501  : ArrayView(&array[0], N)
502 {}
503 
504 
505 
506 template <typename ElementType, typename MemorySpaceType>
507 template <std::size_t N>
509  std::array<typename std::remove_cv<value_type>::type, N> &vector)
510  : // use delegating constructor
511  ArrayView(vector.data(), vector.size())
512 {}
513 
514 
515 
516 template <typename ElementType, typename MemorySpaceType>
517 inline bool
520 {
521  return (other_view.data() == starting_element) &&
522  (other_view.size() == n_elements);
523 }
524 
525 
526 
527 template <typename ElementType, typename MemorySpaceType>
528 inline bool
530 operator==(const ArrayView<typename std::remove_cv<value_type>::type,
531  MemorySpaceType> &other_view) const
532 {
533  return (other_view.data() == starting_element) &&
534  (other_view.size() == n_elements);
535 }
536 
537 
538 
539 template <typename ElementType, typename MemorySpaceType>
540 inline bool
543 {
544  return !(*this == other_view);
545 }
546 
547 
548 
549 template <typename ElementType, typename MemorySpaceType>
552 {
553  if (n_elements == 0)
554  return nullptr;
555  else
556  return starting_element;
557 }
558 
559 
560 
561 template <typename ElementType, typename MemorySpaceType>
562 inline bool
564 operator!=(const ArrayView<typename std::remove_cv<value_type>::type,
565  MemorySpaceType> &other_view) const
566 {
567  return !(*this == other_view);
568 }
569 
570 
571 
572 template <typename ElementType, typename MemorySpaceType>
573 inline std::size_t
575 {
576  return n_elements;
577 }
578 
579 
580 
581 template <typename ElementType, typename MemorySpaceType>
584 {
585  return starting_element;
586 }
587 
588 
589 
590 template <typename ElementType, typename MemorySpaceType>
593 {
594  return starting_element + n_elements;
595 }
596 
597 
598 
599 template <typename ElementType, typename MemorySpaceType>
602 {
603  return starting_element;
604 }
605 
606 
607 
608 template <typename ElementType, typename MemorySpaceType>
611 {
612  return starting_element + n_elements;
613 }
614 
615 
616 
617 template <typename ElementType, typename MemorySpaceType>
620 {
622  Assert(
623  (std::is_same<MemorySpaceType, MemorySpace::Host>::value),
624  ExcMessage(
625  "Accessing elements is only allowed if the data is stored in CPU memory!"));
626 
627  return *(starting_element + i);
628 }
629 
630 
631 
632 #ifndef DOXYGEN
633 namespace internal
634 {
635  namespace ArrayViewHelper
636  {
642  template <class Iterator>
643  bool
644  is_contiguous(const Iterator &first, const Iterator &last)
645  {
646  const auto n = std::distance(first, last);
647  for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
648  if (std::addressof(*(std::next(first, i))) !=
649  std::next(std::addressof(*first), i))
650  return false;
651  return true;
652  }
653 
654 
665  template <class T>
666  constexpr bool
667  is_contiguous(T *, T *)
668  {
669  return true;
670  }
671  } // namespace ArrayViewHelper
672 } // namespace internal
673 #endif
674 
675 
676 
693 template <typename Iterator, typename MemorySpaceType = MemorySpace::Host>
694 ArrayView<typename std::remove_reference<
695  typename std::iterator_traits<Iterator>::reference>::type,
696  MemorySpaceType>
697 make_array_view(const Iterator begin, const Iterator end)
698 {
699  static_assert(
700  std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
701  typename std::random_access_iterator_tag>::value,
702  "The provided iterator should be a random access iterator.");
703  Assert(begin <= end,
704  ExcMessage(
705  "The beginning of the array view should be before the end."));
706  Assert(internal::ArrayViewHelper::is_contiguous(begin, end),
707  ExcMessage("The provided range isn't contiguous in memory!"));
708  // the reference type, not the value type, knows the constness of the iterator
709  return ArrayView<typename std::remove_reference<
710  typename std::iterator_traits<Iterator>::reference>::type,
711  MemorySpaceType>(std::addressof(*begin), end - begin);
712 }
713 
714 
715 
725 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
728 {
729  Assert(begin <= end,
730  ExcMessage(
731  "The beginning of the array view should be before the end."));
733 }
734 
735 
736 
747 template <typename Number, typename MemorySpaceType>
750 {
751  return make_array_view(array_view.cbegin(), array_view.cend());
752 }
753 
754 
755 
766 template <typename Number, typename MemorySpaceType>
769 {
770  return make_array_view(array_view.begin(), array_view.end());
771 }
772 
773 
774 
791 template <int rank, int dim, typename Number>
794 {
795  return make_array_view(tensor.begin_raw(), tensor.end_raw());
796 }
797 
798 
799 
816 template <int rank, int dim, typename Number>
817 inline ArrayView<Number>
819 {
820  return make_array_view(tensor.begin_raw(), tensor.end_raw());
821 }
822 
823 
824 
841 template <int rank, int dim, typename Number>
844 {
845  return make_array_view(tensor.begin_raw(), tensor.end_raw());
846 }
847 
848 
849 
867 template <int rank, int dim, typename Number>
868 inline ArrayView<Number>
870 {
871  return make_array_view(tensor.begin_raw(), tensor.end_raw());
872 }
873 
874 
875 
889 template <typename ElementType, int N>
891 {
892  return ArrayView<ElementType>(array, N);
893 }
894 
895 
896 
911 template <typename ElementType>
913 make_array_view(Vector<ElementType> &vector)
914 {
915  return ArrayView<ElementType>(vector.begin(), vector.size());
916 }
917 
918 
919 
934 template <typename ElementType>
936 make_array_view(const Vector<ElementType> &vector)
937 {
938  return ArrayView<const ElementType>(vector.begin(), vector.size());
939 }
940 
941 
942 
957 template <typename ElementType>
959 make_array_view(std::vector<ElementType> &vector)
960 {
961  return ArrayView<ElementType>(vector.data(), vector.size());
962 }
963 
964 
965 
980 template <typename ElementType>
982 make_array_view(const std::vector<ElementType> &vector)
983 {
984  return ArrayView<const ElementType>(vector.data(), vector.size());
985 }
986 
987 
988 
1008 template <typename ElementType>
1010 make_array_view(std::vector<ElementType> &vector,
1011  const std::size_t starting_index,
1012  const std::size_t size_of_view)
1013 {
1014  Assert(starting_index + size_of_view <= vector.size(),
1015  ExcMessage("The starting index and size of the view you want to "
1016  "create would lead to a view that extends beyond the end "
1017  "of the given vector."));
1018  return ArrayView<ElementType>(&vector[starting_index], size_of_view);
1019 }
1020 
1021 
1022 
1042 template <typename ElementType>
1044 make_array_view(const std::vector<ElementType> &vector,
1045  const std::size_t starting_index,
1046  const std::size_t size_of_view)
1047 {
1048  Assert(starting_index + size_of_view <= vector.size(),
1049  ExcMessage("The starting index and size of the view you want to "
1050  "create would lead to a view that extends beyond the end "
1051  "of the given vector."));
1052  return ArrayView<const ElementType>(&vector[starting_index], size_of_view);
1053 }
1054 
1055 
1056 
1073 template <typename ElementType>
1076  const typename Table<2, ElementType>::size_type row)
1077 {
1078  AssertIndexRange(row, table.size()[0]);
1079  return ArrayView<ElementType>(&table[row][0], table.size()[1]);
1080 }
1081 
1082 
1083 
1100 template <typename ElementType>
1102 {
1103  return ArrayView<ElementType>(&table[0][0], table.n_elements());
1104 }
1105 
1106 
1107 
1124 template <typename ElementType>
1127 {
1128  return ArrayView<const ElementType>(&table[0][0], table.n_elements());
1129 }
1130 
1131 
1149 template <typename ElementType>
1152 {
1153  return ArrayView<ElementType>(&matrix(0, 0), matrix.n_elements());
1154 }
1155 
1156 
1157 
1174 template <typename ElementType>
1177 {
1178  return ArrayView<const ElementType>(&matrix(0, 0), matrix.n_elements());
1179 }
1180 
1181 
1182 
1199 template <typename ElementType>
1202  const typename Table<2, ElementType>::size_type row)
1203 {
1204  AssertIndexRange(row, table.size()[0]);
1205  return ArrayView<const ElementType>(&table[row][0], table.size()[1]);
1206 }
1207 
1208 
1209 
1229 template <typename ElementType>
1231  Table<2, ElementType> & table,
1232  const typename Table<2, ElementType>::size_type row,
1233  const typename Table<2, ElementType>::size_type starting_column,
1234  const std::size_t size_of_view)
1235 {
1236  AssertIndexRange(row, table.size()[0]);
1237  AssertIndexRange(starting_column, table.size()[1]);
1238  Assert(starting_column + size_of_view <= table.size()[1],
1239  ExcMessage("The starting index and size of the view you want to "
1240  "create would lead to a view that extends beyond the end "
1241  "of a column of the given table."));
1242  return ArrayView<ElementType>(&table[row][starting_column], size_of_view);
1243 }
1244 
1245 
1246 
1266 template <typename ElementType>
1269  const typename Table<2, ElementType>::size_type row,
1270  const typename Table<2, ElementType>::size_type starting_column,
1271  const std::size_t size_of_view)
1272 {
1273  AssertIndexRange(row, table.size()[0]);
1274  AssertIndexRange(starting_column, table.size()[1]);
1275  Assert(starting_column + size_of_view <= table.size()[1],
1276  ExcMessage("The starting index and size of the view you want to "
1277  "create would lead to a view that extends beyond the end "
1278  "of a column of the given table."));
1279  return ArrayView<const ElementType>(&table[row][starting_column],
1280  size_of_view);
1281 }
1282 
1283 
1284 
1285 /*
1286  * Create a view that doesn't allow the container it points to to be modified.
1287  * This is useful if the object passed in is not `const` already and a function
1288  * requires a view to constant memory in its signature.
1289  *
1290  * This function returns an object of type `ArrayView<const T>` where `T` is the
1291  * element type of the container.
1292  *
1293  * @relatesalso ArrayView
1294  */
1295 template <typename Container>
1296 inline auto
1297 make_const_array_view(const Container &container)
1298  -> decltype(make_array_view(container))
1299 {
1300  return make_array_view(container);
1301 }
1302 
1303 
1305 
1306 #endif
bool is_in_correct_memory_space(const void *const ptr)
Definition: array_view.h:353
Number * begin_raw()
auto make_const_array_view(const Container &container) -> decltype(make_array_view(container))
Definition: array_view.h:1297
Contents is actually a matrix.
const_iterator cbegin() const
Definition: array_view.h:601
iterator end() const
Definition: array_view.h:592
#define AssertIndexRange(index, range)
Definition: exceptions.h:1690
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:574
std::size_t n_elements
Definition: array_view.h:337
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:619
static const char T
void reinit(value_type *starting_element, const std::size_t n_elements)
Definition: array_view.h:413
Number * begin_raw()
const Number value_type
Definition: array_view.h:88
#define Assert(cond, exc)
Definition: exceptions.h:1465
#define AssertCuda(error_code)
Definition: exceptions.h:1772
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:395
Number * end_raw()
value_type * data() const noexcept
Definition: array_view.h:551
Point< 2 > first
Definition: grid_out.cc:4587
bool operator!=(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:542
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:394
static const char N
value_type * starting_element
Definition: array_view.h:332
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:697
iterator begin() const
Definition: array_view.h:583
const_iterator cend() const
Definition: array_view.h:610