Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Host/Device accessors for mdspan #3686

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b115039
first draft
fbusato Feb 5, 2025
0ea452d
split implemenation
fbusato Feb 5, 2025
9ae4953
add host/device pointer checks
fbusato Feb 5, 2025
96f8419
add pointer checks
fbusato Feb 6, 2025
52b12a6
add tests
fbusato Feb 6, 2025
cab748e
fix device/host memory accessibility detection
fbusato Feb 6, 2025
31b84c7
fix typo
fbusato Feb 6, 2025
430e46d
add recursive traits
fbusato Feb 6, 2025
3c76d32
prevent ADL
fbusato Feb 6, 2025
d63980d
size_t namespace
fbusato Feb 6, 2025
e9ce8a4
is_pointer namespace
fbusato Feb 6, 2025
de4264c
fix __self
fbusato Feb 7, 2025
c0d12da
add noexcept
fbusato Feb 7, 2025
572447d
Update libcudacxx/include/cuda/__mdspan/host_device_accessor.h
fbusato Feb 8, 2025
0eb90ef
Update libcudacxx/include/cuda/__mdspan/host_device_accessor.h
fbusato Feb 8, 2025
71a9161
expose accessor types
fbusato Feb 8, 2025
921273a
remove default, copy constructors
fbusato Feb 8, 2025
aef9602
fix default and copy constructors
fbusato Feb 10, 2025
0647703
add inheritance aliases
fbusato Feb 10, 2025
c30482e
Merge branch 'main' into host-device-mdspan-accessors
fbusato Feb 10, 2025
fc82009
add default_accessor constructor and conversion
fbusato Feb 10, 2025
21e2feb
guard cuda_runtime_api.h
fbusato Feb 14, 2025
22fecf3
Merge branch 'main' into host-device-mdspan-accessors
fbusato Feb 14, 2025
ca47b44
Update libcudacxx/include/cuda/__mdspan/host_device_accessor.h
fbusato Feb 20, 2025
9a7e393
add detectably_invalid
fbusato Feb 20, 2025
a0af8f4
add __managed_accessor conversions from/to default_accessors
fbusato Feb 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 131 additions & 78 deletions libcudacxx/include/cuda/__mdspan/host_device_accessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,35 @@
# pragma system_header
#endif // no system header

#include <cuda_runtime_api.h>
#include <cuda_runtime_api.h> // TODO: the code should compile even outside nvcc

#include <cuda/std/__type_traits/is_convertible.h>
#include <cuda/std/__type_traits/is_default_constructible.h>
#include <cuda/std/__type_traits/is_pointer.h>
#include <cuda/std/cassert>
#include <cuda/std/cstddef>
//
#include <cuda/std/__concepts/__concept_macros.h>

_LIBCUDACXX_BEGIN_NAMESPACE_CUDA

template <typename _Accessor>
struct host_accessor;
struct __host_accessor;

template <typename _Accessor>
struct __device_accessor;

template <typename _Accessor>
struct __managed_accessor;

template <typename _Accessor>
using host_accessor = __host_accessor<_Accessor>;

template <typename _Accessor>
struct device_accessor;
using device_accessor = __device_accessor<_Accessor>;

template <typename _Accessor>
struct managed_accessor;
using managed_accessor = __managed_accessor<_Accessor>;

/***********************************************************************************************************************
* Host/Device/Managed Accessor Traits
Expand All @@ -52,13 +65,13 @@ template <typename>
inline constexpr bool is_managed_accessor_v = false;

template <typename _Accessor>
inline constexpr bool is_host_accessor_v<host_accessor<_Accessor>> = true;
inline constexpr bool is_host_accessor_v<__host_accessor<_Accessor>> = true;

template <typename _Accessor>
inline constexpr bool is_device_accessor_v<device_accessor<_Accessor>> = true;
inline constexpr bool is_device_accessor_v<__device_accessor<_Accessor>> = true;

template <typename _Accessor>
inline constexpr bool is_managed_accessor_v<managed_accessor<_Accessor>> = true;
inline constexpr bool is_managed_accessor_v<__managed_accessor<_Accessor>> = true;

template <typename _Tp>
inline constexpr bool is_host_device_managed_accessor_v =
Expand All @@ -69,25 +82,28 @@ inline constexpr bool is_host_device_managed_accessor_v =
**********************************************************************************************************************/

template <typename _Accessor>
struct host_accessor : public _Accessor
struct __host_accessor : public _Accessor
{
static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::__host_accessor/cuda::__device_accessor/cuda::__managed_accessor cannot be nested");

using offset_policy = __host_accessor<typename _Accessor::offset_policy>;
using data_handle_type = typename _Accessor::data_handle_type;
using reference = typename _Accessor::reference;
using element_type = typename _Accessor::element_type;

private:
using __data_handle_type = typename _Accessor::data_handle_type;
using __reference = typename _Accessor::reference;
using __self = host_accessor<_Accessor>;
using __self = __host_accessor<_Accessor>;

static constexpr bool __is_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(__data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(__data_handle_type{}, 0));
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{_Accessor{}});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(data_handle_type{}, 0));

static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::host_accessor/cuda::device_accessor/cuda::managed_accessor cannot be nested");

template <typename __data_handle_type>
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool __is_host_accessible_pointer(__data_handle_type __p) noexcept
template <typename data_handle_type>
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool __is_host_accessible_pointer(data_handle_type __p) noexcept
{
if constexpr (_CUDA_VSTD::is_pointer_v<__data_handle_type>)
if constexpr (_CUDA_VSTD::is_pointer_v<data_handle_type>)
{
cudaPointerAttributes __attrib;
_CCCL_VERIFY(::cudaPointerGetAttributes(&__attrib, __p) == ::cudaSuccess, "cudaPointerGetAttributes failed");
Expand All @@ -99,35 +115,45 @@ struct host_accessor : public _Accessor
}
}

_LIBCUDACXX_HIDE_FROM_ABI static constexpr void __check_host_pointer(__data_handle_type __p) noexcept
_LIBCUDACXX_HIDE_FROM_ABI static constexpr void __check_host_pointer(data_handle_type __p) noexcept
{
_CCCL_ASSERT(__self::__is_host_accessible_pointer(__p), "cuda::host_accessor data handle is not a HOST pointer");
_CCCL_ASSERT(__self::__is_host_accessible_pointer(__p), "cuda::__host_accessor data handle is not a HOST pointer");
}

public:
using offset_policy = host_accessor<typename _Accessor::offset_policy>;
using data_handle_type = __data_handle_type;
using reference = __reference;
using element_type = typename _Accessor::element_type;
_CCCL_HIDE_FROM_ABI host_accessor() noexcept(__is_ctor_noexcept) = default;

_CCCL_HIDE_FROM_ABI host_accessor(const host_accessor&) noexcept(__is_copy_ctor_noexcept) = default;

_LIBCUDACXX_HIDE_FROM_ABI constexpr __reference access(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_CCCL_TEMPLATE(typename _NotUsed = void)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_default_constructible, _Accessor))
_LIBCUDACXX_HIDE_FROM_ABI __host_accessor() noexcept(__is_ctor_noexcept)
: _Accessor{}
{}

_CCCL_TEMPLATE(typename _OtherElementType)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _OtherElementType (*)[], element_type (*)[]))
_LIBCUDACXX_HIDE_FROM_ABI constexpr __host_accessor(__host_accessor<_OtherElementType>) noexcept(
__is_copy_ctor_noexcept)
{}

_CCCL_TEMPLATE(typename _OtherElementType)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _OtherElementType (*)[], element_type (*)[]))
_LIBCUDACXX_HIDE_FROM_ABI constexpr __host_accessor(__managed_accessor<_OtherElementType>) noexcept(
__is_copy_ctor_noexcept)
{}
Comment on lines +131 to +147
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a previous review, I mentioned the issue that this omits all the conversions to and from _Accessor that the _Accessor class defines. I just want to mention it again so I don't forget : - ) . Conversions are an important part of an accessor's interface, because they help define conversions for mdspan itself. For example, without default_accessor's converting constructor, you can't assign mdspan-of-nonconst to mdspan-of-const. Section 5.8 of P2897 elaborates this explanation.

Should we consider instead a CRTP base class approach to __*_accessor? That would let developers of custom accessors opt into the run-time pointer checking functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be that you reviewed an older version? I previously added conversions from/to default_accessor for host_accessor and device_accessor.
Honestly, I'm was sure about managed_accessor because it looks unsafe...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider instead a CRTP base class approach to __*_accessor? That would let developers of custom accessors opt into the run-time pointer checking functionality.

the idea is nice. I'm a bit concerned about the implications for users. Could host_accessor be roughly defined in the following way?

class host_accessor : public __host_accessor<cuda::std::default_accessor> { .. };

Copy link
Contributor

@mhoemmen mhoemmen Feb 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fbusato wrote:

could be that you reviewed an older version? I previously added conversions from/to default_accessor for host_accessor and device_accessor.

The issue is with transitive conversions for a possibly generic _Accessor.

For example, suppose that I define two accessors A and B. A is weaker (more type-erased) than B. A defines an implicit conversion from B, and B defines an explicit conversion from A. (This follows the idiom that explicit conversions assert preconditions, while implicit conversions have no preconditions.) One example of this case is A = default_accessor<float>, and B = aligned_accessor<float, 16>.

struct A {
  // ... other accessor stuff ...
  A(B) {}
};

struct B {
  // ... other accessor stuff ...
  explicit B(A) {}
};

The problem is, these conversions don't carry over to {host,device,managed}_accessor. For example, host_accessor<A> does not have an implicit conversion from host_accessor<B>, and host_accessor<B> does not have an explicit conversion from host_accessor<A>.

Here's a draft for how to fix this. I would need to prototype this a bit to make sure it works.

template<class _Accessor>
class host_accessor {
private:
  _Accessor acc_;

  // ... details ...
public:
  // ... other constructors ...

  // This case covers host_accessor<default_accessor<OtherElementType>> as well.
  template<class InputAccessor>
  // If _Accessor is constructible from InputAccessor, then
  // host_accessor<_Accessor> is constructible from
  // host_accessor<InputAccessor>.
  requires(is_constructible<_Accessor, const InputAccessor&>)
  constexpr
  // Conversion is explicit if there is no implicit conversion
  // from InputAccessor to _Accessor.
  explicit(! is_convertible_v<const InputAccessor&, _Accessor>)
  host_accessor(const host_accessor<InputAccessor>& input_acc)
    : acc_(input_acc)
  {}
};

Copy link
Contributor

@mhoemmen mhoemmen Feb 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fbusato I just sent you an offline message with a link to an example of how to do this correctly. wrapper (see below) is like host_accessor or device_accessor -- an accessor that wraps another accessor. The link explains the design and includes tests and use examples.

template<class Accessor>
requires(not is_wrapper_v<Accessor>)
class wrapper : public Accessor {
public:
  using offset_policy = typename Accessor::offset_policy;
  using element_type = typename Accessor::element_type;
  using reference = typename Accessor::reference;
  using data_handle_type = typename Accessor::data_handle_type;

  constexpr wrapper() noexcept 
    requires(std::is_default_constructible_v<Accessor>)
  = default;

  // "Wrapping constructor" -- takes the inner accessor.
  constexpr wrapper(const Accessor& input_acc)
    : Accessor(input_acc)
  {}

  template<class OtherAccessor>
  requires(
    std::is_constructible_v<Accessor, OtherAccessor>
  )
  constexpr
  explicit(
    not std::is_convertible_v<OtherAccessor, Accessor>
  )
  wrapper(const wrapper<OtherAccessor>& input_acc)
    : Accessor(input_acc)
  {}

  constexpr reference
  access(data_handle_type p, size_t k) const {
    return Accessor::access(p, k);
  }

  constexpr typename offset_policy::data_handle_type
  offset(data_handle_type p, size_t k) const {
    return Accessor::offset(p, k);
  }
};


_LIBCUDACXX_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_access_noexcept)
{
NV_IF_ELSE_TARGET(NV_IS_HOST,
(__self::__check_host_pointer(__p);), //
(static_assert(false, "cuda::host_accessor cannot be used in DEVICE code");))
(static_assert(false, "cuda::__host_accessor cannot be used in DEVICE code");))
return _Accessor::access(__p, __i);
}

_LIBCUDACXX_HIDE_FROM_ABI constexpr __data_handle_type offset(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_LIBCUDACXX_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_offset_noexcept)
{
NV_IF_ELSE_TARGET(NV_IS_HOST,
(__self::__check_host_pointer(__p);), //
(static_assert(false, "cuda::host_accessor cannot be used in DEVICE code");))
(static_assert(false, "cuda::__host_accessor cannot be used in DEVICE code");))
return _Accessor::offset(__p, __i);
}
};
Expand All @@ -137,42 +163,57 @@ struct host_accessor : public _Accessor
**********************************************************************************************************************/

template <typename _Accessor>
struct device_accessor : public _Accessor
struct __device_accessor : public _Accessor
{
static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::__host_accessor/cuda::__device_accessor/cuda::__managed_accessor cannot be nested");

using offset_policy = __device_accessor<typename _Accessor::offset_policy>;
using data_handle_type = typename _Accessor::data_handle_type;
using reference = typename _Accessor::reference;
using element_type = typename _Accessor::element_type;

private:
using __data_handle_type = typename _Accessor::data_handle_type;
using __reference = typename _Accessor::reference;
using __self = device_accessor<_Accessor>;
using __self = __device_accessor<_Accessor>;

static constexpr bool __is_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(__data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(__data_handle_type{}, 0));

static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::host_accessor/cuda::device_accessor/cuda::managed_accessor cannot be nested");
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{_Accessor{}});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(data_handle_type{}, 0));

template <typename _Sp = bool> // lazy evaluation
_LIBCUDACXX_HIDE_FROM_ABI static constexpr void __prevent_host_instantiation() noexcept
{
static_assert(sizeof(_Sp) != sizeof(_Sp), "cuda::device_accessor cannot be used in HOST code");
static_assert(sizeof(_Sp) != sizeof(_Sp), "cuda::__device_accessor cannot be used in HOST code");
}

public:
using offset_policy = device_accessor;

_CCCL_HIDE_FROM_ABI device_accessor() noexcept(__is_ctor_noexcept) = default;

_CCCL_HIDE_FROM_ABI device_accessor(const device_accessor&) noexcept(__is_copy_ctor_noexcept) = default;

_LIBCUDACXX_HIDE_FROM_ABI constexpr __reference access(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_CCCL_TEMPLATE(typename _NotUsed = void)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_default_constructible, _Accessor))
_LIBCUDACXX_HIDE_FROM_ABI __device_accessor() noexcept(__is_ctor_noexcept)
: _Accessor{}
{}

_CCCL_TEMPLATE(typename _OtherElementType)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _OtherElementType (*)[], element_type (*)[]))
_LIBCUDACXX_HIDE_FROM_ABI constexpr __device_accessor(__device_accessor<_OtherElementType>) noexcept(
__is_copy_ctor_noexcept)
{}

_CCCL_TEMPLATE(typename _OtherElementType)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _OtherElementType (*)[], element_type (*)[]))
_LIBCUDACXX_HIDE_FROM_ABI constexpr __device_accessor(__managed_accessor<_OtherElementType>) noexcept(
__is_copy_ctor_noexcept)
{}

_LIBCUDACXX_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_access_noexcept)
{
NV_IF_TARGET(NV_IS_HOST, (__self::__prevent_host_instantiation();))
return _Accessor::access(__p, __i);
}

_LIBCUDACXX_HIDE_FROM_ABI constexpr __data_handle_type offset(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_LIBCUDACXX_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_offset_noexcept)
{
NV_IF_TARGET(NV_IS_HOST, (__self::__prevent_host_instantiation();))
Expand All @@ -185,25 +226,31 @@ struct device_accessor : public _Accessor
**********************************************************************************************************************/

template <typename _Accessor>
struct managed_accessor : public _Accessor
struct __managed_accessor : public _Accessor
{
static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::__host_accessor/cuda::__device_accessor/cuda::__managed_accessor cannot be nested");

using offset_policy = __managed_accessor<typename _Accessor::offset_policy>;
using data_handle_type = typename _Accessor::data_handle_type;
using reference = typename _Accessor::reference;
using element_type = typename _Accessor::element_type;

private:
using __data_handle_type = typename _Accessor::data_handle_type;
using __reference = typename _Accessor::reference;
using __self = managed_accessor<_Accessor>;
using __self = __managed_accessor<_Accessor>;

static constexpr bool __is_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(__data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(__data_handle_type{}, 0));
static constexpr bool __is_copy_ctor_noexcept = noexcept(_Accessor{_Accessor{}});
static constexpr bool __is_access_noexcept = noexcept(_Accessor{}.access(data_handle_type{}, 0));
static constexpr bool __is_offset_noexcept = noexcept(_Accessor{}.offset(data_handle_type{}, 0));

static_assert(!is_host_device_managed_accessor_v<_Accessor>,
"cuda::host_accessor/cuda::device_accessor/cuda::managed_accessor cannot be nested");
"cuda::__host_accessor/cuda::__device_accessor/cuda::__managed_accessor cannot be nested");

template <typename __data_handle_type>
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool __is_managed_pointer(__data_handle_type __p) noexcept
template <typename data_handle_type>
_LIBCUDACXX_HIDE_FROM_ABI static constexpr bool __is_managed_pointer(data_handle_type __p) noexcept
{
if constexpr (_CUDA_VSTD::is_pointer_v<__data_handle_type>)
if constexpr (_CUDA_VSTD::is_pointer_v<data_handle_type>)
{
cudaPointerAttributes __attrib;
_CCCL_VERIFY(::cudaPointerGetAttributes(&__attrib, __p) == ::cudaSuccess, "cudaPointerGetAttributes failed");
Expand All @@ -215,26 +262,32 @@ struct managed_accessor : public _Accessor
}
}

_LIBCUDACXX_HIDE_FROM_ABI static constexpr void __check_managed_pointer(__data_handle_type __p) noexcept
_LIBCUDACXX_HIDE_FROM_ABI static constexpr void __check_managed_pointer(data_handle_type __p) noexcept
{
_CCCL_ASSERT(__self::__is_managed_pointer(__p), "cuda::managed_accessor data handle is not a MANAGED pointer");
_CCCL_ASSERT(__self::__is_managed_pointer(__p), "cuda::__managed_accessor data handle is not a MANAGED pointer");
}

public:
using offset_policy = managed_accessor;

_CCCL_HIDE_FROM_ABI managed_accessor() noexcept(__is_ctor_noexcept) = default;

_CCCL_HIDE_FROM_ABI managed_accessor(const managed_accessor&) noexcept(__is_copy_ctor_noexcept) = default;

_LIBCUDACXX_HIDE_FROM_ABI constexpr __reference access(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_CCCL_TEMPLATE(typename _NotUsed = void)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_default_constructible, _Accessor))
_LIBCUDACXX_HIDE_FROM_ABI __managed_accessor() noexcept(__is_ctor_noexcept)
: _Accessor{}
{}

_CCCL_TEMPLATE(typename _OtherElementType)
_CCCL_REQUIRES(_CCCL_TRAIT(_CUDA_VSTD::is_convertible, _OtherElementType (*)[], element_type (*)[]))
_LIBCUDACXX_HIDE_FROM_ABI constexpr __managed_accessor(__managed_accessor<_OtherElementType>) noexcept(
__is_copy_ctor_noexcept)
{}

_LIBCUDACXX_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_access_noexcept)
{
NV_IF_TARGET(NV_IS_HOST, (__self::__check_managed_pointer(__p);))
return _Accessor::access(__p, __i);
}

_LIBCUDACXX_HIDE_FROM_ABI constexpr __data_handle_type offset(__data_handle_type __p, _CUDA_VSTD::size_t __i) const
_LIBCUDACXX_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, _CUDA_VSTD::size_t __i) const
noexcept(__is_offset_noexcept)
{
NV_IF_TARGET(NV_IS_HOST, (__self::__check_managed_pointer(__p);))
Expand All @@ -253,19 +306,19 @@ template <typename>
inline constexpr bool is_device_accessible_v = false;

template <typename _Accessor>
inline constexpr bool is_host_accessible_v<host_accessor<_Accessor>> = true;
inline constexpr bool is_host_accessible_v<__host_accessor<_Accessor>> = true;

template <typename _Accessor>
inline constexpr bool is_host_accessible_v<managed_accessor<_Accessor>> = true;
inline constexpr bool is_host_accessible_v<__managed_accessor<_Accessor>> = true;

template <template <typename> class _TClass, typename _Accessor>
inline constexpr bool is_host_accessible_v<_TClass<_Accessor>> = is_host_accessible_v<_Accessor>;

template <typename _Accessor>
inline constexpr bool is_device_accessible_v<device_accessor<_Accessor>> = true;
inline constexpr bool is_device_accessible_v<__device_accessor<_Accessor>> = true;

template <typename _Accessor>
inline constexpr bool is_device_accessible_v<managed_accessor<_Accessor>> = true;
inline constexpr bool is_device_accessible_v<__managed_accessor<_Accessor>> = true;

template <template <typename> class _TClass, typename _Accessor>
inline constexpr bool is_device_accessible_v<_TClass<_Accessor>> = is_device_accessible_v<_Accessor>;
Expand Down