OpenVDB 14.0.0
Loading...
Searching...
No Matches
DeviceResource.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3//
4#ifndef NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED
5#define NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED
6
7#include <cuda_runtime_api.h>
9
10#include <cstddef>
11#include <type_traits>
12#include <utility>
13
14namespace nanovdb {
15
16namespace cuda {
17
18/// @brief Default stream-ordered device memory resource. Allocations are made
19/// with cudaMallocAsync and freed with cudaFreeAsync via the
20/// util::cuda wrappers.
21/// @note Models the AsyncResource concept, which refines the synchronous
22/// Resource concept (as in CCCL's cuda::mr): the instance methods
23/// provide both the stream-ordered allocate_async / deallocate_async
24/// and the synchronous allocate / deallocate. The type is stateless,
25/// so a default-constructed instance adds no overhead.
27{
28public:
29 // cudaMalloc aligns memory to 256 bytes by default
30 static constexpr size_t DEFAULT_ALIGNMENT = 256;
31
32 /// @brief Stream-ordered allocation.
33 /// @param bytes number of bytes to allocate
34 /// @param stream cuda stream the allocation is ordered on
35 /// @note the alignment parameter is unnamed: cudaMallocAsync always
36 /// 256B-aligns
37 void* allocate_async(size_t bytes, size_t, cudaStream_t stream) {
38 void* p = nullptr;
39 cudaCheck(util::cuda::mallocAsync(&p, bytes, stream));
40 return p;
41 }
42
43 /// @brief Stream-ordered deallocation.
44 /// @param p pointer previously returned by allocate_async
45 /// @param stream cuda stream the deallocation is ordered on
46 void deallocate_async(void* p, size_t, size_t, cudaStream_t stream) {
48 }
49
50 /// @brief Synchronous allocation; the returned memory is immediately
51 /// valid on every stream.
52 /// @param bytes number of bytes to allocate
53 /// @param alignment requested alignment
54 void* allocate(size_t bytes, size_t alignment) {
55 void* p = this->allocate_async(bytes, alignment, cudaStream_t(0));
56 cudaCheck(cudaStreamSynchronize(cudaStream_t(0)));
57 return p;
58 }
59
60 /// @brief Synchronous deallocation; the caller guarantees that device
61 /// work touching the memory has completed.
62 /// @param p pointer previously returned by allocate or allocate_async
63 /// @param bytes size of the allocation in bytes
64 /// @param alignment alignment of the allocation in bytes
65 void deallocate(void* p, size_t bytes, size_t alignment) {
66 this->deallocate_async(p, bytes, alignment, cudaStream_t(0));
67 }
68
69 /// @brief Stateless: memory allocated through one instance may be
70 /// deallocated through any other, so every two instances compare
71 /// equal (the equality cuda::mr's resource concepts require).
72 friend bool operator==(const DeviceResource&, const DeviceResource&) { return true; }
73 friend bool operator!=(const DeviceResource&, const DeviceResource&) { return false; }
74};
75
76/// @brief Returns a program-lifetime, address-stable reference to a default
77/// instance of resource @c R.
78/// @details The instance is a function-local static, so it outlives every
79/// caller and is safe to bind through a default function/constructor
80/// argument. @c R must be default-constructible.
81template <class R>
83{
84 static R sResource;
85 return sResource;
86}
87
88/// @brief Detection trait: @c is_async_resource<R>::value is true iff @c R
89/// models the stream-ordered AsyncResource concept, i.e. exposes
90/// allocate_async(size_t, size_t, cudaStream_t) and
91/// deallocate_async(void*, size_t, size_t, cudaStream_t).
92/// @details Use it to dispatch between a stream-ordered resource and a
93/// synchronous one (which exposes allocate/deallocate without a
94/// stream argument):
95/// @code
96/// template<typename R>
97/// void* allocate(R& resource, size_t bytes, size_t alignment, cudaStream_t stream)
98/// {
99/// if constexpr (nanovdb::cuda::is_async_resource<R>::value)
100/// return resource.allocate_async(bytes, alignment, stream); // stream-ordered
101/// else
102/// return resource.allocate(bytes, alignment); // synchronous
103/// }
104/// @endcode
105/// @note AsyncResource refines the synchronous Resource concept, matching
106/// CCCL's cuda::mr: an async resource must also provide the
107/// synchronous allocate / deallocate, so is_async_resource<R> implies
108/// is_resource<R>. A synchronous-only resource (e.g. PinnedResource)
109/// models just is_resource. The synchronous methods of a stream-ordered
110/// resource are typically thin delegates (allocate_async on the null
111/// stream followed by a stream synchronize).
112template <class R, class = void>
113struct is_async_resource : std::false_type {};
114
115template <class R>
116struct is_async_resource<R, std::void_t<
117 decltype(std::declval<R&>().allocate_async(size_t{0}, size_t{0}, cudaStream_t{0})),
118 decltype(std::declval<R&>().deallocate_async(std::declval<void*>(), size_t{0}, size_t{0}, cudaStream_t{0})),
119 decltype(std::declval<R&>().allocate(size_t{0}, size_t{0})),
120 decltype(std::declval<R&>().deallocate(std::declval<void*>(), size_t{0}, size_t{0}))>>
121 : std::true_type {};
122
123/// @brief Detection trait: @c is_host_accessible_resource<R>::value is true
124/// iff @c R declares `static constexpr bool HOST_ACCESSIBLE = true`,
125/// i.e. its allocations are mapped into the host address space (e.g.
126/// PinnedResource). Defaults to false: allocations are device-resident.
127/// @note Unlike the void_t detections above, this checks the member's VALUE:
128/// a resource declaring HOST_ACCESSIBLE = false stays device-resident.
129template<typename R, typename = void>
130struct is_host_accessible_resource : std::false_type {};
131template<typename R>
132struct is_host_accessible_resource<R, typename std::enable_if<bool(R::HOST_ACCESSIBLE)>::type> : std::true_type {};
133
134/// @brief Companion detection: @c is_device_accessible_resource<R>::value is
135/// true iff @c R declares `static constexpr bool DEVICE_ACCESSIBLE =
136/// true`, i.e. its allocations are also valid device addresses even
137/// though they are host-accessible (e.g. ManagedResource). A handle
138/// over such a resource exposes both accessor families. Purely
139/// device-resident resources do not need the marker: not being
140/// host-accessible already implies device residency.
141template<typename R, typename = void>
142struct is_device_accessible_resource : std::false_type {};
143template<typename R>
144struct is_device_accessible_resource<R, typename std::enable_if<bool(R::DEVICE_ACCESSIBLE)>::type> : std::true_type {};
145
146/// @brief Detection trait: @c is_resource<R>::value is true iff @c R models
147/// the synchronous Resource concept, i.e. exposes
148/// allocate(size_t, size_t) and deallocate(void*, size_t, size_t).
149/// @details Use it to constrain code paths that need a resource without a
150/// stream argument, e.g. host-side allocations:
151/// @code
152/// template<typename R>
153/// void* allocate(R& resource, size_t bytes, size_t alignment)
154/// {
155/// static_assert(nanovdb::cuda::is_resource<R>::value, "R must be a synchronous resource");
156/// return resource.allocate(bytes, alignment);
157/// }
158/// @endcode
159template <class R, class = void>
160struct is_resource : std::false_type {};
161
162template <class R>
163struct is_resource<R, std::void_t<
164 decltype(std::declval<R&>().allocate(size_t{0}, size_t{0})),
165 decltype(std::declval<R&>().deallocate(std::declval<void*>(), size_t{0}, size_t{0}))>>
166 : std::true_type {};
167
168/// @brief Detection trait: @c is_equality_comparable_resource<R>::value is
169/// true iff @c R models a resource concept and provides operator==:
170/// two resources compare equal when memory allocated through one may
171/// be deallocated through the other. cuda::Buffer and
172/// cuda::ResourceRef static_assert it, as cuda::mr's resource concepts
173/// require it.
174template <class R, class = void>
175struct is_equality_comparable_resource : std::false_type {};
176
177template <class R>
179 std::enable_if_t<is_resource<R>::value || is_async_resource<R>::value>,
180 decltype(bool(std::declval<const R&>() == std::declval<const R&>()))>>
181 : std::true_type {};
182
183/// @brief CRTP base supplying the synchronous half of the resource concept in
184/// terms of the stream-ordered half, so a custom stream-ordered resource
185/// only has to write allocate_async and deallocate_async.
186/// @tparam Derived the resource deriving from this base
187/// @details A stream-ordered resource must also model the synchronous concept
188/// (is_async_resource implies is_resource), which means writing four
189/// methods where two would do. The synchronous pair is not a bare
190/// delegate: memory from allocate must be usable immediately on any
191/// stream, so the null-stream allocation has to be synchronized before
192/// it is returned. Omitting that synchronization yields memory that
193/// satisfies the concept but is not actually synchronous -- a race
194/// rather than a compile error -- so it lives here rather than being
195/// rewritten per resource.
196/// @code
197/// struct MyResource : nanovdb::cuda::SyncFromAsync<MyResource> {
198/// static constexpr size_t DEFAULT_ALIGNMENT = 256;
199/// void* allocate_async(size_t bytes, size_t alignment, cudaStream_t stream);
200/// void deallocate_async(void* p, size_t bytes, size_t alignment, cudaStream_t stream);
201/// // equality, as cuda::mr requires: stateless, so every instance is interchangeable
202/// friend bool operator==(const MyResource&, const MyResource&) { return true; }
203/// friend bool operator!=(const MyResource&, const MyResource&) { return false; }
204/// };
205/// @endcode
206template <class Derived>
208{
209 /// @brief Allocates @c bytes usable on any stream when this returns.
210 /// @param bytes number of bytes to allocate
211 /// @param alignment requested alignment
212 /// @note Every call synchronizes the null stream; on hot paths prefer the
213 /// stream-ordered pair.
214 void* allocate(size_t bytes, size_t alignment)
215 {
216 void* p = static_cast<Derived&>(*this).allocate_async(bytes, alignment, cudaStream_t{0});
217 cudaCheck(cudaStreamSynchronize(cudaStream_t{0}));
218 return p;
219 }
220
221 /// @brief Frees @c p on the null stream.
222 /// @param p pointer previously returned by allocate
223 /// @param bytes size passed to the matching allocate
224 /// @param alignment alignment passed to the matching allocate
225 /// @note No synchronization here: the synchronous concept's contract is
226 /// that the memory is already quiescent when deallocate is called.
227 void deallocate(void* p, size_t bytes, size_t alignment)
228 {
229 static_cast<Derived&>(*this).deallocate_async(p, bytes, alignment, cudaStream_t{0});
230 }
231};
232
233/// @brief Synchronous device memory resource backed by cudaMalloc/cudaFree.
234/// Models only the Resource concept: it never touches stream-ordered
235/// allocation, so it works on devices without memory-pool support
236/// (cudaDevAttrMemoryPoolsSupported == 0), where DeviceResource's
237/// cudaMallocAsync path fails by design. Pair with AsyncFromSync to
238/// drive the stream-ordered builders on such a device.
240{
241public:
242 // cudaMalloc aligns memory to 256 bytes by default
243 static constexpr size_t DEFAULT_ALIGNMENT = 256;
244
245 /// @brief Allocates @c bytes with cudaMalloc; valid on every stream when
246 /// this returns. A zero request returns nullptr.
247 void* allocate(size_t bytes, size_t)
248 {
249 if (bytes == 0) return nullptr;
250 void* p = nullptr;
251 cudaCheck(cudaMalloc(&p, bytes));
252 return p;
253 }
254
255 /// @brief Frees @c p with cudaFree; the caller guarantees that device work
256 /// touching the memory has completed.
257 void deallocate(void* p, size_t, size_t) { cudaCheck(cudaFree(p)); }
258
259 /// @brief Stateless: memory allocated through one instance may be
260 /// deallocated through any other, so every two instances compare
261 /// equal (the equality cuda::mr's resource concepts require).
262 friend bool operator==(const MallocResource&, const MallocResource&) { return true; }
263 friend bool operator!=(const MallocResource&, const MallocResource&) { return false; }
264};// MallocResource
265
266/// @brief Wrapper presenting a synchronous resource as a stream-ordered one,
267/// so it can drive components that require the AsyncResource concept
268/// (TempPool and the GPU builders).
269/// @tparam R the wrapped synchronous resource, held by value; wrap a
270/// ResourceRef<R> to borrow a stateful instance instead.
271/// @details The mirror of SyncFromAsync, and the analog of cuda::mr's
272/// synchronous_resource_adapter. allocate_async forwards to
273/// R::allocate, whose memory is immediately valid on every stream --
274/// a stronger guarantee than stream-ordering requires.
275/// deallocate_async synchronizes @c stream before R::deallocate,
276/// establishing the quiescence the synchronous contract demands.
277/// @warning Every deallocation synchronizes its stream, so expect
278/// serialization relative to a genuinely stream-ordered resource.
279/// That is the unavoidable cost of a synchronous backend under a
280/// stream-ordered algorithm; this wrapper exists so the cost is
281/// explicit and chosen by the caller -- e.g. on a device without
282/// memory-pool support -- rather than silently substituted.
283template<class R>
285{
286 static_assert(is_resource<R>::value,
287 "AsyncFromSync requires R to model the synchronous Resource concept");
288
289 static constexpr size_t DEFAULT_ALIGNMENT = R::DEFAULT_ALIGNMENT;
290
291 /// @brief The adapter is host-accessible iff the adapted resource is.
294
296
297 /// @brief Allocates through the synchronous resource; the result is valid
298 /// on every stream, hence trivially valid on @c stream.
299 void* allocate_async(size_t bytes, size_t alignment, cudaStream_t) { return resource.allocate(bytes, alignment); }
300
301 /// @brief Synchronizes @c stream, then frees through the synchronous
302 /// resource -- the synchronize makes the quiescence contract hold.
303 /// Null is a no-op and skips the synchronize.
304 void deallocate_async(void* p, size_t bytes, size_t alignment, cudaStream_t stream)
305 {
306 if (p == nullptr) return;
307 cudaCheck(cudaStreamSynchronize(stream));
308 resource.deallocate(p, bytes, alignment);
309 }
310
311 /// @brief Synchronous pair, forwarding to the wrapped resource.
312 void* allocate(size_t bytes, size_t alignment) { return resource.allocate(bytes, alignment); }
313 void deallocate(void* p, size_t bytes, size_t alignment) { resource.deallocate(p, bytes, alignment); }
314
315 /// @brief Two adapters compare equal iff their wrapped resources do;
316 /// present only when @c R itself is equality-comparable.
317 template<class S = R, std::enable_if_t<is_equality_comparable_resource<S>::value, int> = 0>
318 friend bool operator==(const AsyncFromSync& lhs, const AsyncFromSync& rhs) { return lhs.resource == rhs.resource; }
319 template<class S = R, std::enable_if_t<is_equality_comparable_resource<S>::value, int> = 0>
320 friend bool operator!=(const AsyncFromSync& lhs, const AsyncFromSync& rhs) { return !(lhs.resource == rhs.resource); }
321};// AsyncFromSync<R>
322
323/// @brief Non-owning reference to a memory resource that is itself a resource:
324/// copying the ref shares the underlying resource rather than copying it.
325/// @tparam R the referenced resource type
326/// @details Types that hold their resource by value -- cuda::Buffer, matching
327/// cuda::buffer -- select their ownership semantics by what is placed
328/// in that slot: a concrete resource is owned as a copy, while a
329/// ResourceRef borrows. This is the same division cuda::mr draws
330/// between any_resource (owning) and resource_ref (borrowing), and the
331/// same shape as std::pmr::polymorphic_allocator over memory_resource*.
332/// Use it when a resource is stateful or long-lived and a container
333/// must allocate through *that* instance rather than a copy of it.
334/// @warning The referenced resource must outlive every use of this ref and of
335/// all copies of it, including any container holding one.
336template <class R>
338{
340 "ResourceRef requires R to model the AsyncResource or the Resource concept");
342 "a memory resource needs operator==: add friend bool operator==(const R&, const R&), true when memory "
343 "allocated through one may be deallocated through the other (always, for a stateless resource), "
344 "and operator!= for cuda::mr under C++17");
345
346 static constexpr size_t DEFAULT_ALIGNMENT = R::DEFAULT_ALIGNMENT;
347
348 /// @brief A reference is host-accessible iff the referenced resource is.
351
352 /// @brief Constructs a ref borrowing @c resource.
353 /// @param resource resource to allocate from; must outlive this ref
354 ResourceRef(R& resource) : mResource(&resource) {}
355
356 /// @{
357 /// @brief Stream-ordered pair, present only when @c R models AsyncResource,
358 /// so a ref over a synchronous resource does not misreport its tier.
359 template<class S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
360 void* allocate_async(size_t bytes, size_t alignment, cudaStream_t stream)
361 {
362 return mResource->allocate_async(bytes, alignment, stream);
363 }
364 template<class S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
365 void deallocate_async(void* p, size_t bytes, size_t alignment, cudaStream_t stream)
366 {
367 mResource->deallocate_async(p, bytes, alignment, stream);
368 }
369 /// @}
370
371 /// @brief Synchronous pair, forwarding to the referenced resource.
372 void* allocate(size_t bytes, size_t alignment) { return mResource->allocate(bytes, alignment); }
373 void deallocate(void* p, size_t bytes, size_t alignment) { mResource->deallocate(p, bytes, alignment); }
374
375 /// @brief Two refs compare equal iff memory allocated through one may be
376 /// deallocated through the other: they reference the same resource,
377 /// or resources that compare equal, as cuda::mr::resource_ref does.
378 friend bool operator==(ResourceRef lhs, ResourceRef rhs)
379 {
380 return lhs.mResource == rhs.mResource || *lhs.mResource == *rhs.mResource;
381 }
382 friend bool operator!=(ResourceRef lhs, ResourceRef rhs) { return !(lhs == rhs); }
383
384private:
385 R* mResource;
386};// ResourceRef<R>
387
388namespace detail {
389
390/// @brief Returns a ResourceRef to @c resource: the one spelling NanoVDB's
391/// own components use to borrow a caller's resource.
392template<class R>
393ResourceRef<R> borrowInternal(R& resource) { return ResourceRef<R>(resource); }
394
395}// namespace detail
396
397}
398
399} // namespace nanovdb::cuda
400
401
402#endif // end of NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED
Default stream-ordered device memory resource. Allocations are made with cudaMallocAsync and freed wi...
Definition DeviceResource.h:27
friend bool operator!=(const DeviceResource &, const DeviceResource &)
Definition DeviceResource.h:73
void deallocate(void *p, size_t bytes, size_t alignment)
Synchronous deallocation; the caller guarantees that device work touching the memory has completed.
Definition DeviceResource.h:65
void * allocate(size_t bytes, size_t alignment)
Synchronous allocation; the returned memory is immediately valid on every stream.
Definition DeviceResource.h:54
void * allocate_async(size_t bytes, size_t, cudaStream_t stream)
Stream-ordered allocation.
Definition DeviceResource.h:37
void deallocate_async(void *p, size_t, size_t, cudaStream_t stream)
Stream-ordered deallocation.
Definition DeviceResource.h:46
static constexpr size_t DEFAULT_ALIGNMENT
Definition DeviceResource.h:30
friend bool operator==(const DeviceResource &, const DeviceResource &)
Stateless: memory allocated through one instance may be deallocated through any other,...
Definition DeviceResource.h:72
Synchronous device memory resource backed by cudaMalloc/cudaFree. Models only the Resource concept: i...
Definition DeviceResource.h:240
friend bool operator!=(const MallocResource &, const MallocResource &)
Definition DeviceResource.h:263
friend bool operator==(const MallocResource &, const MallocResource &)
Stateless: memory allocated through one instance may be deallocated through any other,...
Definition DeviceResource.h:262
void deallocate(void *p, size_t, size_t)
Frees p with cudaFree; the caller guarantees that device work touching the memory has completed.
Definition DeviceResource.h:257
static constexpr size_t DEFAULT_ALIGNMENT
Definition DeviceResource.h:243
void * allocate(size_t bytes, size_t)
Allocates bytes with cudaMalloc; valid on every stream when this returns. A zero request returns null...
Definition DeviceResource.h:247
Definition VoxToNanoVDB.h:15
ResourceRef< R > borrowInternal(R &resource)
Returns a ResourceRef to resource: the one spelling NanoVDB's own components use to borrow a caller's...
Definition DeviceResource.h:393
Definition Buffer.h:24
R & default_resource()
Returns a program-lifetime, address-stable reference to a default instance of resource R.
Definition DeviceResource.h:82
cudaError_t freeAsync(void *d_ptr, cudaStream_t)
Wrapper forced to synchronous cudaFree; see the mode comment above. The trailing stream argument is a...
Definition Util.h:127
cudaError_t mallocAsync(void **d_ptr, size_t size, cudaStream_t)
Wrapper forced to synchronous cudaMalloc; see the mode comment above. The trailing stream argument is...
Definition Util.h:120
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:34
Definition Coord.h:590
Cuda specific utility functions.
#define cudaCheck(ans)
Definition Util.h:49
Wrapper presenting a synchronous resource as a stream-ordered one, so it can drive components that re...
Definition DeviceResource.h:285
static constexpr bool HOST_ACCESSIBLE
The adapter is host-accessible iff the adapted resource is.
Definition DeviceResource.h:292
void deallocate(void *p, size_t bytes, size_t alignment)
Definition DeviceResource.h:313
void * allocate(size_t bytes, size_t alignment)
Synchronous pair, forwarding to the wrapped resource.
Definition DeviceResource.h:312
static constexpr bool DEVICE_ACCESSIBLE
Definition DeviceResource.h:293
static constexpr size_t DEFAULT_ALIGNMENT
Definition DeviceResource.h:289
void * allocate_async(size_t bytes, size_t alignment, cudaStream_t)
Allocates through the synchronous resource; the result is valid on every stream, hence trivially vali...
Definition DeviceResource.h:299
friend bool operator!=(const AsyncFromSync &lhs, const AsyncFromSync &rhs)
Definition DeviceResource.h:320
friend bool operator==(const AsyncFromSync &lhs, const AsyncFromSync &rhs)
Two adapters compare equal iff their wrapped resources do; present only when R itself is equality-com...
Definition DeviceResource.h:318
void deallocate_async(void *p, size_t bytes, size_t alignment, cudaStream_t stream)
Synchronizes stream, then frees through the synchronous resource – the synchronize makes the quiescen...
Definition DeviceResource.h:304
R resource
Definition DeviceResource.h:295
Non-owning reference to a memory resource that is itself a resource: copying the ref shares the under...
Definition DeviceResource.h:338
static constexpr bool HOST_ACCESSIBLE
A reference is host-accessible iff the referenced resource is.
Definition DeviceResource.h:349
void deallocate(void *p, size_t bytes, size_t alignment)
Definition DeviceResource.h:373
void * allocate(size_t bytes, size_t alignment)
Synchronous pair, forwarding to the referenced resource.
Definition DeviceResource.h:372
static constexpr bool DEVICE_ACCESSIBLE
Definition DeviceResource.h:350
friend bool operator!=(ResourceRef lhs, ResourceRef rhs)
Definition DeviceResource.h:382
ResourceRef(R &resource)
Constructs a ref borrowing resource.
Definition DeviceResource.h:354
void deallocate_async(void *p, size_t bytes, size_t alignment, cudaStream_t stream)
Stream-ordered pair, present only when R models AsyncResource, so a ref over a synchronous resource d...
Definition DeviceResource.h:365
static constexpr size_t DEFAULT_ALIGNMENT
Definition DeviceResource.h:346
void * allocate_async(size_t bytes, size_t alignment, cudaStream_t stream)
Stream-ordered pair, present only when R models AsyncResource, so a ref over a synchronous resource d...
Definition DeviceResource.h:360
friend bool operator==(ResourceRef lhs, ResourceRef rhs)
Two refs compare equal iff memory allocated through one may be deallocated through the other: they re...
Definition DeviceResource.h:378
CRTP base supplying the synchronous half of the resource concept in terms of the stream-ordered half,...
Definition DeviceResource.h:208
void deallocate(void *p, size_t bytes, size_t alignment)
Frees p on the null stream.
Definition DeviceResource.h:227
void * allocate(size_t bytes, size_t alignment)
Allocates bytes usable on any stream when this returns.
Definition DeviceResource.h:214
Detection trait: is_async_resource<R>::value is true iff R models the stream-ordered AsyncResource co...
Definition DeviceResource.h:113
Companion detection: is_device_accessible_resource<R>::value is true iff R declares static constexpr ...
Definition DeviceResource.h:142
Detection trait: is_equality_comparable_resource<R>::value is true iff R models a resource concept an...
Definition DeviceResource.h:175
Detection trait: is_host_accessible_resource<R>::value is true iff R declares static constexpr bool H...
Definition DeviceResource.h:130
Detection trait: is_resource<R>::value is true iff R models the synchronous Resource concept,...
Definition DeviceResource.h:160