Context
Current ownership for 1D/2D allocations is handled via UniqueArray<T, Loc> (a std::unique_ptr<T[]> with CUDA deleters) plus helper factories (make_unique_array, make_unique_array2d). This mixes two concerns:
- Owning untyped storage returned by
cudaMalloc* (bytes, no constructors/destructors).
- Presenting that storage as an "array of
T".
For device/pinned allocations, constructors/destructors are never run, so UniqueArray<T, Loc> is only sound for "POD-like" T (std::is_standard_layout is insufficient for this: types can be standard-layout but still non-trivial). We need clearer semantics and constraints.
Goals
- Make the ownership layer explicitly byte-based (no implicit "array of
T" promise for device/pinned).
- Keep
BufferView<T, Loc> as the universal typed non-owning view.
- Kepp
Buffer<T, Loc> as the boring RAII owner for Host/Pinned/Device, implemented on top of a small BufferStorage<Loc> (raw bytes).
- Move pitched/2D allocation ownership into a dedicated
ImageStorage module, used by Image.
Proposed Changes
- Introduce
BufferStorage<Loc> (raw byte owner):
- stores
void* ptr + std::size_t nbytes
- RAII free via:
- Host:
operator new/delete (aligned as needed)
- Host-pinned:
cudaMallocHost/cudaFreeHost
- Device:
cudaMalloc/cudaFree
- Destructors must be
noexcept; CUDA free errors handled by CUDA_CHECK_TERMINATE
- Refactor
Buffer<T, Loc>:
- implemented as
{BufferStorage<Loc> storage; std::size_t count;}
data() returns static_cast<T*>(storage.data())
- add element constraint (e.g.,
BufferElement<T> = trivially copyable + trivially default destructible)
- Remove
UniqueArray and associated factories
- Introduce
ImageStorage<T, Loc> in a separate header (e.g. image_storage.hpp):
- owns allocation for 2D pitched storage + metadata (
pitch_bytes, height, width)
- Device uses
cudaMallocPitch; host/pinned uses contiguous or aligned-pitch allocation (TBD)
Image becomes a thin wrapper over ImageStorage + view/accessors.
Acceptance Criteria
Buffer<T, Loc> retains the same public surface (data/size/view/cview, move-only).
- Buffers cannot be instantiated with non-POD-like element types (enforced at compile time).
Image no longer depends on make_unique_array2d; pitched ownership is centralised in ImageStorage.
- Tests/examples updated accordingly and pass/work.
Context
Current ownership for 1D/2D allocations is handled via
UniqueArray<T, Loc>(astd::unique_ptr<T[]>with CUDA deleters) plus helper factories (make_unique_array,make_unique_array2d). This mixes two concerns:cudaMalloc*(bytes, no constructors/destructors).T".For device/pinned allocations, constructors/destructors are never run, so
UniqueArray<T, Loc>is only sound for "POD-like"T(std::is_standard_layoutis insufficient for this: types can be standard-layout but still non-trivial). We need clearer semantics and constraints.Goals
T" promise for device/pinned).BufferView<T, Loc>as the universal typed non-owning view.Buffer<T, Loc>as the boring RAII owner for Host/Pinned/Device, implemented on top of a smallBufferStorage<Loc>(raw bytes).ImageStoragemodule, used byImage.Proposed Changes
BufferStorage<Loc>(raw byte owner):void* ptr+std::size_t nbytesoperator new/delete(aligned as needed)cudaMallocHost/cudaFreeHostcudaMalloc/cudaFreenoexcept; CUDA free errors handled byCUDA_CHECK_TERMINATEBuffer<T, Loc>:{BufferStorage<Loc> storage; std::size_t count;}data()returnsstatic_cast<T*>(storage.data())BufferElement<T>= trivially copyable + trivially default destructible)UniqueArrayand associated factoriesImageStorage<T, Loc>in a separate header (e.g.image_storage.hpp):pitch_bytes,height,width)cudaMallocPitch; host/pinned uses contiguous or aligned-pitch allocation (TBD)Imagebecomes a thin wrapper overImageStorage+ view/accessors.Acceptance Criteria
Buffer<T, Loc>retains the same public surface (data/size/view/cview, move-only).Imageno longer depends onmake_unique_array2d; pitched ownership is centralised inImageStorage.