Reference documentation for deal.II version Git ede8f93e86 2020-12-03 14:59:20 -0700
\(\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 - 2020 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/table.h>
25 #include <deal.II/base/tensor.h>
26 
28 
29 #include <type_traits>
30 #include <vector>
31 
33 
34 
75 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
76 class ArrayView
77 {
78 public:
84 
88  using iterator = value_type *;
89 
93  using const_iterator = const ElementType *;
94 
98  ArrayView();
99 
119  ArrayView(value_type *starting_element, const std::size_t n_elements);
120 
130  ArrayView(const ArrayView<typename std::remove_cv<value_type>::type,
131  MemorySpaceType> &view);
132 
136  explicit ArrayView(value_type &element);
137 
152  ArrayView(
153  const std::vector<typename std::remove_cv<value_type>::type> &vector);
154 
169  ArrayView(std::vector<typename std::remove_cv<value_type>::type> &vector);
170 
179  template <std::size_t N>
180  ArrayView(
181  const std::array<typename std::remove_cv<value_type>::type, N> &vector);
182 
191  template <std::size_t N>
192  ArrayView(std::array<typename std::remove_cv<value_type>::type, N> &vector);
193 
213  void
214  reinit(value_type *starting_element, const std::size_t n_elements);
215 
221  bool
222  operator==(
223  const ArrayView<const value_type, MemorySpaceType> &other_view) const;
224 
230  bool
231  operator==(const ArrayView<typename std::remove_cv<value_type>::type,
232  MemorySpaceType> &other_view) const;
233 
239  bool
240  operator!=(
241  const ArrayView<const value_type, MemorySpaceType> &other_view) const;
242 
248  bool
249  operator!=(const ArrayView<typename std::remove_cv<value_type>::type,
250  MemorySpaceType> &other_view) const;
251 
256  std::size_t
257  size() const;
258 
263  value_type *
264  data() const noexcept;
265 
269  iterator
270  begin() const;
271 
275  iterator
276  end() const;
277 
282  cbegin() const;
283 
288  cend() const;
289 
302  value_type &operator[](const std::size_t i) const;
303 
304 private:
310 
314  std::size_t n_elements;
315 
316  friend class ArrayView<const ElementType, MemorySpaceType>;
317 };
318 
319 
320 
321 //---------------------------------------------------------------------------
322 
323 
324 namespace internal
325 {
326  namespace ArrayViewHelper
327  {
328  template <typename MemorySpaceType>
329  inline bool
330  is_in_correct_memory_space(const void *const ptr)
331  {
332 #ifndef DEAL_II_COMPILER_CUDA_AWARE
333  (void)ptr;
334  static_assert(std::is_same<MemorySpaceType, MemorySpace::Host>::value,
335  "If the compiler doesn't understand CUDA code, "
336  "the only possible memory space is 'MemorySpace::Host'!");
337  return true;
338 #else
339  cudaPointerAttributes attributes;
340  const cudaError_t cuda_error = cudaPointerGetAttributes(&attributes, ptr);
341  if (cuda_error != cudaErrorInvalidValue)
342  {
343  AssertCuda(cuda_error);
344  if (std::is_same<MemorySpaceType, MemorySpace::Host>::value)
345  return (attributes.type == cudaMemoryTypeHost) ||
346  (attributes.type == cudaMemoryTypeUnregistered);
347  else
348  return attributes.type == cudaMemoryTypeDevice;
349  }
350  else
351  {
352  // ignore and reset the error since host pointers produce an error
353  cudaGetLastError();
354  return std::is_same<MemorySpaceType, MemorySpace::Host>::value;
355  }
356 #endif
357  }
358  } // namespace ArrayViewHelper
359 } // namespace internal
360 
361 
362 
363 template <typename ElementType, typename MemorySpaceType>
365  : starting_element(nullptr)
366  , n_elements(0)
367 {}
368 
369 
370 
371 template <typename ElementType, typename MemorySpaceType>
374  const std::size_t n_elements)
375  : starting_element(starting_element)
376  , n_elements(n_elements)
377 {
378  Assert(
379  n_elements == 0 ||
380  internal::ArrayViewHelper::is_in_correct_memory_space<MemorySpaceType>(
381  starting_element),
382  ExcMessage("The memory space indicated by the template parameter "
383  "and the one derived from the pointer value do not match!"));
384 }
385 
386 
387 
388 template <typename ElementType, typename MemorySpaceType>
389 inline void
391  const std::size_t n_elements)
392 {
393  *this = ArrayView(starting_element, n_elements);
394 }
395 
396 
397 
398 template <typename ElementType, typename MemorySpaceType>
400  : starting_element(&element)
401  , n_elements(1)
402 {}
403 
404 
405 
406 template <typename ElementType, typename MemorySpaceType>
408  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
409  &view)
411  , n_elements(view.n_elements)
412 {}
413 
414 
415 
416 template <typename ElementType, typename MemorySpaceType>
418  const std::vector<typename std::remove_cv<value_type>::type> &vector)
419  : // use delegating constructor
420  ArrayView(vector.data(), vector.size())
421 {
422  // the following static_assert is not strictly necessary because,
423  // if we got a const std::vector reference argument but ElementType
424  // is not itself const, then the call to the forwarding constructor
425  // above will already have failed: vector.data() will have returned
426  // a const pointer, but we need a non-const pointer.
427  //
428  // nevertheless, leave the static_assert in since it provides a
429  // more descriptive error message that will simply come after the first
430  // error produced above
431  static_assert(std::is_const<value_type>::value == true,
432  "This constructor may only be called if the ArrayView "
433  "object has a const value_type. In other words, you can "
434  "only create an ArrayView to const values from a const "
435  "std::vector.");
436 }
437 
438 
439 
440 template <typename ElementType, typename MemorySpaceType>
442  std::vector<typename std::remove_cv<value_type>::type> &vector)
443  : // use delegating constructor
444  ArrayView(vector.data(), vector.size())
445 {}
446 
447 
448 
449 template <typename ElementType, typename MemorySpaceType>
450 template <std::size_t N>
452  const std::array<typename std::remove_cv<value_type>::type, N> &vector)
453  : // use delegating constructor
454  ArrayView(vector.data(), vector.size())
455 {
456  // the following static_assert is not strictly necessary because,
457  // if we got a const std::array reference argument but ElementType
458  // is not itself const, then the call to the forwarding constructor
459  // above will already have failed: vector.data() will have returned
460  // a const pointer, but we need a non-const pointer.
461  //
462  // nevertheless, leave the static_assert in since it provides a
463  // more descriptive error message that will simply come after the first
464  // error produced above
465  static_assert(std::is_const<value_type>::value == true,
466  "This constructor may only be called if the ArrayView "
467  "object has a const value_type. In other words, you can "
468  "only create an ArrayView to const values from a const "
469  "std::array.");
470 }
471 
472 
473 
474 template <typename ElementType, typename MemorySpaceType>
475 template <std::size_t N>
477  std::array<typename std::remove_cv<value_type>::type, N> &vector)
478  : // use delegating constructor
479  ArrayView(vector.data(), vector.size())
480 {}
481 
482 
483 
484 template <typename ElementType, typename MemorySpaceType>
485 inline bool
488 {
489  return (other_view.data() == starting_element) &&
490  (other_view.size() == n_elements);
491 }
492 
493 
494 
495 template <typename ElementType, typename MemorySpaceType>
496 inline bool
498 operator==(const ArrayView<typename std::remove_cv<value_type>::type,
499  MemorySpaceType> &other_view) const
500 {
501  return (other_view.data() == starting_element) &&
502  (other_view.size() == n_elements);
503 }
504 
505 
506 
507 template <typename ElementType, typename MemorySpaceType>
508 inline bool
511 {
512  return !(*this == other_view);
513 }
514 
515 
516 
517 template <typename ElementType, typename MemorySpaceType>
520 {
521  if (n_elements == 0)
522  return nullptr;
523  else
524  return starting_element;
525 }
526 
527 
528 
529 template <typename ElementType, typename MemorySpaceType>
530 inline bool
532 operator!=(const ArrayView<typename std::remove_cv<value_type>::type,
533  MemorySpaceType> &other_view) const
534 {
535  return !(*this == other_view);
536 }
537 
538 
539 
540 template <typename ElementType, typename MemorySpaceType>
541 inline std::size_t
543 {
544  return n_elements;
545 }
546 
547 
548 
549 template <typename ElementType, typename MemorySpaceType>
552 {
553  return starting_element;
554 }
555 
556 
557 
558 template <typename ElementType, typename MemorySpaceType>
561 {
562  return starting_element + n_elements;
563 }
564 
565 
566 
567 template <typename ElementType, typename MemorySpaceType>
570 {
571  return starting_element;
572 }
573 
574 
575 
576 template <typename ElementType, typename MemorySpaceType>
579 {
580  return starting_element + n_elements;
581 }
582 
583 
584 
585 template <typename ElementType, typename MemorySpaceType>
588 {
590  Assert(
591  (std::is_same<MemorySpaceType, MemorySpace::Host>::value),
592  ExcMessage(
593  "Accessing elements is only allowed if the data is stored in CPU memory!"));
594 
595  return *(starting_element + i);
596 }
597 
598 
599 
600 #ifndef DOXYGEN
601 namespace internal
602 {
603  namespace ArrayViewHelper
604  {
610  template <class Iterator>
611  bool
612  is_contiguous(const Iterator &first, const Iterator &last)
613  {
614  const auto n = std::distance(first, last);
615  for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
616  if (std::addressof(*(std::next(first, i))) !=
617  std::next(std::addressof(*first), i))
618  return false;
619  return true;
620  }
621 
622 
633  template <class T>
634  constexpr bool
635  is_contiguous(T *, T *)
636  {
637  return true;
638  }
639  } // namespace ArrayViewHelper
640 } // namespace internal
641 #endif
642 
643 
644 
661 template <typename Iterator, typename MemorySpaceType = MemorySpace::Host>
662 ArrayView<typename std::remove_reference<
663  typename std::iterator_traits<Iterator>::reference>::type,
664  MemorySpaceType>
665 make_array_view(const Iterator begin, const Iterator end)
666 {
667  static_assert(
668  std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
669  typename std::random_access_iterator_tag>::value,
670  "The provided iterator should be a random access iterator.");
671  Assert(begin <= end,
672  ExcMessage(
673  "The beginning of the array view should be before the end."));
674  Assert(internal::ArrayViewHelper::is_contiguous(begin, end),
675  ExcMessage("The provided range isn't contiguous in memory!"));
676  // the reference type, not the value type, knows the constness of the iterator
677  return ArrayView<typename std::remove_reference<
678  typename std::iterator_traits<Iterator>::reference>::type,
679  MemorySpaceType>(std::addressof(*begin), end - begin);
680 }
681 
682 
683 
693 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
696 {
697  Assert(begin <= end,
698  ExcMessage(
699  "The beginning of the array view should be before the end."));
701 }
702 
703 
704 
715 template <typename Number, typename MemorySpaceType>
718 {
719  return make_array_view(array_view.cbegin(), array_view.cend());
720 }
721 
722 
723 
734 template <typename Number, typename MemorySpaceType>
737 {
738  return make_array_view(array_view.begin(), array_view.end());
739 }
740 
741 
742 
759 template <int rank, int dim, typename Number>
762 {
763  return make_array_view(tensor.begin_raw(), tensor.end_raw());
764 }
765 
766 
767 
784 template <int rank, int dim, typename Number>
785 inline ArrayView<Number>
787 {
788  return make_array_view(tensor.begin_raw(), tensor.end_raw());
789 }
790 
791 
792 
809 template <int rank, int dim, typename Number>
812 {
813  return make_array_view(tensor.begin_raw(), tensor.end_raw());
814 }
815 
816 
817 
835 template <int rank, int dim, typename Number>
836 inline ArrayView<Number>
838 {
839  return make_array_view(tensor.begin_raw(), tensor.end_raw());
840 }
841 
842 
843 
857 template <typename ElementType, int N>
859 {
860  return ArrayView<ElementType>(array, N);
861 }
862 
863 
864 
879 template <typename ElementType>
881 make_array_view(Vector<ElementType> &vector)
882 {
883  return ArrayView<ElementType>(vector.begin(), vector.size());
884 }
885 
886 
887 
902 template <typename ElementType>
904 make_array_view(const Vector<ElementType> &vector)
905 {
906  return ArrayView<const ElementType>(vector.begin(), vector.size());
907 }
908 
909 
910 
925 template <typename ElementType>
927 make_array_view(std::vector<ElementType> &vector)
928 {
929  return ArrayView<ElementType>(vector.data(), vector.size());
930 }
931 
932 
933 
948 template <typename ElementType>
950 make_array_view(const std::vector<ElementType> &vector)
951 {
952  return ArrayView<const ElementType>(vector.data(), vector.size());
953 }
954 
955 
956 
976 template <typename ElementType>
978 make_array_view(std::vector<ElementType> &vector,
979  const std::size_t starting_index,
980  const std::size_t size_of_view)
981 {
982  Assert(starting_index + size_of_view <= vector.size(),
983  ExcMessage("The starting index and size of the view you want to "
984  "create would lead to a view that extends beyond the end "
985  "of the given vector."));
986  return ArrayView<ElementType>(&vector[starting_index], size_of_view);
987 }
988 
989 
990 
1010 template <typename ElementType>
1012 make_array_view(const std::vector<ElementType> &vector,
1013  const std::size_t starting_index,
1014  const std::size_t size_of_view)
1015 {
1016  Assert(starting_index + size_of_view <= vector.size(),
1017  ExcMessage("The starting index and size of the view you want to "
1018  "create would lead to a view that extends beyond the end "
1019  "of the given vector."));
1020  return ArrayView<const ElementType>(&vector[starting_index], size_of_view);
1021 }
1022 
1023 
1024 
1041 template <typename ElementType>
1044  const typename Table<2, ElementType>::size_type row)
1045 {
1046  AssertIndexRange(row, table.size()[0]);
1047  return ArrayView<ElementType>(&table[row][0], table.size()[1]);
1048 }
1049 
1050 
1051 
1068 template <typename ElementType>
1070 {
1071  return ArrayView<ElementType>(&table[0][0], table.n_elements());
1072 }
1073 
1074 
1075 
1092 template <typename ElementType>
1095 {
1096  return ArrayView<const ElementType>(&table[0][0], table.n_elements());
1097 }
1098 
1099 
1117 template <typename ElementType>
1120 {
1121  return ArrayView<ElementType>(&matrix(0, 0), matrix.n_elements());
1122 }
1123 
1124 
1125 
1142 template <typename ElementType>
1145 {
1146  return ArrayView<const ElementType>(&matrix(0, 0), matrix.n_elements());
1147 }
1148 
1149 
1150 
1167 template <typename ElementType>
1170  const typename Table<2, ElementType>::size_type row)
1171 {
1172  AssertIndexRange(row, table.size()[0]);
1173  return ArrayView<const ElementType>(&table[row][0], table.size()[1]);
1174 }
1175 
1176 
1177 
1197 template <typename ElementType>
1199  Table<2, ElementType> & table,
1200  const typename Table<2, ElementType>::size_type row,
1201  const typename Table<2, ElementType>::size_type starting_column,
1202  const std::size_t size_of_view)
1203 {
1204  AssertIndexRange(row, table.size()[0]);
1205  AssertIndexRange(starting_column, table.size()[1]);
1206  Assert(starting_column + size_of_view <= table.size()[1],
1207  ExcMessage("The starting index and size of the view you want to "
1208  "create would lead to a view that extends beyond the end "
1209  "of a column of the given table."));
1210  return ArrayView<ElementType>(&table[row][starting_column], size_of_view);
1211 }
1212 
1213 
1214 
1234 template <typename ElementType>
1237  const typename Table<2, ElementType>::size_type row,
1238  const typename Table<2, ElementType>::size_type starting_column,
1239  const std::size_t size_of_view)
1240 {
1241  AssertIndexRange(row, table.size()[0]);
1242  AssertIndexRange(starting_column, table.size()[1]);
1243  Assert(starting_column + size_of_view <= table.size()[1],
1244  ExcMessage("The starting index and size of the view you want to "
1245  "create would lead to a view that extends beyond the end "
1246  "of a column of the given table."));
1247  return ArrayView<const ElementType>(&table[row][starting_column],
1248  size_of_view);
1249 }
1250 
1251 
1252 
1253 /*
1254  * Create a view that doesn't allow the container it points to to be modified.
1255  * This is useful if the object passed in is not `const` already and a function
1256  * requires a view to constant memory in its signature.
1257  *
1258  * This function returns an object of type `ArrayView<const T>` where `T` is the
1259  * element type of the container.
1260  *
1261  * @relatesalso ArrayView
1262  */
1263 template <typename Container>
1264 inline auto
1265 make_const_array_view(const Container &container)
1266  -> decltype(make_array_view(container))
1267 {
1268  return make_array_view(container);
1269 }
1270 
1271 
1273 
1274 #endif
bool is_in_correct_memory_space(const void *const ptr)
Definition: array_view.h:330
Number * begin_raw()
auto make_const_array_view(const Container &container) -> decltype(make_array_view(container))
Definition: array_view.h:1265
Contents is actually a matrix.
const_iterator cbegin() const
Definition: array_view.h:569
iterator end() const
Definition: array_view.h:560
#define AssertIndexRange(index, range)
Definition: exceptions.h:1691
STL namespace.
size_type n_elements() const
bool operator==(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:487
std::size_t size() const
Definition: array_view.h:542
std::size_t n_elements
Definition: array_view.h:314
const const Number * const_iterator
Definition: array_view.h:93
Number * end_raw()
static ::ExceptionBase & ExcMessage(std::string arg1)
value_type & operator[](const std::size_t i) const
Definition: array_view.h:587
static const char T
void reinit(value_type *starting_element, const std::size_t n_elements)
Definition: array_view.h:390
Number * begin_raw()
const Number value_type
Definition: array_view.h:83
#define Assert(cond, exc)
Definition: exceptions.h:1466
#define AssertCuda(error_code)
Definition: exceptions.h:1773
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:372
Number * end_raw()
value_type * data() const noexcept
Definition: array_view.h:519
Point< 2 > first
Definition: grid_out.cc:4340
bool operator!=(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:510
size_type size(const unsigned int i) const
typename AlignedVector< T >::size_type size_type
Definition: table.h:409
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:371
static const char N
value_type * starting_element
Definition: array_view.h:309
Definition: table.h:687
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:665
iterator begin() const
Definition: array_view.h:551
const_iterator cend() const
Definition: array_view.h:578