Coverage for cuda / bindings / _internal / utils.pyx: 67%
78 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-10 01:19 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-10 01:19 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
5cimport cpython
6from libc.stdint cimport intptr_t
7from libcpp.utility cimport move
8from cython.operator cimport dereference as deref
11cdef bint is_nested_sequence(data):
12 if not cpython.PySequence_Check(data):
13 return False
14 else:
15 for i in data:
16 if not cpython.PySequence_Check(i):
17 return False
18 else:
19 return True
22cdef void* get_buffer_pointer(buf, Py_ssize_t size, readonly=True) except*:
23 """The caller must ensure ``buf`` is alive when the returned pointer is in use."""
24 cdef void* bufPtr
25 cdef int flags = cpython.PyBUF_ANY_CONTIGUOUS
26 if not readonly:
27 flags |= cpython.PyBUF_WRITABLE
28 cdef int status = -1
29 cdef cpython.Py_buffer view
31 if isinstance(buf, int):
32 bufPtr = <void*><intptr_t>buf
33 else: # try buffer protocol
34 try:
35 status = cpython.PyObject_GetBuffer(buf, &view, flags)
36 # when the caller does not provide a size, it is set to -1 at generate-time by cybind
37 if size != -1:
38 assert view.len == size
39 assert view.ndim == 1
40 except Exception as e:
41 adj = "writable " if not readonly else ""
42 raise ValueError(
43 "buf must be either a Python int representing the pointer "
44 f"address to a valid buffer, or a 1D contiguous {adj}"
45 "buffer, of size bytes") from e
46 else:
47 bufPtr = view.buf
48 finally:
49 if status == 0:
50 cpython.PyBuffer_Release(&view)
52 return bufPtr
55# Cython can't infer the ResT overload when it is wrapped in nullable_unique_ptr,
56# so we need a dummy (__unused) input argument to help it
57cdef int get_resource_ptr(nullable_unique_ptr[vector[ResT]] &in_out_ptr, object obj, ResT* __unused) except 1:
58 if cpython.PySequence_Check(obj):
59 vec = new vector[ResT](len(obj))
60 # set the ownership immediately to avoid leaking the `vec` memory in
61 # case of exception in the following loop
62 in_out_ptr.reset(vec, True)
63 for i in range(len(obj)):
64 deref(vec)[i] = obj[i]
65 else:
66 in_out_ptr.reset(<vector[ResT]*><intptr_t>obj, False)
67 return 0
70cdef int get_resource_ptrs(nullable_unique_ptr[ vector[PtrT*] ] &in_out_ptr, object obj, PtrT* __unused) except 1:
71 if cpython.PySequence_Check(obj):
72 vec = new vector[PtrT*](len(obj))
73 # set the ownership immediately to avoid leaking the `vec` memory in
74 # case of exception in the following loop
75 in_out_ptr.reset(vec, True)
76 for i in range(len(obj)):
77 deref(vec)[i] = <PtrT*><intptr_t>(obj[i])
78 else:
79 in_out_ptr.reset(<vector[PtrT*]*><intptr_t>obj, False)
80 return 0
83cdef int get_nested_resource_ptr(nested_resource[ResT] &in_out_ptr, object obj, ResT* __unused) except 1:
84 cdef nullable_unique_ptr[ vector[intptr_t] ] nested_ptr
85 cdef nullable_unique_ptr[ vector[vector[ResT]] ] nested_res_ptr
86 cdef vector[intptr_t]* nested_vec = NULL
87 cdef vector[vector[ResT]]* nested_res_vec = NULL
88 cdef size_t i = 0, length = 0
89 cdef intptr_t addr
91 if is_nested_sequence(obj):
92 length = len(obj)
93 nested_res_vec = new vector[vector[ResT]](length)
94 nested_vec = new vector[intptr_t](length)
95 # set the ownership immediately to avoid leaking memory in case of
96 # exception in the following loop
97 nested_res_ptr.reset(nested_res_vec, True)
98 nested_ptr.reset(nested_vec, True)
99 for i, obj_i in enumerate(obj):
100 if ResT is char:
101 obj_i_bytes = (<str?>(obj_i)).encode()
102 str_len = <size_t>(len(obj_i_bytes)) + 1 # including null termination
103 deref(nested_res_vec)[i].resize(str_len)
104 obj_i_ptr = <char*>(obj_i_bytes)
105 # cast to size_t explicitly to work around a potentially Cython bug
106 deref(nested_res_vec)[i].assign(obj_i_ptr, obj_i_ptr + <size_t>str_len)
107 else:
108 deref(nested_res_vec)[i] = obj_i
109 deref(nested_vec)[i] = <intptr_t>(deref(nested_res_vec)[i].data())
110 elif cpython.PySequence_Check(obj):
111 length = len(obj)
112 nested_vec = new vector[intptr_t](length)
113 nested_ptr.reset(nested_vec, True)
114 for i, addr in enumerate(obj):
115 deref(nested_vec)[i] = addr
116 nested_res_ptr.reset(NULL, False)
117 else:
118 # obj is an int (ResT**)
119 nested_res_ptr.reset(NULL, False)
120 nested_ptr.reset(<vector[intptr_t]*><intptr_t>obj, False)
122 in_out_ptr.ptrs = move(nested_ptr)
123 in_out_ptr.nested_resource_ptr = move(nested_res_ptr)
124 return 0
127class FunctionNotFoundError(RuntimeError): pass
129class NotSupportedError(RuntimeError): pass