Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_DualView.hpp
Go to the documentation of this file.
1 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 
22 
23 #ifndef KOKKOS_DUALVIEW_HPP
24 #define KOKKOS_DUALVIEW_HPP
25 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
26 #define KOKKOS_IMPL_PUBLIC_INCLUDE
27 #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
28 #endif
29 
30 #include <Kokkos_Core.hpp>
31 #include <impl/Kokkos_Error.hpp>
32 
33 namespace Kokkos {
34 
35 /* \class DualView
36  * \brief Container to manage mirroring a Kokkos::View that lives
37  * in device memory with a Kokkos::View that lives in host memory.
38  *
39  * This class provides capabilities to manage data which exists in two
40  * memory spaces at the same time. It keeps views of the same layout
41  * on two memory spaces as well as modified flags for both
42  * allocations. Users are responsible for setting the modified flags
43  * manually if they change the data in either memory space, by calling
44  * the sync() method templated on the device where they modified the
45  * data. Users may synchronize data by calling the modify() function,
46  * templated on the device towards which they want to synchronize
47  * (i.e., the target of the one-way copy operation).
48  *
49  * The DualView class also provides convenience methods such as
50  * realloc, resize and capacity which call the appropriate methods of
51  * the underlying Kokkos::View objects.
52  *
53  * The four template arguments are the same as those of Kokkos::View.
54  * (Please refer to that class' documentation for a detailed
55  * description.)
56  *
57  * \tparam DataType The type of the entries stored in the container.
58  *
59  * \tparam Layout The array's layout in memory.
60  *
61  * \tparam Device The Kokkos Device type. If its memory space is
62  * not the same as the host's memory space, then DualView will
63  * contain two separate Views: one in device memory, and one in
64  * host memory. Otherwise, DualView will only store one View.
65  *
66  * \tparam MemoryTraits (optional) The user's intended memory access
67  * behavior. Please see the documentation of Kokkos::View for
68  * examples. The default suffices for most users.
69  */
70 
71 namespace Impl {
72 
73 #ifdef KOKKOS_ENABLE_CUDA
74 
75 inline const Kokkos::Cuda& get_cuda_space(const Kokkos::Cuda& in) { return in; }
76 
77 inline const Kokkos::Cuda& get_cuda_space() {
78  return *Kokkos::Impl::cuda_get_deep_copy_space();
79 }
80 
81 template <typename NonCudaExecSpace>
82 inline const Kokkos::Cuda& get_cuda_space(const NonCudaExecSpace&) {
83  return get_cuda_space();
84 }
85 
86 #endif // KOKKOS_ENABLE_CUDA
87 
88 } // namespace Impl
89 
90 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
91 template <class DataType, class Arg1Type = void, class Arg2Type = void,
92  class Arg3Type = void>
93 class DualView;
94 #else
95 template <class DataType, class... Properties>
96 class DualView;
97 #endif
98 
99 template <class>
100 struct is_dual_view : public std::false_type {};
101 
102 template <class DT, class... DP>
103 struct is_dual_view<DualView<DT, DP...>> : public std::true_type {};
104 
105 template <class DT, class... DP>
106 struct is_dual_view<const DualView<DT, DP...>> : public std::true_type {};
107 
108 template <class T>
109 inline constexpr bool is_dual_view_v = is_dual_view<T>::value;
110 
111 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
112 template <class DataType, class Arg1Type, class Arg2Type, class Arg3Type>
113 class DualView : public ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type> {
114  template <class, class, class, class>
115 #else
116 template <class DataType, class... Properties>
117 class DualView : public ViewTraits<DataType, Properties...> {
118  template <class, class...>
119 #endif
120  friend class DualView;
121 
122  public:
124 
125 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
126  using traits = ViewTraits<DataType, Arg1Type, Arg2Type, Arg3Type>;
127 #else
128  using traits = ViewTraits<DataType, Properties...>;
129 #endif
130 
132  using host_mirror_space = typename traits::host_mirror_space;
133 
135 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
136  using t_dev = View<typename traits::data_type, Arg1Type, Arg2Type, Arg3Type>;
137 #else
138  using t_dev = View<typename traits::data_type, Properties...>;
139 #endif
140 
143  using t_host = typename t_dev::HostMirror;
144 
147 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
148  using t_dev_const =
149  View<typename traits::const_data_type, Arg1Type, Arg2Type, Arg3Type>;
150 #else
151  using t_dev_const = View<typename traits::const_data_type, Properties...>;
152 #endif
153 
156  using t_host_const = typename t_dev_const::HostMirror;
157 
159  using t_dev_const_randomread =
160  View<typename traits::const_data_type, typename traits::array_layout,
161  typename traits::device_type,
162  Kokkos::MemoryTraits<Kokkos::RandomAccess>>;
163 
167  using t_host_const_randomread = typename t_dev_const_randomread::HostMirror;
168 
170  using t_dev_um =
171  View<typename traits::data_type, typename traits::array_layout,
172  typename traits::device_type, MemoryUnmanaged>;
173 
175  using t_host_um =
176  View<typename t_host::data_type, typename t_host::array_layout,
177  typename t_host::device_type, MemoryUnmanaged>;
178 
180  using t_dev_const_um =
181  View<typename traits::const_data_type, typename traits::array_layout,
182  typename traits::device_type, MemoryUnmanaged>;
183 
185  using t_host_const_um =
186  View<typename t_host::const_data_type, typename t_host::array_layout,
187  typename t_host::device_type, MemoryUnmanaged>;
188 
190  using t_dev_const_randomread_um =
191  View<typename t_host::const_data_type, typename t_host::array_layout,
192  typename t_host::device_type,
193  Kokkos::MemoryTraits<Kokkos::Unmanaged | Kokkos::RandomAccess>>;
194 
198  using t_host_const_randomread_um =
200 
202 
204 
205  protected:
206  // modified_flags[0] -> host
207  // modified_flags[1] -> device
208  using t_modified_flags = View<unsigned int[2], LayoutLeft, Kokkos::HostSpace>;
209  t_modified_flags modified_flags;
210 
211  public:
213 
214  // Moved this specifically after modified_flags to resolve an alignment issue
215  // on MSVC/NVCC
217 
218  t_dev d_view;
219  t_host h_view;
221 
223 
224 
230  DualView() = default;
231 
241  DualView(const std::string& label,
242  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
243  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
244  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
245  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
246  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
247  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
248  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
249  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
250  : modified_flags(
251  Kokkos::view_alloc(typename t_modified_flags::execution_space{},
252  "DualView::modified_flags")),
253  d_view(label, n0, n1, n2, n3, n4, n5, n6, n7),
254  h_view(create_mirror_view(d_view)) // without UVM, host View mirrors
255  {}
256 
267  template <class... P>
268  DualView(const Impl::ViewCtorProp<P...>& arg_prop,
269  std::enable_if_t<!Impl::ViewCtorProp<P...>::has_pointer,
270  size_t> const n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
271  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
272  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
273  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
274  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
275  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
276  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
277  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG)
278  : modified_flags(t_modified_flags("DualView::modified_flags")),
279  d_view(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7) {
280  // without UVM, host View mirrors
281  if constexpr (Kokkos::Impl::has_type<Impl::WithoutInitializing_t,
282  P...>::value)
283  h_view = Kokkos::create_mirror_view(Kokkos::WithoutInitializing, d_view);
284  else
285  h_view = Kokkos::create_mirror_view(d_view);
286  }
287 
289  template <typename DT, typename... DP>
290  DualView(const DualView<DT, DP...>& src)
291  : modified_flags(src.modified_flags),
292  d_view(src.d_view),
293  h_view(src.h_view) {}
294 
296  template <class DT, class... DP, class Arg0, class... Args>
297  DualView(const DualView<DT, DP...>& src, const Arg0& arg0, Args... args)
298  : modified_flags(src.modified_flags),
299  d_view(Kokkos::subview(src.d_view, arg0, args...)),
300  h_view(Kokkos::subview(src.h_view, arg0, args...)) {}
301 
312  DualView(const t_dev& d_view_, const t_host& h_view_)
313  : modified_flags(t_modified_flags("DualView::modified_flags")),
314  d_view(d_view_),
315  h_view(h_view_) {
316  if (int(d_view.rank) != int(h_view.rank) ||
317  d_view.extent(0) != h_view.extent(0) ||
318  d_view.extent(1) != h_view.extent(1) ||
319  d_view.extent(2) != h_view.extent(2) ||
320  d_view.extent(3) != h_view.extent(3) ||
321  d_view.extent(4) != h_view.extent(4) ||
322  d_view.extent(5) != h_view.extent(5) ||
323  d_view.extent(6) != h_view.extent(6) ||
324  d_view.extent(7) != h_view.extent(7) ||
325  d_view.stride_0() != h_view.stride_0() ||
326  d_view.stride_1() != h_view.stride_1() ||
327  d_view.stride_2() != h_view.stride_2() ||
328  d_view.stride_3() != h_view.stride_3() ||
329  d_view.stride_4() != h_view.stride_4() ||
330  d_view.stride_5() != h_view.stride_5() ||
331  d_view.stride_6() != h_view.stride_6() ||
332  d_view.stride_7() != h_view.stride_7() ||
333  d_view.span() != h_view.span()) {
334  Kokkos::Impl::throw_runtime_exception(
335  "DualView constructed with incompatible views");
336  }
337  }
338  // does the DualView have only one device
339  struct impl_dualview_is_single_device {
340  enum : bool {
341  value = std::is_same<typename t_dev::device_type,
342  typename t_host::device_type>::value
343  };
344  };
345 
346  // does the given device match the device of t_dev?
347  template <typename Device>
348  struct impl_device_matches_tdev_device {
349  enum : bool {
350  value = std::is_same<typename t_dev::device_type, Device>::value
351  };
352  };
353  // does the given device match the device of t_host?
354  template <typename Device>
355  struct impl_device_matches_thost_device {
356  enum : bool {
357  value = std::is_same<typename t_host::device_type, Device>::value
358  };
359  };
360 
361  // does the given device match the execution space of t_host?
362  template <typename Device>
363  struct impl_device_matches_thost_exec {
364  enum : bool {
365  value = std::is_same<typename t_host::execution_space, Device>::value
366  };
367  };
368 
369  // does the given device match the execution space of t_dev?
370  template <typename Device>
371  struct impl_device_matches_tdev_exec {
372  enum : bool {
373  value = std::is_same<typename t_dev::execution_space, Device>::value
374  };
375  };
376 
377  // does the given device's memory space match the memory space of t_dev?
378  template <typename Device>
379  struct impl_device_matches_tdev_memory_space {
380  enum : bool {
381  value = std::is_same<typename t_dev::memory_space,
382  typename Device::memory_space>::value
383  };
384  };
385 
387 
389 
412  template <class Device>
413  KOKKOS_INLINE_FUNCTION const typename std::conditional_t<
414  impl_device_matches_tdev_device<Device>::value, t_dev,
415  typename std::conditional_t<
416  impl_device_matches_thost_device<Device>::value, t_host,
417  typename std::conditional_t<
418  impl_device_matches_thost_exec<Device>::value, t_host,
419  typename std::conditional_t<
420  impl_device_matches_tdev_exec<Device>::value, t_dev,
421  typename std::conditional_t<
422  impl_device_matches_tdev_memory_space<Device>::value,
423  t_dev, t_host>>>>>
424  view() const {
425  constexpr bool device_is_memspace =
426  std::is_same<Device, typename Device::memory_space>::value;
427  constexpr bool device_is_execspace =
428  std::is_same<Device, typename Device::execution_space>::value;
429  constexpr bool device_exec_is_t_dev_exec =
430  std::is_same<typename Device::execution_space,
431  typename t_dev::execution_space>::value;
432  constexpr bool device_mem_is_t_dev_mem =
433  std::is_same<typename Device::memory_space,
434  typename t_dev::memory_space>::value;
435  constexpr bool device_exec_is_t_host_exec =
436  std::is_same<typename Device::execution_space,
437  typename t_host::execution_space>::value;
438  constexpr bool device_mem_is_t_host_mem =
439  std::is_same<typename Device::memory_space,
440  typename t_host::memory_space>::value;
441  constexpr bool device_is_t_host_device =
442  std::is_same<typename Device::execution_space,
443  typename t_host::device_type>::value;
444  constexpr bool device_is_t_dev_device =
445  std::is_same<typename Device::memory_space,
446  typename t_host::device_type>::value;
447 
448  static_assert(
449  device_is_t_dev_device || device_is_t_host_device ||
450  (device_is_memspace &&
451  (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
452  (device_is_execspace &&
453  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
454  ((!device_is_execspace && !device_is_memspace) &&
455  ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
456  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
457  "Template parameter to .view() must exactly match one of the "
458  "DualView's device types or one of the execution or memory spaces");
459 
460  return Impl::if_c<std::is_same<typename t_dev::memory_space,
461  typename Device::memory_space>::value,
462  t_dev, t_host>::select(d_view, h_view);
463  }
464 
465  KOKKOS_INLINE_FUNCTION
466  t_host view_host() const { return h_view; }
467 
468  KOKKOS_INLINE_FUNCTION
469  t_dev view_device() const { return d_view; }
470 
471  KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
472  return (d_view.is_allocated() && h_view.is_allocated());
473  }
474 
475  template <class Device>
476  static int get_device_side() {
477  constexpr bool device_is_memspace =
478  std::is_same<Device, typename Device::memory_space>::value;
479  constexpr bool device_is_execspace =
480  std::is_same<Device, typename Device::execution_space>::value;
481  constexpr bool device_exec_is_t_dev_exec =
482  std::is_same<typename Device::execution_space,
483  typename t_dev::execution_space>::value;
484  constexpr bool device_mem_is_t_dev_mem =
485  std::is_same<typename Device::memory_space,
486  typename t_dev::memory_space>::value;
487  constexpr bool device_exec_is_t_host_exec =
488  std::is_same<typename Device::execution_space,
489  typename t_host::execution_space>::value;
490  constexpr bool device_mem_is_t_host_mem =
491  std::is_same<typename Device::memory_space,
492  typename t_host::memory_space>::value;
493  constexpr bool device_is_t_host_device =
494  std::is_same<typename Device::execution_space,
495  typename t_host::device_type>::value;
496  constexpr bool device_is_t_dev_device =
497  std::is_same<typename Device::memory_space,
498  typename t_host::device_type>::value;
499 
500  static_assert(
501  device_is_t_dev_device || device_is_t_host_device ||
502  (device_is_memspace &&
503  (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) ||
504  (device_is_execspace &&
505  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) ||
506  ((!device_is_execspace && !device_is_memspace) &&
507  ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ||
508  (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))),
509  "Template parameter to .sync() must exactly match one of the "
510  "DualView's device types or one of the execution or memory spaces");
511 
512  int dev = -1;
513  if (device_is_t_dev_device)
514  dev = 1;
515  else if (device_is_t_host_device)
516  dev = 0;
517  else {
518  if (device_is_memspace) {
519  if (device_mem_is_t_dev_mem) dev = 1;
520  if (device_mem_is_t_host_mem) dev = 0;
521  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
522  }
523  if (device_is_execspace) {
524  if (device_exec_is_t_dev_exec) dev = 1;
525  if (device_exec_is_t_host_exec) dev = 0;
526  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
527  }
528  if (!device_is_execspace && !device_is_memspace) {
529  if (device_mem_is_t_dev_mem) dev = 1;
530  if (device_mem_is_t_host_mem) dev = 0;
531  if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1;
532  if (device_exec_is_t_dev_exec) dev = 1;
533  if (device_exec_is_t_host_exec) dev = 0;
534  if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1;
535  }
536  }
537  return dev;
538  }
539  static constexpr const int view_header_size = 128;
540  void impl_report_host_sync() const noexcept {
541  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
542  nullptr) {
543  Kokkos::Tools::syncDualView(
544  h_view.label(),
545  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
546  view_header_size),
547  false);
548  }
549  }
550  void impl_report_device_sync() const noexcept {
551  if (Kokkos::Tools::Experimental::get_callbacks().sync_dual_view !=
552  nullptr) {
553  Kokkos::Tools::syncDualView(
554  d_view.label(),
555  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
556  view_header_size),
557  true);
558  }
559  }
560 
578  // deliberately passing args by cref as they're used multiple times
579  template <class Device, class... Args>
580  void sync_impl(std::true_type, Args const&... args) {
581  if (modified_flags.data() == nullptr) return;
582 
583  int dev = get_device_side<Device>();
584 
585  if (dev == 1) { // if Device is the same as DualView's device type
586  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
587 #ifdef KOKKOS_ENABLE_CUDA
588  if (std::is_same<typename t_dev::memory_space,
589  Kokkos::CudaUVMSpace>::value) {
590  if (d_view.data() == h_view.data())
591  Kokkos::Impl::cuda_prefetch_pointer(
592  Impl::get_cuda_space(args...), d_view.data(),
593  sizeof(typename t_dev::value_type) * d_view.span(), true);
594  }
595 #endif
596 
597  deep_copy(args..., d_view, h_view);
598  modified_flags(0) = modified_flags(1) = 0;
599  impl_report_device_sync();
600  }
601  }
602  if (dev == 0) { // hopefully Device is the same as DualView's host type
603  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
604 #ifdef KOKKOS_ENABLE_CUDA
605  if (std::is_same<typename t_dev::memory_space,
606  Kokkos::CudaUVMSpace>::value) {
607  if (d_view.data() == h_view.data())
608  Kokkos::Impl::cuda_prefetch_pointer(
609  Impl::get_cuda_space(args...), d_view.data(),
610  sizeof(typename t_dev::value_type) * d_view.span(), false);
611  }
612 #endif
613 
614  deep_copy(args..., h_view, d_view);
615  modified_flags(0) = modified_flags(1) = 0;
616  impl_report_host_sync();
617  }
618  }
619  if constexpr (std::is_same<typename t_host::memory_space,
620  typename t_dev::memory_space>::value) {
621  typename t_dev::execution_space().fence(
622  "Kokkos::DualView<>::sync: fence after syncing DualView");
623  typename t_host::execution_space().fence(
624  "Kokkos::DualView<>::sync: fence after syncing DualView");
625  }
626  }
627 
628  template <class Device>
629  void sync(const std::enable_if_t<
630  (std::is_same<typename traits::data_type,
631  typename traits::non_const_data_type>::value) ||
632  (std::is_same<Device, int>::value),
633  int>& = 0) {
634  sync_impl<Device>(std::true_type{});
635  }
636 
637  template <class Device, class ExecutionSpace>
638  void sync(const ExecutionSpace& exec,
639  const std::enable_if_t<
640  (std::is_same<typename traits::data_type,
641  typename traits::non_const_data_type>::value) ||
642  (std::is_same<Device, int>::value),
643  int>& = 0) {
644  sync_impl<Device>(std::true_type{}, exec);
645  }
646 
647  // deliberately passing args by cref as they're used multiple times
648  template <class Device, class... Args>
649  void sync_impl(std::false_type, Args const&...) {
650  if (modified_flags.data() == nullptr) return;
651 
652  int dev = get_device_side<Device>();
653 
654  if (dev == 1) { // if Device is the same as DualView's device type
655  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
656  Impl::throw_runtime_exception(
657  "Calling sync on a DualView with a const datatype.");
658  }
659  impl_report_device_sync();
660  }
661  if (dev == 0) { // hopefully Device is the same as DualView's host type
662  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
663  Impl::throw_runtime_exception(
664  "Calling sync on a DualView with a const datatype.");
665  }
666  impl_report_host_sync();
667  }
668  }
669 
670  template <class Device>
671  void sync(const std::enable_if_t<
672  (!std::is_same<typename traits::data_type,
673  typename traits::non_const_data_type>::value) ||
674  (std::is_same<Device, int>::value),
675  int>& = 0) {
676  sync_impl<Device>(std::false_type{});
677  }
678  template <class Device, class ExecutionSpace>
679  void sync(const ExecutionSpace& exec,
680  const std::enable_if_t<
681  (!std::is_same<typename traits::data_type,
682  typename traits::non_const_data_type>::value) ||
683  (std::is_same<Device, int>::value),
684  int>& = 0) {
685  sync_impl<Device>(std::false_type{}, exec);
686  }
687 
688  // deliberately passing args by cref as they're used multiple times
689  template <typename... Args>
690  void sync_host_impl(Args const&... args) {
691  if (!std::is_same<typename traits::data_type,
692  typename traits::non_const_data_type>::value)
693  Impl::throw_runtime_exception(
694  "Calling sync_host on a DualView with a const datatype.");
695  if (modified_flags.data() == nullptr) return;
696  if (modified_flags(1) > modified_flags(0)) {
697 #ifdef KOKKOS_ENABLE_CUDA
698  if (std::is_same<typename t_dev::memory_space,
699  Kokkos::CudaUVMSpace>::value) {
700  if (d_view.data() == h_view.data())
701  Kokkos::Impl::cuda_prefetch_pointer(
702  Impl::get_cuda_space(args...), d_view.data(),
703  sizeof(typename t_dev::value_type) * d_view.span(), false);
704  }
705 #endif
706 
707  deep_copy(args..., h_view, d_view);
708  modified_flags(1) = modified_flags(0) = 0;
709  impl_report_host_sync();
710  }
711  }
712 
713  template <class ExecSpace>
714  void sync_host(const ExecSpace& exec) {
715  sync_host_impl(exec);
716  }
717  void sync_host() { sync_host_impl(); }
718 
719  // deliberately passing args by cref as they're used multiple times
720  template <typename... Args>
721  void sync_device_impl(Args const&... args) {
722  if (!std::is_same<typename traits::data_type,
723  typename traits::non_const_data_type>::value)
724  Impl::throw_runtime_exception(
725  "Calling sync_device on a DualView with a const datatype.");
726  if (modified_flags.data() == nullptr) return;
727  if (modified_flags(0) > modified_flags(1)) {
728 #ifdef KOKKOS_ENABLE_CUDA
729  if (std::is_same<typename t_dev::memory_space,
730  Kokkos::CudaUVMSpace>::value) {
731  if (d_view.data() == h_view.data())
732  Kokkos::Impl::cuda_prefetch_pointer(
733  Impl::get_cuda_space(args...), d_view.data(),
734  sizeof(typename t_dev::value_type) * d_view.span(), true);
735  }
736 #endif
737 
738  deep_copy(args..., d_view, h_view);
739  modified_flags(1) = modified_flags(0) = 0;
740  impl_report_device_sync();
741  }
742  }
743 
744  template <class ExecSpace>
745  void sync_device(const ExecSpace& exec) {
746  sync_device_impl(exec);
747  }
748  void sync_device() { sync_device_impl(); }
749 
750  template <class Device>
751  bool need_sync() const {
752  if (modified_flags.data() == nullptr) return false;
753  int dev = get_device_side<Device>();
754 
755  if (dev == 1) { // if Device is the same as DualView's device type
756  if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) {
757  return true;
758  }
759  }
760  if (dev == 0) { // hopefully Device is the same as DualView's host type
761  if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) {
762  return true;
763  }
764  }
765  return false;
766  }
767 
768  inline bool need_sync_host() const {
769  if (modified_flags.data() == nullptr) return false;
770  return modified_flags(0) < modified_flags(1);
771  }
772 
773  inline bool need_sync_device() const {
774  if (modified_flags.data() == nullptr) return false;
775  return modified_flags(1) < modified_flags(0);
776  }
777  void impl_report_device_modification() {
778  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
779  nullptr) {
780  Kokkos::Tools::modifyDualView(
781  d_view.label(),
782  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(d_view.data()) -
783  view_header_size),
784  true);
785  }
786  }
787  void impl_report_host_modification() {
788  if (Kokkos::Tools::Experimental::get_callbacks().modify_dual_view !=
789  nullptr) {
790  Kokkos::Tools::modifyDualView(
791  h_view.label(),
792  reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(h_view.data()) -
793  view_header_size),
794  false);
795  }
796  }
802  template <class Device, class Dummy = DualView,
803  std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
804  nullptr>
805  void modify() {
806  if (modified_flags.data() == nullptr) {
807  modified_flags = t_modified_flags("DualView::modified_flags");
808  }
809 
810  int dev = get_device_side<Device>();
811 
812  if (dev == 1) { // if Device is the same as DualView's device type
813  // Increment the device's modified count.
814  modified_flags(1) =
815  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
816  : modified_flags(0)) +
817  1;
818  impl_report_device_modification();
819  }
820  if (dev == 0) { // hopefully Device is the same as DualView's host type
821  // Increment the host's modified count.
822  modified_flags(0) =
823  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
824  : modified_flags(0)) +
825  1;
826  impl_report_host_modification();
827  }
828 
829 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
830  if (modified_flags(0) && modified_flags(1)) {
831  std::string msg = "Kokkos::DualView::modify ERROR: ";
832  msg += "Concurrent modification of host and device views ";
833  msg += "in DualView \"";
834  msg += d_view.label();
835  msg += "\"\n";
836  Kokkos::abort(msg.c_str());
837  }
838 #endif
839  }
840 
841  template <
842  class Device, class Dummy = DualView,
843  std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
844  void modify() {
845  return;
846  }
847 
848  template <class Dummy = DualView,
849  std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
850  nullptr>
851  inline void modify_host() {
852  if (modified_flags.data() != nullptr) {
853  modified_flags(0) =
854  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
855  : modified_flags(0)) +
856  1;
857  impl_report_host_modification();
858 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
859  if (modified_flags(0) && modified_flags(1)) {
860  std::string msg = "Kokkos::DualView::modify_host ERROR: ";
861  msg += "Concurrent modification of host and device views ";
862  msg += "in DualView \"";
863  msg += d_view.label();
864  msg += "\"\n";
865  Kokkos::abort(msg.c_str());
866  }
867 #endif
868  }
869  }
870 
871  template <
872  class Dummy = DualView,
873  std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
874  inline void modify_host() {
875  return;
876  }
877 
878  template <class Dummy = DualView,
879  std::enable_if_t<!Dummy::impl_dualview_is_single_device::value>* =
880  nullptr>
881  inline void modify_device() {
882  if (modified_flags.data() != nullptr) {
883  modified_flags(1) =
884  (modified_flags(1) > modified_flags(0) ? modified_flags(1)
885  : modified_flags(0)) +
886  1;
887  impl_report_device_modification();
888 #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK
889  if (modified_flags(0) && modified_flags(1)) {
890  std::string msg = "Kokkos::DualView::modify_device ERROR: ";
891  msg += "Concurrent modification of host and device views ";
892  msg += "in DualView \"";
893  msg += d_view.label();
894  msg += "\"\n";
895  Kokkos::abort(msg.c_str());
896  }
897 #endif
898  }
899  }
900 
901  template <
902  class Dummy = DualView,
903  std::enable_if_t<Dummy::impl_dualview_is_single_device::value>* = nullptr>
904  inline void modify_device() {
905  return;
906  }
907 
908  inline void clear_sync_state() {
909  if (modified_flags.data() != nullptr)
910  modified_flags(1) = modified_flags(0) = 0;
911  }
912 
914 
916 
922  template <class... ViewCtorArgs>
923  void impl_realloc(const size_t n0, const size_t n1, const size_t n2,
924  const size_t n3, const size_t n4, const size_t n5,
925  const size_t n6, const size_t n7,
926  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) {
927  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
928 
929  static_assert(!alloc_prop_input::has_label,
930  "The view constructor arguments passed to Kokkos::realloc "
931  "must not include a label!");
932  static_assert(
933  !alloc_prop_input::has_pointer,
934  "The view constructor arguments passed to Kokkos::realloc must "
935  "not include a pointer!");
936  static_assert(
937  !alloc_prop_input::has_memory_space,
938  "The view constructor arguments passed to Kokkos::realloc must "
939  "not include a memory space instance!");
940 
941  const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
942  const bool sizeMismatch =
943  Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
944 
945  if (sizeMismatch) {
946  ::Kokkos::realloc(arg_prop, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
947  if (alloc_prop_input::initialize) {
948  h_view = create_mirror_view(typename t_host::memory_space(), d_view);
949  } else {
950  h_view = create_mirror_view(Kokkos::WithoutInitializing,
951  typename t_host::memory_space(), d_view);
952  }
953  } else if (alloc_prop_input::initialize) {
954  if constexpr (alloc_prop_input::has_execution_space) {
955  const auto& exec_space =
956  Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
957  ::Kokkos::deep_copy(exec_space, d_view, typename t_dev::value_type{});
958  } else
959  ::Kokkos::deep_copy(d_view, typename t_dev::value_type{});
960  }
961 
962  /* Reset dirty flags */
963  if (modified_flags.data() == nullptr) {
964  modified_flags = t_modified_flags("DualView::modified_flags");
965  } else
966  modified_flags(1) = modified_flags(0) = 0;
967  }
968 
969  template <class... ViewCtorArgs>
970  void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
971  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
972  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
973  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
974  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
975  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
976  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
977  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
978  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
979  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, arg_prop);
980  }
981 
982  void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
983  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
984  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
985  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
986  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
987  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
988  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
989  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
990  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Impl::ViewCtorProp<>{});
991  }
992 
993  template <typename I>
994  std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
995  const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
996  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
997  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
998  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
999  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1000  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1001  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1002  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1003  impl_realloc(n0, n1, n2, n3, n4, n5, n6, n7, Kokkos::view_alloc(arg_prop));
1004  }
1005 
1010  template <class... ViewCtorArgs>
1011  void impl_resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1012  const size_t n0, const size_t n1, const size_t n2,
1013  const size_t n3, const size_t n4, const size_t n5,
1014  const size_t n6, const size_t n7) {
1015  using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>;
1016 
1017  static_assert(!alloc_prop_input::has_label,
1018  "The view constructor arguments passed to Kokkos::resize "
1019  "must not include a label!");
1020  static_assert(
1021  !alloc_prop_input::has_pointer,
1022  "The view constructor arguments passed to Kokkos::resize must "
1023  "not include a pointer!");
1024  static_assert(
1025  !alloc_prop_input::has_memory_space,
1026  "The view constructor arguments passed to Kokkos::resize must "
1027  "not include a memory space instance!");
1028 
1029  const size_t new_extents[8] = {n0, n1, n2, n3, n4, n5, n6, n7};
1030  const bool sizeMismatch =
1031  Impl::size_mismatch(h_view, h_view.rank_dynamic, new_extents);
1032 
1033  if (modified_flags.data() == nullptr) {
1034  modified_flags = t_modified_flags("DualView::modified_flags");
1035  }
1036 
1037  [[maybe_unused]] auto resize_on_device = [&](const auto& properties) {
1038  /* Resize on Device */
1039  if (sizeMismatch) {
1040  ::Kokkos::resize(properties, d_view, n0, n1, n2, n3, n4, n5, n6, n7);
1041  if (alloc_prop_input::initialize) {
1042  h_view = create_mirror_view(typename t_host::memory_space(), d_view);
1043  } else {
1044  h_view = create_mirror_view(Kokkos::WithoutInitializing,
1045  typename t_host::memory_space(), d_view);
1046  }
1047 
1048  /* Mark Device copy as modified */
1049  ++modified_flags(1);
1050  }
1051  };
1052 
1053  [[maybe_unused]] auto resize_on_host = [&](const auto& properties) {
1054  /* Resize on Host */
1055  if (sizeMismatch) {
1056  ::Kokkos::resize(properties, h_view, n0, n1, n2, n3, n4, n5, n6, n7);
1057  if (alloc_prop_input::initialize) {
1058  d_view = create_mirror_view(typename t_dev::memory_space(), h_view);
1059 
1060  } else {
1061  d_view = create_mirror_view(Kokkos::WithoutInitializing,
1062  typename t_dev::memory_space(), h_view);
1063  }
1064 
1065  /* Mark Host copy as modified */
1066  ++modified_flags(0);
1067  }
1068  };
1069 
1070  constexpr bool has_execution_space = alloc_prop_input::has_execution_space;
1071 
1072  if constexpr (has_execution_space) {
1073  using ExecSpace = typename alloc_prop_input::execution_space;
1074  const auto& exec_space =
1075  Impl::get_property<Impl::ExecutionSpaceTag>(arg_prop);
1076  constexpr bool exec_space_can_access_device =
1077  SpaceAccessibility<ExecSpace,
1078  typename t_dev::memory_space>::accessible;
1079  constexpr bool exec_space_can_access_host =
1080  SpaceAccessibility<ExecSpace,
1081  typename t_host::memory_space>::accessible;
1082  static_assert(exec_space_can_access_device || exec_space_can_access_host);
1083  if constexpr (exec_space_can_access_device) {
1084  sync<typename t_dev::memory_space>(exec_space);
1085  resize_on_device(arg_prop);
1086  return;
1087  }
1088  if constexpr (exec_space_can_access_host) {
1089  sync<typename t_host::memory_space>(exec_space);
1090  resize_on_host(arg_prop);
1091  return;
1092  }
1093  } else {
1094  if (modified_flags(1) >= modified_flags(0)) {
1095  resize_on_device(arg_prop);
1096  } else {
1097  resize_on_host(arg_prop);
1098  }
1099  }
1100  }
1101 
1102  void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1103  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1104  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1105  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1106  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1107  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1108  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1109  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1110  impl_resize(Impl::ViewCtorProp<>{}, n0, n1, n2, n3, n4, n5, n6, n7);
1111  }
1112 
1113  template <class... ViewCtorArgs>
1114  void resize(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1115  const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1116  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1117  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1118  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1119  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1120  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1121  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1122  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1123  impl_resize(arg_prop, n0, n1, n2, n3, n4, n5, n6, n7);
1124  }
1125 
1126  template <class I>
1127  std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1128  const I& arg_prop, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1129  const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1130  const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1131  const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1132  const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1133  const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1134  const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG,
1135  const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) {
1136  impl_resize(Kokkos::view_alloc(arg_prop), n0, n1, n2, n3, n4, n5, n6, n7);
1137  }
1138 
1140 
1142 
1144  KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); }
1145 
1146  KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const {
1147  return d_view.span_is_contiguous();
1148  }
1149 
1151  template <typename iType>
1152  void stride(iType* stride_) const {
1153  d_view.stride(stride_);
1154  }
1155 
1156  template <typename iType>
1157  KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
1158  std::is_integral<iType>::value, size_t>
1159  extent(const iType& r) const {
1160  return d_view.extent(r);
1161  }
1162 
1163  template <typename iType>
1164  KOKKOS_INLINE_FUNCTION constexpr std::enable_if_t<
1165  std::is_integral<iType>::value, int>
1166  extent_int(const iType& r) const {
1167  return static_cast<int>(d_view.extent(r));
1168  }
1169 
1171 };
1172 
1173 } // namespace Kokkos
1174 
1175 //----------------------------------------------------------------------------
1176 //----------------------------------------------------------------------------
1177 //
1178 // Partial specializations of Kokkos::subview() for DualView objects.
1179 //
1180 
1181 namespace Kokkos {
1182 namespace Impl {
1183 
1184 template <class V>
1185 struct V2DV;
1186 
1187 template <class D, class... P>
1188 struct V2DV<View<D, P...>> {
1189  using type = DualView<D, P...>;
1190 };
1191 } /* namespace Impl */
1192 
1193 template <class DataType, class... Properties, class... Args>
1194 auto subview(const DualView<DataType, Properties...>& src, Args&&... args) {
1195  // leverage Kokkos::View facilities to deduce the properties of the subview
1196  using deduce_subview_type =
1197  decltype(subview(std::declval<View<DataType, Properties...>>(),
1198  std::forward<Args>(args)...));
1199  // map it back to dual view
1200  return typename Impl::V2DV<deduce_subview_type>::type(
1201  src, std::forward<Args>(args)...);
1202 }
1203 
1204 } /* namespace Kokkos */
1205 
1206 //----------------------------------------------------------------------------
1207 //----------------------------------------------------------------------------
1208 
1209 namespace Kokkos {
1210 
1211 //
1212 // Partial specialization of Kokkos::deep_copy() for DualView objects.
1213 //
1214 
1215 template <class DT, class... DP, class ST, class... SP>
1216 void deep_copy(DualView<DT, DP...>& dst, const DualView<ST, SP...>& src) {
1217  if (src.need_sync_device()) {
1218  deep_copy(dst.h_view, src.h_view);
1219  dst.modify_host();
1220  } else {
1221  deep_copy(dst.d_view, src.d_view);
1222  dst.modify_device();
1223  }
1224 }
1225 
1226 template <class ExecutionSpace, class DT, class... DP, class ST, class... SP>
1227 void deep_copy(const ExecutionSpace& exec, DualView<DT, DP...>& dst,
1228  const DualView<ST, SP...>& src) {
1229  if (src.need_sync_device()) {
1230  deep_copy(exec, dst.h_view, src.h_view);
1231  dst.modify_host();
1232  } else {
1233  deep_copy(exec, dst.d_view, src.d_view);
1234  dst.modify_device();
1235  }
1236 }
1237 
1238 } // namespace Kokkos
1239 
1240 //----------------------------------------------------------------------------
1241 //----------------------------------------------------------------------------
1242 
1243 namespace Kokkos {
1244 
1245 //
1246 // Non-member resize and realloc
1247 //
1248 
1249 template <class... Properties, class... Args>
1250 void resize(DualView<Properties...>& dv, Args&&... args) noexcept(
1251  noexcept(dv.resize(std::forward<Args>(args)...))) {
1252  dv.resize(std::forward<Args>(args)...);
1253 }
1254 
1255 template <class... ViewCtorArgs, class... Properties, class... Args>
1256 void resize(
1257  const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1258  DualView<Properties...>& dv,
1259  Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1260  std::forward<Args>(args)...))) {
1261  dv.resize(arg_prop, std::forward<Args>(args)...);
1262 }
1263 
1264 template <class I, class... Properties, class... Args>
1265 std::enable_if_t<Impl::is_view_ctor_property<I>::value> resize(
1266  const I& arg_prop, DualView<Properties...>& dv,
1267  Args&&... args) noexcept(noexcept(dv.resize(arg_prop,
1268  std::forward<Args>(args)...))) {
1269  dv.resize(arg_prop, std::forward<Args>(args)...);
1270 }
1271 
1272 template <class... ViewCtorArgs, class... Properties, class... Args>
1273 void realloc(const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop,
1274  DualView<Properties...>& dv,
1275  Args&&... args) noexcept(noexcept(dv
1276  .realloc(std::forward<Args>(
1277  args)...))) {
1278  dv.realloc(arg_prop, std::forward<Args>(args)...);
1279 }
1280 
1281 template <class... Properties, class... Args>
1282 void realloc(DualView<Properties...>& dv, Args&&... args) noexcept(
1283  noexcept(dv.realloc(std::forward<Args>(args)...))) {
1284  dv.realloc(std::forward<Args>(args)...);
1285 }
1286 
1287 template <class I, class... Properties, class... Args>
1288 std::enable_if_t<Impl::is_view_ctor_property<I>::value> realloc(
1289  const I& arg_prop, DualView<Properties...>& dv,
1290  Args&&... args) noexcept(noexcept(dv.realloc(arg_prop,
1291  std::forward<Args>(
1292  args)...))) {
1293  dv.realloc(arg_prop, std::forward<Args>(args)...);
1294 }
1295 
1296 } // end namespace Kokkos
1297 
1298 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1299 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
1300 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DUALVIEW
1301 #endif
1302 #endif
View< typename traits::non_const_data_type, typename traits::array_layout, Device< DefaultHostExecutionSpace, typename traits::host_mirror_space::memory_space >, typename traits::hooks_policy > HostMirror
Compatible HostMirror view.