Skip to content

Commit ff85f31

Browse files
Copilotjpfeuffer
andcommitted
Simplify array wrappers to use libcpp.vector directly without C++ layer
- Removed C++ wrapper classes (ArrayWrapper.hpp, ArrayWrapper.pxd) - ArrayWrapper classes now directly hold libcpp_vector - ArrayView classes now directly hold raw pointer + size + owner - Added factory functions for creating views from C level - For value returns: use owning wrapper with swap (no extra copy) - For reference returns: use views for zero-copy access - Fixed buffer protocol format string storage - Updated .pxd with proper attribute declarations Co-authored-by: jpfeuffer <8102638+jpfeuffer@users.noreply.github.com>
1 parent 29559b3 commit ff85f31

File tree

7 files changed

+727
-506
lines changed

7 files changed

+727
-506
lines changed

autowrap/CodeGenerator.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2097,9 +2097,15 @@ def create_default_cimports(self):
20972097
|cimport numpy as numpy
20982098
|import numpy as numpy
20992099
|from ArrayWrappers cimport (
2100+
| ArrayWrapperFloat, ArrayWrapperDouble,
2101+
| ArrayWrapperInt8, ArrayWrapperInt16, ArrayWrapperInt32, ArrayWrapperInt64,
2102+
| ArrayWrapperUInt8, ArrayWrapperUInt16, ArrayWrapperUInt32, ArrayWrapperUInt64,
21002103
| ArrayViewFloat, ArrayViewDouble,
21012104
| ArrayViewInt8, ArrayViewInt16, ArrayViewInt32, ArrayViewInt64,
2102-
| ArrayViewUInt8, ArrayViewUInt16, ArrayViewUInt32, ArrayViewUInt64
2105+
| ArrayViewUInt8, ArrayViewUInt16, ArrayViewUInt32, ArrayViewUInt64,
2106+
| _create_view_float, _create_view_double,
2107+
| _create_view_int8, _create_view_int16, _create_view_int32, _create_view_int64,
2108+
| _create_view_uint8, _create_view_uint16, _create_view_uint32, _create_view_uint64
21032109
|)
21042110
"""
21052111
)

autowrap/ConversionProvider.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,11 @@ def _get_wrapper_class_name(self, cpp_type: CppType) -> str:
21922192
}
21932193
return type_map.get(cpp_type.base_type, "Double")
21942194

2195+
def _get_factory_function_name(self, cpp_type: CppType) -> str:
2196+
"""Get the factory function name for creating an ArrayView."""
2197+
suffix = self._get_wrapper_class_name(cpp_type)
2198+
return f"_create_view_{suffix.lower()}"
2199+
21952200
def output_conversion(
21962201
self, cpp_type: CppType, input_cpp_var: str, output_py_var: str
21972202
) -> Optional[Code]:
@@ -2200,7 +2205,7 @@ def output_conversion(
22002205
Uses ArrayWrapper/ArrayView classes with buffer protocol:
22012206
- For non-const references: Create zero-copy view (ArrayView with readonly=False)
22022207
- For const references: Create zero-copy view (ArrayView with readonly=True)
2203-
- For value returns: Copy data using memcpy (Python owns memory)
2208+
- For value returns: Use owning wrapper (data is already a copy)
22042209
"""
22052210
(tt,) = cpp_type.template_args
22062211

@@ -2239,17 +2244,20 @@ def output_conversion(
22392244
dtype = self._get_numpy_dtype(tt)
22402245
ctype = self.CTYPE_MAP.get(dtype, "double")
22412246
wrapper_suffix = self._get_wrapper_class_name(tt)
2247+
factory_func = self._get_factory_function_name(tt)
22422248

22432249
# Check if this is a reference return (view opportunity)
22442250
if cpp_type.is_ref:
2245-
# Use ArrayView for zero-copy access
2251+
# Use ArrayView for zero-copy access via factory function
22462252
readonly = "True" if cpp_type.is_const else "False"
22472253
code = Code().add(
22482254
"""
22492255
|# Convert C++ vector reference to numpy array VIEW (zero-copy)
2250-
|cdef ArrayView$wrapper_suffix _view_$output_py_var = ArrayView$wrapper_suffix(
2251-
| $input_cpp_var.data(),
2252-
| $input_cpp_var.size(),
2256+
|cdef $ctype* _ptr_$output_py_var = $input_cpp_var.data()
2257+
|cdef size_t _size_$output_py_var = $input_cpp_var.size()
2258+
|cdef ArrayView$wrapper_suffix _view_$output_py_var = $factory_func(
2259+
| _ptr_$output_py_var,
2260+
| _size_$output_py_var,
22532261
| owner=self,
22542262
| readonly=$readonly
22552263
|)
@@ -2260,26 +2268,27 @@ def output_conversion(
22602268
input_cpp_var=input_cpp_var,
22612269
output_py_var=output_py_var,
22622270
wrapper_suffix=wrapper_suffix,
2271+
factory_func=factory_func,
22632272
readonly=readonly,
2273+
ctype=ctype,
22642274
),
22652275
)
22662276
return code
22672277
else:
2268-
# Value return - copy data to Python (simpler and safer)
2278+
# Value return - use owning wrapper (data is already a copy)
2279+
# Swap the returned vector into the wrapper to transfer ownership
22692280
code = Code().add(
22702281
"""
2271-
|# Convert C++ vector to numpy array COPY (Python owns data)
2272-
|cdef size_t n_$output_py_var = $input_cpp_var.size()
2273-
|cdef object $output_py_var = numpy.empty(n_$output_py_var, dtype=numpy.$dtype)
2274-
|if n_$output_py_var > 0:
2275-
| memcpy(<void*>numpy.PyArray_DATA($output_py_var), $input_cpp_var.data(), n_$output_py_var * sizeof($ctype))
2282+
|# Convert C++ vector to numpy array using owning wrapper (data already copied)
2283+
|cdef ArrayWrapper$wrapper_suffix _wrapper_$output_py_var = ArrayWrapper$wrapper_suffix()
2284+
|_wrapper_$output_py_var.set_data($input_cpp_var)
2285+
|cdef object $output_py_var = numpy.asarray(_wrapper_$output_py_var)
2286+
|$output_py_var.base = _wrapper_$output_py_var
22762287
""",
22772288
dict(
22782289
input_cpp_var=input_cpp_var,
22792290
output_py_var=output_py_var,
2280-
inner_type=inner_type,
2281-
dtype=dtype,
2282-
ctype=ctype,
2291+
wrapper_suffix=wrapper_suffix,
22832292
),
22842293
)
22852294
return code

autowrap/data_files/autowrap/ArrayWrapper.hpp

Lines changed: 0 additions & 84 deletions
This file was deleted.

autowrap/data_files/autowrap/ArrayWrapper.pxd

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,113 @@
11
# cython: language_level=3
22
"""
33
Cython declaration file for ArrayWrappers module.
4-
This allows other Cython modules to import the wrapper classes.
4+
This allows other Cython modules to import the wrapper classes and factory functions.
55
"""
66

77
from libcpp.vector cimport vector as libcpp_vector
88
from libcpp cimport bool as cbool
99
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t
1010

11-
# Owning wrapper classes
11+
# Owning wrapper classes (hold libcpp_vector directly)
1212
cdef class ArrayWrapperFloat:
13-
pass
13+
cdef libcpp_vector[float] vec
1414

1515
cdef class ArrayWrapperDouble:
16-
pass
16+
cdef libcpp_vector[double] vec
1717

1818
cdef class ArrayWrapperInt8:
19-
pass
19+
cdef libcpp_vector[int8_t] vec
2020

2121
cdef class ArrayWrapperInt16:
22-
pass
22+
cdef libcpp_vector[int16_t] vec
2323

2424
cdef class ArrayWrapperInt32:
25-
pass
25+
cdef libcpp_vector[int32_t] vec
2626

2727
cdef class ArrayWrapperInt64:
28-
pass
28+
cdef libcpp_vector[int64_t] vec
2929

3030
cdef class ArrayWrapperUInt8:
31-
pass
31+
cdef libcpp_vector[uint8_t] vec
3232

3333
cdef class ArrayWrapperUInt16:
34-
pass
34+
cdef libcpp_vector[uint16_t] vec
3535

3636
cdef class ArrayWrapperUInt32:
37-
pass
37+
cdef libcpp_vector[uint32_t] vec
3838

3939
cdef class ArrayWrapperUInt64:
40-
pass
40+
cdef libcpp_vector[uint64_t] vec
4141

42-
# Non-owning view classes
42+
# Non-owning view classes (hold raw pointer + size + owner)
4343
cdef class ArrayViewFloat:
44-
pass
44+
cdef float* ptr
45+
cdef size_t _size
46+
cdef object owner
47+
cdef cbool readonly
4548

4649
cdef class ArrayViewDouble:
47-
pass
50+
cdef double* ptr
51+
cdef size_t _size
52+
cdef object owner
53+
cdef cbool readonly
4854

4955
cdef class ArrayViewInt8:
50-
pass
56+
cdef int8_t* ptr
57+
cdef size_t _size
58+
cdef object owner
59+
cdef cbool readonly
5160

5261
cdef class ArrayViewInt16:
53-
pass
62+
cdef int16_t* ptr
63+
cdef size_t _size
64+
cdef object owner
65+
cdef cbool readonly
5466

5567
cdef class ArrayViewInt32:
56-
pass
68+
cdef int32_t* ptr
69+
cdef size_t _size
70+
cdef object owner
71+
cdef cbool readonly
5772

5873
cdef class ArrayViewInt64:
59-
pass
74+
cdef int64_t* ptr
75+
cdef size_t _size
76+
cdef object owner
77+
cdef cbool readonly
6078

6179
cdef class ArrayViewUInt8:
62-
pass
80+
cdef uint8_t* ptr
81+
cdef size_t _size
82+
cdef object owner
83+
cdef cbool readonly
6384

6485
cdef class ArrayViewUInt16:
65-
pass
86+
cdef uint16_t* ptr
87+
cdef size_t _size
88+
cdef object owner
89+
cdef cbool readonly
6690

6791
cdef class ArrayViewUInt32:
68-
pass
92+
cdef uint32_t* ptr
93+
cdef size_t _size
94+
cdef object owner
95+
cdef cbool readonly
6996

7097
cdef class ArrayViewUInt64:
71-
pass
98+
cdef uint64_t* ptr
99+
cdef size_t _size
100+
cdef object owner
101+
cdef cbool readonly
102+
103+
# Factory functions for creating views from C level
104+
cdef ArrayViewFloat _create_view_float(float* ptr, size_t size, object owner, cbool readonly)
105+
cdef ArrayViewDouble _create_view_double(double* ptr, size_t size, object owner, cbool readonly)
106+
cdef ArrayViewInt8 _create_view_int8(int8_t* ptr, size_t size, object owner, cbool readonly)
107+
cdef ArrayViewInt16 _create_view_int16(int16_t* ptr, size_t size, object owner, cbool readonly)
108+
cdef ArrayViewInt32 _create_view_int32(int32_t* ptr, size_t size, object owner, cbool readonly)
109+
cdef ArrayViewInt64 _create_view_int64(int64_t* ptr, size_t size, object owner, cbool readonly)
110+
cdef ArrayViewUInt8 _create_view_uint8(uint8_t* ptr, size_t size, object owner, cbool readonly)
111+
cdef ArrayViewUInt16 _create_view_uint16(uint16_t* ptr, size_t size, object owner, cbool readonly)
112+
cdef ArrayViewUInt32 _create_view_uint32(uint32_t* ptr, size_t size, object owner, cbool readonly)
113+
cdef ArrayViewUInt64 _create_view_uint64(uint64_t* ptr, size_t size, object owner, cbool readonly)

0 commit comments

Comments
 (0)