apoCHARMM 1.0.0
High-performance molecular dynamics simulations on GPUs
 
Loading...
Searching...
No Matches
DeviceVector< T > Class Template Reference

Stores an owned, contiguous sequence in CUDA device memory. More...

#include <DeviceVector.h>

Public Member Functions

 DeviceVector (void)
 Constructs an empty vector without owned device storage.
 
 DeviceVector (const std::size_t count)
 Constructs a vector with uninitialized device storage.
 
 DeviceVector (const std::vector< T > &other)
 Constructs a device vector by copying a host vector.
 
 DeviceVector (const std::vector< T > &&other)
 Constructs a device vector by copying a const host rvalue.
 
 DeviceVector (const DeviceVector< T > &other)
 Constructs an independent copy of another device vector.
 
 DeviceVector (const DeviceVector< T > &&other)
 Constructs an independent copy of a const device-vector rvalue.
 
 ~DeviceVector (void) noexcept
 Releases owned device storage without propagating CUDA failures.
 
DeviceVector< T > & operator= (const std::vector< T > &other)
 Replaces the vector with a copy of a host vector.
 
DeviceVector< T > & operator= (const std::vector< T > &&other)
 Replaces the vector with a copy of a const host rvalue.
 
DeviceVector< T > & operator= (const DeviceVector< T > &other)
 Replaces the vector with a deep copy of another device vector.
 
DeviceVector< T > & operator= (const DeviceVector< T > &&other)
 Replaces the vector with a deep copy of a const device-vector rvalue.
 
const T * data (void) const
 Returns a read-only pointer to the owned device allocation.
 
T * data (void)
 Returns a mutable pointer to the owned device allocation.
 
void assignData (T *data)
 Replaces the stored device pointer without changing metadata.
 
bool empty (void) const
 Returns whether the active element range is empty.
 
std::size_t size (void) const
 Returns the number of active element slots.
 
std::size_t capacity (void) const
 Returns the number of allocated element slots.
 
void shrink_to_fit (void)
 Reduces device capacity to the current size.
 
void clear (void)
 Releases all device storage and resets the vector.
 
void push_back (const T &value)
 Appends one value to the active device sequence.
 
void resize (const std::size_t count)
 Changes the number of active element slots.
 
void swap (DeviceVector< T > &other) noexcept
 Exchanges allocation ownership and metadata with another vector.
 

Detailed Description

template<typename T>
class DeviceVector< T >

Stores an owned, contiguous sequence in CUDA device memory.

DeviceVector owns one CUDA allocation containing capacity() adjacent element slots and identifies the active prefix with size(). It has no host mirror, iterator interface, stream member, or recorded CUDA device. Allocation and copy operations therefore use the CUDA runtime state current on the calling thread. Use CudaContainer when coordinated host and device representations are required.

Elements are handlded as raw storage. The container does not construct, destroy, or value-initialize individual elements. The specializations provided by the current apoCHARMM library are int, int2, int3, int4, unsigned int, float, float2, float3, float4, long long int, longlong2, longlong3, longlong4, unsigned long long int, std::size_t, double, double2, double3, and double4.

Template Parameters
TElement representation stored in device memory. A specialization must be safe to copy byte-for-byte and pass by value to a CUDA kernel.
Warning
The class does not protect its metadata with locks. Callers must serialize access to one object whenever any caller may mutate it.
Pointers returned by data() are device pointers. Host code must not dereference them directly.
See also
device_vector

Constructor & Destructor Documentation

◆ DeviceVector() [1/6]

template<typename T >
DeviceVector< T >::DeviceVector ( void  )

Constructs an empty vector without owned device storage.

Postcondition
empty() is true, size() and capacity() are zero, and data() is nullptr.
Note
This constructor performs no CUDA operation.

◆ DeviceVector() [2/6]

template<typename T >
DeviceVector< T >::DeviceVector ( const std::size_t  count)

Constructs a vector with uninitialized device storage.

Parameters
[in]countNumber of active element slots to allocate.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if the CUDA allocation fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Precondition
count * sizeof(T) is representable as std::size_t.
Postcondition
On success, size() and capacity() equal count. A zero count produces data() == nullptr; otherwise data() identifies an owned device allocation.
Warning
The active element slots are not initialized.

◆ DeviceVector() [3/6]

template<typename T >
DeviceVector< T >::DeviceVector ( const std::vector< T > &  other)

Constructs a device vector by copying a host vector.

Parameters
[in]otherBorrowed, read-only host vector. Its active elements are copied during the call, and no reference to it is retained.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if device allocation or the host-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() and capacity() equal other.size(), and the active device elements are an independent copy of other.
Note
The copy uses cudaMemcpy without an explicit stream and performs no separate device synchronization.

◆ DeviceVector() [4/6]

template<typename T >
DeviceVector< T >::DeviceVector ( const std::vector< T > &&  other)

Constructs a device vector by copying a const host rvalue.

Parameters
[in]otherBorrowed, read-only host vector. Its active elements are copied during the call, and no reference to it is retained.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if device allocation or the host-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() and capacity() equal other.size(), and the active device elements are an independent copy of other.
Note
This overload does not move from or modify other; it performs the same host-to-device copy as the lvalue overload.
The copy uses cudaMemcpy without an explicit stream and performs no separate device synchronization.

◆ DeviceVector() [5/6]

template<typename T >
DeviceVector< T >::DeviceVector ( const DeviceVector< T > &  other)

Constructs an independent copy of another device vector.

Parameters
[in]otherBorrowed, read-only source vector. Its active device elements are copied during the call, and no pointer into it is retained.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if device allocation or the device-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() and capacity() equal other.size(), and the active elements reside in an allocation independent of other.
Note
Spare capacity in other is not copied.
The copy uses cudaMemcpy without an explicit stream and performs no separate device synchronization.

◆ DeviceVector() [6/6]

template<typename T >
DeviceVector< T >::DeviceVector ( const DeviceVector< T > &&  other)

Constructs an independent copy of a const device-vector rvalue.

Parameters
[in]otherBorrowed, read-only source vector. Its active device elements are copied during the call, and no pointer into it is retained.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if device allocation or the device-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() and capacity() equal other.size(), and the active elements reside in an allocation independent of other.
Note
This overload does not transfer ownership from or modify other; it performs the same deep copy as the lvalue copy constructor.
The copy uses cudaMemcpy without an explicit stream and performs no separate device synchronization.

◆ ~DeviceVector()

template<typename T >
DeviceVector< T >::~DeviceVector ( void  )
noexcept

Releases owned device storage without propagating CUDA failures.

The destructor passes the stored pointer to the non-throwing CUDA cleanup helper, clears the metadata, and ignores the return status from cudaFree.

Warning
If CUDA cannot release the allocation, the storage may remain reserved and no diagnostic is reported.

Member Function Documentation

◆ assignData()

template<typename T >
void DeviceVector< T >::assignData ( T *  data)

Replaces the stored device pointer without changing metadata.

This legacy escape hatch performs no copy, allocation, deallocation, or validation. Subsequent clear() or destruction passes the replacement pointer to cudaFree, so a non-null pointer is effectively transferred to this object.

Parameters
[in]dataNullable CUDA allocation pointer to store. When non-null, it must be releasable with cudaFree and identify storage for at least capacity() elements.
Postcondition
data() equals data; size() and capacity() are unchanged.
Warning
Any previously owned allocation is not released and becomes unreachable through this object.
Passing nullptr while capacity() is nonzero, passing borrowed storage, or passing a buffer shorter than capacity() breaks the ownership and storage invariants required by later operations.

◆ capacity()

template<typename T >
std::size_t DeviceVector< T >::capacity ( void  ) const

Returns the number of allocated element slots.

Returns
The device-allocation capacity in elements, not bytes.

◆ clear()

template<typename T >
void DeviceVector< T >::clear ( void  )

Releases all device storage and resets the vector.

Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if cudaFree fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, empty() is true, size() and capacity() are zero, and data() is nullptr.
Note
All previously returned device pointers are invalidated.
Warning
On a deallocation failure, the object still reports the empty state and loses the allocation pointer; the device storage may remain reserved.

◆ data() [1/2]

template<typename T >
T * DeviceVector< T >::data ( void  )

Returns a mutable pointer to the owned device allocation.

Returns
A borrowed CUDA device pointer to the first allocated element slot, or nullptr when no allocation is owned. The pointee storage remains valid until this object is destroyed, cleared, assigned replacement storage, or reallocated. swap() preserves the pointer value but transfers ownership to the other vector.
Note
Mutations through the pointer do not change size() or capacity().
Warning
Host code must not dereference the returned pointer directly.

◆ data() [2/2]

template<typename T >
const T * DeviceVector< T >::data ( void  ) const

Returns a read-only pointer to the owned device allocation.

Returns
A borrowed CUDA device pointer to the first allocated element slot, or nullptr when no allocation is owned. The pointee storage remains valid until this object is destroyed, cleared, assigned replacement storage, or reallocated. swap() preserves the pointer value but transfers ownership to the other vector.
Warning
Host code must not dereference the returned pointer directly.

◆ empty()

template<typename T >
bool DeviceVector< T >::empty ( void  ) const

Returns whether the active element range is empty.

Returns
true when size() is zero; otherwise false. An empty vector may still own storage when capacity() is nonzero.

◆ operator=() [1/4]

template<typename T >
DeviceVector< T > & DeviceVector< T >::operator= ( const DeviceVector< T > &&  other)

Replaces the vector with a deep copy of a const device-vector rvalue.

The destination capacity is changed to other.capacity(), then other.size() active elements are copied device-to-device.

Parameters
[in]otherBorrowed, read-only source vector. No pointer into it is retained after the call.
Returns
A borrowed reference aliasing this destination object. It remains valid for the lifetime of the destination.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix preservation, deallocation, or the final device-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() equals other.size(), capacity() equals other.capacity(), and the active elements are an independent copy.
Note
Source slots in [other.size(), other.capacity()) are not copied.
This overload does not transfer ownership from or modify other.
Any capacity change invalidates previously returned device pointers.
The implementation does not special-case self-assignment and still issues the device-to-device copy.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix preservation fails, the destination remains unchanged. If capacity adjustment fails while releasing the old allocation, the destination is reset to an empty state and the old allocation may remain reserved. If the final device-to-device copy fails, the new size and capacity remain observable and active contents are unspecified.

◆ operator=() [2/4]

template<typename T >
DeviceVector< T > & DeviceVector< T >::operator= ( const DeviceVector< T > &  other)

Replaces the vector with a deep copy of another device vector.

The destination capacity is changed to other.capacity(), then other.size() active elements are copied device-to-device.

Parameters
[in]otherBorrowed, read-only source vector. No pointer into it is retained after the call.
Returns
A borrowed reference aliasing this destination object. It remains valid for the lifetime of the destination.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix preservation, deallocation, or the final device-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() equals other.size(), capacity() equals other.capacity(), and the active elements are an independent copy.
Note
Source slots in [other.size(), other.capacity()) are not copied.
Any capacity change invalidates previously returned device pointers.
The implementation does not special-case self-assignment and still issues the device-to-device copy.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix preservation fails, the destination remains unchanged. If capacity adjustment fails while releasing the old allocation, the destination is reset to an empty state and the old allocation may remain reserved. If the final device-to-device copy fails, the new size and capacity remain observable and active contents are unspecified.

◆ operator=() [3/4]

template<typename T >
DeviceVector< T > & DeviceVector< T >::operator= ( const std::vector< T > &&  other)

Replaces the vector with a copy of a const host rvalue.

The destination capacity is changed to other.capacity(), then other.size() active elements are copied from host to device.

Parameters
[in]otherBorrowed, read-only host vector. No reference to it is retained after the call.
Returns
A borrowed reference aliasing this destination object. It remains valid for the lifetime of the destination.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix preservation, deallocation, or the final host-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() equals other.size(), capacity() equals other.capacity(), and the active device elements copy other.
Note
This overload does not move from or modify other.
Any capacity change invalidates previously returned device pointers.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix preservation fails, the destination remains unchanged. If capacity adjustment fails while releasing the old allocation, the destination is reset to an empty state and the old allocation may remain reserved. If the final host-to-device copy fails, the new size and capacity remain observable and active contents are unspecified.

◆ operator=() [4/4]

template<typename T >
DeviceVector< T > & DeviceVector< T >::operator= ( const std::vector< T > &  other)

Replaces the vector with a copy of a host vector.

The destination capacity is changed to other.capacity(), then other.size() active elements are copied from host to device.

Parameters
[in]otherBorrowed, read-only host vector. No reference to it is retained after the call.
Returns
A borrowed reference aliasing this destination object. It remains valid for the lifetime of the destination.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix preservation, deallocation, or the final host-to-device copy fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, size() equals other.size(), capacity() equals other.capacity(), and the active device elements copy other.
Note
Slots in [size(), capacity()) have unspecified contents.
Any capacity change invalidates previously returned device pointers.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix preservation fails, the destination remains unchanged. If capacity adjustment fails while releasing the old allocation, the destination is reset to an empty state and the old allocation may remain reserved. If the final host-to-device copy fails, the new size and capacity remain observable and active contents are unspecified.

◆ push_back()

template<typename T >
void DeviceVector< T >::push_back ( const T &  value)

Appends one value to the active device sequence.

When the allocation is full, capacity grows to capacity() + capacity() / 2 + 1 and the existing active prefix is copied to the replacement allocation. A single CUDA thread then writes the new value on the default stream.

Parameters
[in]valueHost value copied into the new device element. No reference to value is retained after kernel launch.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix copying, deallocation, or cudaGetLastError() returns a non-success status immediately after launch.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Precondition
When growth is required, the growth expression and resulting byte count are representable as std::size_t.
Postcondition
After a successful immediate launch check, size() is increased by one and the write has been enqueued.
Note
Growth invalidates previously returned device pointers. Appending within spare capacity preserves the allocation address.
Warning
The call does not synchronize the default stream. Kernel execution errors may be reported by a later CUDA operation rather than this call.
The launch checker does not clear a pre-existing CUDA last-error value before launch. A stale error can therefore make this call throw after the kernel has been enqueued.
If the immediate launch-status check fails, size() is not increased. Any completed growth remains in effect, and storage outside the active prefix may have been modified by an enqueued kernel.

◆ resize()

template<typename T >
void DeviceVector< T >::resize ( const std::size_t  count)

Changes the number of active element slots.

Growing beyond capacity reallocates exactly count slots and preserves the old active prefix. Resizing within capacity changes only the logical size. Newly exposed elements are not initialized, and shrinking does not release storage.

Parameters
[in]countRequested active element count.
Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if required allocation, device-to-device prefix copying, or deallocation fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Precondition
count * sizeof(T) is representable as std::size_t when allocation or reallocation is required.
Postcondition
On success, size() equals count. Capacity is unchanged when it was already sufficient; otherwise it equals count.
Note
Reallocation invalidates previously returned device pointers. resize(0) preserves an existing nonzero-capacity allocation.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix copying fails, the original vector remains unchanged. If releasing the original allocation fails, the vector is reset to an empty state and the allocation may remain reserved.

◆ shrink_to_fit()

template<typename T >
void DeviceVector< T >::shrink_to_fit ( void  )

Reduces device capacity to the current size.

The active prefix is preserved. The call is a no-op when size() already equals capacity(); otherwise it replaces or releases the allocation.

Exceptions
ApoCharmmErrorWith ApoCharmmErrorCode::Cuda if allocation, device-to-device prefix copying, or deallocation fails.
std::bad_allocIf reporting a CUDA failure cannot allocate diagnostic storage.
std::length_errorIf a CUDA failure diagnostic exceeds an implementation-defined string limit.
Postcondition
On success, capacity() equals size(). If the size is zero, data() is nullptr.
Note
A capacity change invalidates previously returned device pointers.
CUDA copies use cudaMemcpy without an explicit stream and perform no separate device synchronization.
Warning
If provisional allocation or prefix copying fails, the original vector remains unchanged. If releasing the original allocation fails, the vector is reset to an empty state and the allocation may remain reserved.

◆ size()

template<typename T >
std::size_t DeviceVector< T >::size ( void  ) const

Returns the number of active element slots.

Returns
The length of the active prefix in elements.

◆ swap()

template<typename T >
void DeviceVector< T >::swap ( DeviceVector< T > &  other)
noexcept

Exchanges allocation ownership and metadata with another vector.

Parameters
[in,out]otherVector whose size, capacity, and device pointer are exchanged with this object. No element data is copied.
Postcondition
Each vector owns the allocation and metadata previously owned by the other. Device pointer values remain unchanged, but their owning objects are exchanged.
Note
The operation performs no CUDA call, supports self-swap, and does not synchronize any stream.