Reference documentation for deal.II version Git 4abc4a1666 2020-07-04 19:58:34 +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 - 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.memoryType == cudaMemoryTypeHost;
346  else
347  return attributes.memoryType == cudaMemoryTypeDevice;
348  }
349  else
350  {
351  // ignore and reset the error since host pointers produce an error
352  cudaGetLastError();
353  return std::is_same<MemorySpaceType, MemorySpace::Host>::value;
354  }
355 #endif
356  }
357  } // namespace ArrayViewHelper
358 } // namespace internal
359 
360 
361 
362 template <typename ElementType, typename MemorySpaceType>
364  : starting_element(nullptr)
365  , n_elements(0)
366 {}
367 
368 
369 
370 template <typename ElementType, typename MemorySpaceType>
373  const std::size_t n_elements)
374  : starting_element(starting_element)
375  , n_elements(n_elements)
376 {
377  Assert(
378  n_elements == 0 ||
379  internal::ArrayViewHelper::is_in_correct_memory_space<MemorySpaceType>(
380  starting_element),
381  ExcMessage("The memory space indicated by the template parameter "
382  "and the one derived from the pointer value do not match!"));
383 }
384 
385 
386 
387 template <typename ElementType, typename MemorySpaceType>
388 inline void
390  const std::size_t n_elements)
391 {
392  *this = ArrayView(starting_element, n_elements);
393 }
394 
395 
396 
397 template <typename ElementType, typename MemorySpaceType>
399  : starting_element(&element)
400  , n_elements(1)
401 {}
402 
403 
404 
405 template <typename ElementType, typename MemorySpaceType>
407  const ArrayView<typename std::remove_cv<value_type>::type, MemorySpaceType>
408  &view)
410  , n_elements(view.n_elements)
411 {}
412 
413 
414 
415 template <typename ElementType, typename MemorySpaceType>
417  const std::vector<typename std::remove_cv<value_type>::type> &vector)
418  : // use delegating constructor
419  ArrayView(vector.data(), vector.size())
420 {
421  // the following static_assert is not strictly necessary because,
422  // if we got a const std::vector reference argument but ElementType
423  // is not itself const, then the call to the forwarding constructor
424  // above will already have failed: vector.data() will have returned
425  // a const pointer, but we need a non-const pointer.
426  //
427  // nevertheless, leave the static_assert in since it provides a
428  // more descriptive error message that will simply come after the first
429  // error produced above
430  static_assert(std::is_const<value_type>::value == true,
431  "This constructor may only be called if the ArrayView "
432  "object has a const value_type. In other words, you can "
433  "only create an ArrayView to const values from a const "
434  "std::vector.");
435 }
436 
437 
438 
439 template <typename ElementType, typename MemorySpaceType>
441  std::vector<typename std::remove_cv<value_type>::type> &vector)
442  : // use delegating constructor
443  ArrayView(vector.data(), vector.size())
444 {}
445 
446 
447 
448 template <typename ElementType, typename MemorySpaceType>
449 template <std::size_t N>
451  const std::array<typename std::remove_cv<value_type>::type, N> &vector)
452  : // use delegating constructor
453  ArrayView(vector.data(), vector.size())
454 {
455  // the following static_assert is not strictly necessary because,
456  // if we got a const std::array reference argument but ElementType
457  // is not itself const, then the call to the forwarding constructor
458  // above will already have failed: vector.data() will have returned
459  // a const pointer, but we need a non-const pointer.
460  //
461  // nevertheless, leave the static_assert in since it provides a
462  // more descriptive error message that will simply come after the first
463  // error produced above
464  static_assert(std::is_const<value_type>::value == true,
465  "This constructor may only be called if the ArrayView "
466  "object has a const value_type. In other words, you can "
467  "only create an ArrayView to const values from a const "
468  "std::array.");
469 }
470 
471 
472 
473 template <typename ElementType, typename MemorySpaceType>
474 template <std::size_t N>
476  std::array<typename std::remove_cv<value_type>::type, N> &vector)
477  : // use delegating constructor
478  ArrayView(vector.data(), vector.size())
479 {}
480 
481 
482 
483 template <typename ElementType, typename MemorySpaceType>
484 inline bool
487 {
488  return (other_view.data() == starting_element) &&
489  (other_view.size() == n_elements);
490 }
491 
492 
493 
494 template <typename ElementType, typename MemorySpaceType>
495 inline bool
497 operator==(const ArrayView<typename std::remove_cv<value_type>::type,
498  MemorySpaceType> &other_view) const
499 {
500  return (other_view.data() == starting_element) &&
501  (other_view.size() == n_elements);
502 }
503 
504 
505 
506 template <typename ElementType, typename MemorySpaceType>
507 inline bool
510 {
511  return !(*this == other_view);
512 }
513 
514 
515 
516 template <typename ElementType, typename MemorySpaceType>
519 {
520  if (n_elements == 0)
521  return nullptr;
522  else
523  return starting_element;
524 }
525 
526 
527 
528 template <typename ElementType, typename MemorySpaceType>
529 inline bool
531 operator!=(const ArrayView<typename std::remove_cv<value_type>::type,
532  MemorySpaceType> &other_view) const
533 {
534  return !(*this == other_view);
535 }
536 
537 
538 
539 template <typename ElementType, typename MemorySpaceType>
540 inline std::size_t
542 {
543  return n_elements;
544 }
545 
546 
547 
548 template <typename ElementType, typename MemorySpaceType>
551 {
552  return starting_element;
553 }
554 
555 
556 
557 template <typename ElementType, typename MemorySpaceType>
560 {
561  return starting_element + n_elements;
562 }
563 
564 
565 
566 template <typename ElementType, typename MemorySpaceType>
569 {
570  return starting_element;
571 }
572 
573 
574 
575 template <typename ElementType, typename MemorySpaceType>
578 {
579  return starting_element + n_elements;
580 }
581 
582 
583 
584 template <typename ElementType, typename MemorySpaceType>
587 {
589  Assert(
590  (std::is_same<MemorySpaceType, MemorySpace::Host>::value),
591  ExcMessage(
592  "Accessing elements is only allowed if the data is stored in CPU memory!"));
593 
594  return *(starting_element + i);
595 }
596 
597 
598 
599 #ifndef DOXYGEN
600 namespace internal
601 {
602  namespace ArrayViewHelper
603  {
609  template <class Iterator>
610  bool
611  is_contiguous(const Iterator &first, const Iterator &last)
612  {
613  const auto n = std::distance(first, last);
614  for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
615  if (std::addressof(*(std::next(first, i))) !=
616  std::next(std::addressof(*first), i))
617  return false;
618  return true;
619  }
620 
621 
632  template <class T>
633  constexpr bool
634  is_contiguous(T *, T *)
635  {
636  return true;
637  }
638  } // namespace ArrayViewHelper
639 } // namespace internal
640 #endif
641 
642 
643 
660 template <typename Iterator, typename MemorySpaceType = MemorySpace::Host>
661 ArrayView<typename std::remove_reference<
662  typename std::iterator_traits<Iterator>::reference>::type,
663  MemorySpaceType>
665 {
666  static_assert(
667  std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
668  typename std::random_access_iterator_tag>::value,
669  "The provided iterator should be a random access iterator.");
670  Assert(begin <= end,
671  ExcMessage(
672  "The beginning of the array view should be before the end."));
673  Assert(internal::ArrayViewHelper::is_contiguous(begin, end),
674  ExcMessage("The provided range isn't contiguous in memory!"));
675  // the reference type, not the value type, knows the constness of the iterator
676  return ArrayView<typename std::remove_reference<
677  typename std::iterator_traits<Iterator>::reference>::type,
678  MemorySpaceType>(std::addressof(*begin), end - begin);
679 }
680 
681 
682 
692 template <typename ElementType, typename MemorySpaceType = MemorySpace::Host>
695 {
696  Assert(begin <= end,
697  ExcMessage(
698  "The beginning of the array view should be before the end."));
700 }
701 
702 
703 
714 template <typename Number, typename MemorySpaceType>
717 {
718  return make_array_view(array_view.cbegin(), array_view.cend());
719 }
720 
721 
722 
733 template <typename Number, typename MemorySpaceType>
736 {
737  return make_array_view(array_view.begin(), array_view.end());
738 }
739 
740 
741 
758 template <int rank, int dim, typename Number>
761 {
762  return make_array_view(tensor.begin_raw(), tensor.end_raw());
763 }
764 
765 
766 
783 template <int rank, int dim, typename Number>
784 inline ArrayView<Number>
786 {
787  return make_array_view(tensor.begin_raw(), tensor.end_raw());
788 }
789 
790 
791 
808 template <int rank, int dim, typename Number>
811 {
812  return make_array_view(tensor.begin_raw(), tensor.end_raw());
813 }
814 
815 
816 
834 template <int rank, int dim, typename Number>
835 inline ArrayView<Number>
837 {
838  return make_array_view(tensor.begin_raw(), tensor.end_raw());
839 }
840 
841 
842 
856 template <typename ElementType, int N>
858 {
859  return ArrayView<ElementType>(array, N);
860 }
861 
862 
863 
878 template <typename ElementType>
880 make_array_view(Vector<ElementType> &vector)
881 {
882  return ArrayView<ElementType>(vector.begin(), vector.size());
883 }
884 
885 
886 
901 template <typename ElementType>
903 make_array_view(const Vector<ElementType> &vector)
904 {
905  return ArrayView<const ElementType>(vector.begin(), vector.size());
906 }
907 
908 
909 
924 template <typename ElementType>
926 make_array_view(std::vector<ElementType> &vector)
927 {
928  return ArrayView<ElementType>(vector.data(), vector.size());
929 }
930 
931 
932 
947 template <typename ElementType>
949 make_array_view(const std::vector<ElementType> &vector)
950 {
951  return ArrayView<const ElementType>(vector.data(), vector.size());
952 }
953 
954 
955 
975 template <typename ElementType>
977 make_array_view(std::vector<ElementType> &vector,
978  const std::size_t starting_index,
979  const std::size_t size_of_view)
980 {
981  Assert(starting_index + size_of_view <= vector.size(),
982  ExcMessage("The starting index and size of the view you want to "
983  "create would lead to a view that extends beyond the end "
984  "of the given vector."));
985  return ArrayView<ElementType>(&vector[starting_index], size_of_view);
986 }
987 
988 
989 
1009 template <typename ElementType>
1011 make_array_view(const std::vector<ElementType> &vector,
1012  const std::size_t starting_index,
1013  const std::size_t size_of_view)
1014 {
1015  Assert(starting_index + size_of_view <= vector.size(),
1016  ExcMessage("The starting index and size of the view you want to "
1017  "create would lead to a view that extends beyond the end "
1018  "of the given vector."));
1019  return ArrayView<const ElementType>(&vector[starting_index], size_of_view);
1020 }
1021 
1022 
1023 
1040 template <typename ElementType>
1043  const typename Table<2, ElementType>::size_type row)
1044 {
1045  AssertIndexRange(row, table.size()[0]);
1046  return ArrayView<ElementType>(&table[row][0], table.size()[1]);
1047 }
1048 
1049 
1050 
1067 template <typename ElementType>
1069 {
1070  return ArrayView<ElementType>(&table[0][0], table.n_elements());
1071 }
1072 
1073 
1074 
1091 template <typename ElementType>
1094 {
1095  return ArrayView<const ElementType>(&table[0][0], table.n_elements());
1096 }
1097 
1098 
1116 template <typename ElementType>
1119 {
1120  return ArrayView<ElementType>(&matrix(0, 0), matrix.n_elements());
1121 }
1122 
1123 
1124 
1141 template <typename ElementType>
1144 {
1145  return ArrayView<const ElementType>(&matrix(0, 0), matrix.n_elements());
1146 }
1147 
1148 
1149 
1166 template <typename ElementType>
1169  const typename Table<2, ElementType>::size_type row)
1170 {
1171  AssertIndexRange(row, table.size()[0]);
1172  return ArrayView<const ElementType>(&table[row][0], table.size()[1]);
1173 }
1174 
1175 
1176 
1196 template <typename ElementType>
1198  Table<2, ElementType> & table,
1199  const typename Table<2, ElementType>::size_type row,
1200  const typename Table<2, ElementType>::size_type starting_column,
1201  const std::size_t size_of_view)
1202 {
1203  AssertIndexRange(row, table.size()[0]);
1204  AssertIndexRange(starting_column, table.size()[1]);
1205  Assert(starting_column + size_of_view <= table.size()[1],
1206  ExcMessage("The starting index and size of the view you want to "
1207  "create would lead to a view that extends beyond the end "
1208  "of a column of the given table."));
1209  return ArrayView<ElementType>(&table[row][starting_column], size_of_view);
1210 }
1211 
1212 
1213 
1233 template <typename ElementType>
1236  const typename Table<2, ElementType>::size_type row,
1237  const typename Table<2, ElementType>::size_type starting_column,
1238  const std::size_t size_of_view)
1239 {
1240  AssertIndexRange(row, table.size()[0]);
1241  AssertIndexRange(starting_column, table.size()[1]);
1242  Assert(starting_column + size_of_view <= table.size()[1],
1243  ExcMessage("The starting index and size of the view you want to "
1244  "create would lead to a view that extends beyond the end "
1245  "of a column of the given table."));
1246  return ArrayView<const ElementType>(&table[row][starting_column],
1247  size_of_view);
1248 }
1249 
1250 
1251 
1252 /*
1253  * Create a view that doesn't allow the container it points to to be modified.
1254  * This is useful if the object passed in is not `const` already and a function
1255  * requires a view to constant memory in its signature.
1256  *
1257  * This function returns an object of type `ArrayView<const T>` where `T` is the
1258  * element type of the container.
1259  *
1260  * @relatesalso ArrayView
1261  */
1262 template <typename Container>
1263 inline auto
1264 make_const_array_view(const Container &container)
1265  -> decltype(make_array_view(container))
1266 {
1267  return make_array_view(container);
1268 }
1269 
1270 
1272 
1273 #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:1264
Contents is actually a matrix.
const_iterator cbegin() const
Definition: array_view.h:568
iterator end() const
Definition: array_view.h:559
#define AssertIndexRange(index, range)
Definition: exceptions.h:1628
STL namespace.
size_type n_elements() const
bool operator==(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:486
std::size_t size() const
Definition: array_view.h:541
std::size_t n_elements
Definition: array_view.h:314
const ElementType * 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:586
static const char T
void reinit(value_type *starting_element, const std::size_t n_elements)
Definition: array_view.h:389
Number * begin_raw()
ElementType value_type
Definition: array_view.h:83
#define Assert(cond, exc)
Definition: exceptions.h:1403
#define AssertCuda(error_code)
Definition: exceptions.h:1710
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:363
Number * end_raw()
value_type * data() const noexcept
Definition: array_view.h:518
Point< 2 > first
Definition: grid_out.cc:4352
bool operator!=(const ArrayView< const value_type, MemorySpaceType > &other_view) const
Definition: array_view.h:509
MatrixTableIterators::Iterator< TransposeTable< T >, Constness, MatrixTableIterators::Storage::column_major > Iterator
Definition: table.h:1907
value_type * iterator
Definition: array_view.h:88
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:362
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:664
iterator begin() const
Definition: array_view.h:550
const_iterator cend() const
Definition: array_view.h:577