Skip to content

Commit 1a2874e

Browse files
Add tests for std::deque and std::list mutable reference cleanup code (#207)
* Initial plan * Add tests for std::deque and std::list mutable reference cleanup code Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> * Run code review and codeql checks Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> * Remove CodeQL artifact and update gitignore Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> Co-authored-by: Timo Sachsenberg <timo.sachsenberg@uni-tuebingen.de>
1 parent bb5fe19 commit 1a2874e

File tree

6 files changed

+280
-1
lines changed

6 files changed

+280
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,4 @@ tests/test_files/enums.pyx
176176
# generated typestubs
177177
tests/test_files/*.pyi
178178

179+
_codeql_detected_source_root

tests/test_code_generator_new_stl.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ def test_new_stl_code_generation():
5252
"getDeque method should be generated"
5353
assert "def sumDeque(" in pyx_content, \
5454
"sumDeque method should be generated"
55+
assert "def doubleDequeElements(" in pyx_content, \
56+
"doubleDequeElements method should be generated"
5557
assert "def getList(" in pyx_content, \
5658
"getList method should be generated"
5759
assert "def sumList(" in pyx_content, \
5860
"sumList method should be generated"
61+
assert "def doubleListElements(" in pyx_content, \
62+
"doubleListElements method should be generated"
5963
assert "def getOptionalValue(" in pyx_content, \
6064
"getOptionalValue method should be generated"
6165
assert "def unwrapOptional(" in pyx_content, \
@@ -104,6 +108,11 @@ def test_new_stl_code_generation():
104108
sum_deque_result = obj.sumDeque([5, 10, 15])
105109
assert sum_deque_result == 30, f"sumDeque returned {sum_deque_result}"
106110

111+
# Test deque mutable reference (cleanup code)
112+
deque_data = [1, 2, 3, 4]
113+
obj.doubleDequeElements(deque_data)
114+
assert deque_data == [2, 4, 6, 8], f"doubleDequeElements should modify list in place: {deque_data}"
115+
107116
# Test list (std::list)
108117
result_list = obj.getList()
109118
assert isinstance(result_list, list), "std::list should return list"
@@ -114,6 +123,13 @@ def test_new_stl_code_generation():
114123
sum_list_result = obj.sumList([1.0, 2.0, 3.0])
115124
assert abs(sum_list_result - 6.0) < 0.0001, f"sumList returned {sum_list_result}"
116125

126+
# Test list mutable reference (cleanup code)
127+
list_data = [1.0, 2.0, 3.0]
128+
obj.doubleListElements(list_data)
129+
expected_doubled = [2.0, 4.0, 6.0]
130+
for i, (r, e) in enumerate(zip(list_data, expected_doubled)):
131+
assert abs(r - e) < 0.0001, f"doubleListElements should modify list in place: {list_data}"
132+
117133
# Test optional
118134
opt_with_value = obj.getOptionalValue(True)
119135
assert opt_with_value == 42, f"Optional with value should return 42, got {opt_with_value}"

tests/test_files/inherited.pyx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#Generated with autowrap 0.23.0 and Cython (Parser) 3.2.0
1+
#Generated with autowrap 0.23.0 and Cython (Parser) 3.2.1
22
#cython: c_string_encoding=ascii
33
#cython: embedsignature=False
44
from enum import Enum as _PyEnum
@@ -11,6 +11,12 @@ from libcpp.set cimport set as libcpp_set
1111
from libcpp.vector cimport vector as libcpp_vector
1212
from libcpp.pair cimport pair as libcpp_pair
1313
from libcpp.map cimport map as libcpp_map
14+
from libcpp.unordered_map cimport unordered_map as libcpp_unordered_map
15+
from libcpp.unordered_set cimport unordered_set as libcpp_unordered_set
16+
from libcpp.deque cimport deque as libcpp_deque
17+
from libcpp.list cimport list as libcpp_list
18+
from libcpp.optional cimport optional as libcpp_optional
19+
from libcpp.string_view cimport string_view as libcpp_string_view
1420
from libcpp cimport bool
1521
from libc.string cimport const_char
1622
from cython.operator cimport dereference as deref, preincrement as inc, address as address

tests/test_files/new_stl_test.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ class NewSTLTest {
6868
return sum;
6969
}
7070

71+
// Mutable reference test - doubles each element
72+
void doubleDequeElements(std::deque<int>& d) {
73+
for (size_t i = 0; i < d.size(); i++) {
74+
d[i] *= 2;
75+
}
76+
}
77+
7178
// =========================================================================
7279
// std::list tests
7380
// =========================================================================
@@ -84,6 +91,13 @@ class NewSTLTest {
8491
return sum;
8592
}
8693

94+
// Mutable reference test - doubles each element
95+
void doubleListElements(std::list<double>& l) {
96+
for (auto& v : l) {
97+
v *= 2;
98+
}
99+
}
100+
87101
// =========================================================================
88102
// std::optional tests
89103
// =========================================================================

tests/test_files/new_stl_test.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ cdef extern from "new_stl_test.hpp":
4242
# deque tests
4343
libcpp_deque[int] getDeque()
4444
int sumDeque(libcpp_deque[int]& d)
45+
void doubleDequeElements(libcpp_deque[int]& d)
4546

4647
# list tests
4748
libcpp_list[double] getList()
4849
double sumList(libcpp_list[double]& l)
50+
void doubleListElements(libcpp_list[double]& l)
4951

5052
# optional tests
5153
libcpp_optional[int] getOptionalValue(bool hasValue)

tests/test_files/new_stl_test.pyx

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#Generated with autowrap 0.23.0 and Cython (Parser) 3.2.1
2+
#cython: c_string_encoding=ascii
3+
#cython: embedsignature=False
4+
from enum import Enum as _PyEnum
5+
from cpython cimport Py_buffer
6+
from cpython cimport bool as pybool_t
7+
from libcpp.string cimport string as libcpp_string
8+
from libcpp.string cimport string as libcpp_utf8_string
9+
from libcpp.string cimport string as libcpp_utf8_output_string
10+
from libcpp.set cimport set as libcpp_set
11+
from libcpp.vector cimport vector as libcpp_vector
12+
from libcpp.pair cimport pair as libcpp_pair
13+
from libcpp.map cimport map as libcpp_map
14+
from libcpp.unordered_map cimport unordered_map as libcpp_unordered_map
15+
from libcpp.unordered_set cimport unordered_set as libcpp_unordered_set
16+
from libcpp.deque cimport deque as libcpp_deque
17+
from libcpp.list cimport list as libcpp_list
18+
from libcpp.optional cimport optional as libcpp_optional
19+
from libcpp.string_view cimport string_view as libcpp_string_view
20+
from libcpp cimport bool
21+
from libc.string cimport const_char
22+
from cython.operator cimport dereference as deref, preincrement as inc, address as address
23+
from AutowrapRefHolder cimport AutowrapRefHolder
24+
from AutowrapPtrHolder cimport AutowrapPtrHolder
25+
from AutowrapConstPtrHolder cimport AutowrapConstPtrHolder
26+
from smart_ptr cimport shared_ptr
27+
from new_stl_test cimport _NewSTLTest as __NewSTLTest
28+
29+
cdef extern from "autowrap_tools.hpp":
30+
char * _cast_const_away(char *)
31+
32+
cdef class _NewSTLTest:
33+
"""
34+
Cython implementation of __NewSTLTest
35+
"""
36+
37+
cdef shared_ptr[__NewSTLTest] inst
38+
39+
def __dealloc__(self):
40+
self.inst.reset()
41+
42+
43+
def __init__(self):
44+
"""
45+
__init__(self) -> None
46+
"""
47+
self.inst = shared_ptr[__NewSTLTest](new __NewSTLTest())
48+
49+
def getUnorderedMap(self):
50+
"""
51+
getUnorderedMap(self) -> Dict[bytes, int]
52+
"""
53+
_r = self.inst.get().getUnorderedMap()
54+
py_result = dict()
55+
cdef libcpp_unordered_map[libcpp_string, int].iterator it__r = _r.begin()
56+
while it__r != _r.end():
57+
py_result[<libcpp_string>(deref(it__r).first)] = <int>(deref(it__r).second)
58+
inc(it__r)
59+
return py_result
60+
61+
def sumUnorderedMapValues(self, dict m ):
62+
"""
63+
sumUnorderedMapValues(self, m: Dict[bytes, int] ) -> int
64+
"""
65+
assert isinstance(m, dict) and all(isinstance(k, bytes) for k in m.keys()) and all(isinstance(v, int) for v in m.values()), 'arg m wrong type'
66+
cdef libcpp_unordered_map[libcpp_string, int] * v0 = new libcpp_unordered_map[libcpp_string, int]()
67+
for key, value in m.items():
68+
deref(v0)[ <libcpp_string> key ] = <int> value
69+
cdef int _r = self.inst.get().sumUnorderedMapValues(deref(v0))
70+
replace = dict()
71+
cdef libcpp_unordered_map[libcpp_string, int].iterator it_m = v0.begin()
72+
while it_m != v0.end():
73+
replace[<libcpp_string> deref(it_m).first] = <int> deref(it_m).second
74+
inc(it_m)
75+
m.clear()
76+
m.update(replace)
77+
del v0
78+
py_result = <int>_r
79+
return py_result
80+
81+
def getUnorderedSet(self):
82+
"""
83+
getUnorderedSet(self) -> Set[int]
84+
"""
85+
_r = self.inst.get().getUnorderedSet()
86+
py_result = set()
87+
cdef libcpp_unordered_set[int].iterator it__r = _r.begin()
88+
while it__r != _r.end():
89+
py_result.add(<int>deref(it__r))
90+
inc(it__r)
91+
return py_result
92+
93+
def sumUnorderedSet(self, set s ):
94+
"""
95+
sumUnorderedSet(self, s: Set[int] ) -> int
96+
"""
97+
assert isinstance(s, set) and all(isinstance(li, int) for li in s), 'arg s wrong type'
98+
cdef libcpp_unordered_set[int] * v0 = new libcpp_unordered_set[int]()
99+
for item0 in s:
100+
v0.insert(<int> item0)
101+
cdef int _r = self.inst.get().sumUnorderedSet(deref(v0))
102+
replace = set()
103+
cdef libcpp_unordered_set[int].iterator it_s = v0.begin()
104+
while it_s != v0.end():
105+
replace.add(<int> deref(it_s))
106+
inc(it_s)
107+
s.clear()
108+
s.update(replace)
109+
del v0
110+
py_result = <int>_r
111+
return py_result
112+
113+
def getDeque(self):
114+
"""
115+
getDeque(self) -> List[int]
116+
"""
117+
_r = self.inst.get().getDeque()
118+
py_result = [<int>_r.at(i) for i in range(_r.size())]
119+
return py_result
120+
121+
def sumDeque(self, list d ):
122+
"""
123+
sumDeque(self, d: List[int] ) -> int
124+
"""
125+
assert isinstance(d, list) and all(isinstance(li, int) for li in d), 'arg d wrong type'
126+
cdef libcpp_deque[int] v0
127+
for item0 in d:
128+
v0.push_back(<int> item0)
129+
cdef int _r = self.inst.get().sumDeque(v0)
130+
d[:] = [<int>v0.at(i) for i in range(v0.size())]
131+
py_result = <int>_r
132+
return py_result
133+
134+
def doubleDequeElements(self, list d ):
135+
"""
136+
doubleDequeElements(self, d: List[int] ) -> None
137+
"""
138+
assert isinstance(d, list) and all(isinstance(li, int) for li in d), 'arg d wrong type'
139+
cdef libcpp_deque[int] v0
140+
for item0 in d:
141+
v0.push_back(<int> item0)
142+
self.inst.get().doubleDequeElements(v0)
143+
d[:] = [<int>v0.at(i) for i in range(v0.size())]
144+
145+
def getList(self):
146+
"""
147+
getList(self) -> List[float]
148+
"""
149+
_r = self.inst.get().getList()
150+
py_result = []
151+
cdef libcpp_list[double].iterator it__r = _r.begin()
152+
while it__r != _r.end():
153+
py_result.append(deref(it__r))
154+
inc(it__r)
155+
return py_result
156+
157+
def sumList(self, list l ):
158+
"""
159+
sumList(self, l: List[float] ) -> float
160+
"""
161+
assert isinstance(l, list) and all(isinstance(li, float) for li in l), 'arg l wrong type'
162+
cdef libcpp_list[double] v0
163+
for item in l:
164+
v0.push_back(item)
165+
cdef double _r = self.inst.get().sumList(v0)
166+
l[:] = []
167+
cdef libcpp_list[double].iterator it_l = v0.begin()
168+
while it_l != v0.end():
169+
l.append(deref(it_l))
170+
inc(it_l)
171+
py_result = <double>_r
172+
return py_result
173+
174+
def doubleListElements(self, list l ):
175+
"""
176+
doubleListElements(self, l: List[float] ) -> None
177+
"""
178+
assert isinstance(l, list) and all(isinstance(li, float) for li in l), 'arg l wrong type'
179+
cdef libcpp_list[double] v0
180+
for item in l:
181+
v0.push_back(item)
182+
self.inst.get().doubleListElements(v0)
183+
l[:] = []
184+
cdef libcpp_list[double].iterator it_l = v0.begin()
185+
while it_l != v0.end():
186+
l.append(deref(it_l))
187+
inc(it_l)
188+
189+
def getOptionalValue(self, bool hasValue ):
190+
"""
191+
getOptionalValue(self, hasValue: bool ) -> Optional[int]
192+
"""
193+
assert isinstance(hasValue, pybool_t), 'arg hasValue wrong type'
194+
195+
_r = self.inst.get().getOptionalValue((<bool>hasValue))
196+
if _r.has_value():
197+
py_result = _r.value()
198+
else:
199+
py_result = None
200+
return py_result
201+
202+
def unwrapOptional(self, object opt ):
203+
"""
204+
unwrapOptional(self, opt: Optional[int] ) -> int
205+
"""
206+
assert (opt is None or isinstance(opt, int)), 'arg opt wrong type'
207+
cdef libcpp_optional[int] v0
208+
if opt is not None:
209+
v0 = libcpp_optional[int](<int>opt)
210+
cdef int _r = self.inst.get().unwrapOptional(v0)
211+
py_result = <int>_r
212+
return py_result
213+
214+
def getStringViewLength(self, bytes sv ):
215+
"""
216+
getStringViewLength(self, sv: bytes ) -> int
217+
"""
218+
assert isinstance(sv, (bytes, str)), 'arg sv wrong type'
219+
cdef bytes v0
220+
if isinstance(sv, str):
221+
v0 = sv.encode('utf-8')
222+
else:
223+
v0 = sv
224+
cdef size_t _r = self.inst.get().getStringViewLength((<libcpp_string_view>v0))
225+
py_result = <size_t>_r
226+
return py_result
227+
228+
def stringViewToString(self, bytes sv ):
229+
"""
230+
stringViewToString(self, sv: bytes ) -> bytes
231+
"""
232+
assert isinstance(sv, (bytes, str)), 'arg sv wrong type'
233+
cdef bytes v0
234+
if isinstance(sv, str):
235+
v0 = sv.encode('utf-8')
236+
else:
237+
v0 = sv
238+
cdef libcpp_string _r = self.inst.get().stringViewToString((<libcpp_string_view>v0))
239+
py_result = <libcpp_string>_r
240+
return py_result

0 commit comments

Comments
 (0)