Skip to content

Commit a4b0cd5

Browse files
committed
Implement dict copy primitive
1 parent dc4f0af commit a4b0cd5

File tree

6 files changed

+39
-0
lines changed

6 files changed

+39
-0
lines changed

mypyc/lib-rt/CPy.h

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ PyObject *CPyDict_Keys(PyObject *dict);
349349
PyObject *CPyDict_Values(PyObject *dict);
350350
PyObject *CPyDict_Items(PyObject *dict);
351351
char CPyDict_Clear(PyObject *dict);
352+
PyObject *CPyDict_Copy(PyObject *dict);
352353
PyObject *CPyDict_GetKeysIter(PyObject *dict);
353354
PyObject *CPyDict_GetItemsIter(PyObject *dict);
354355
PyObject *CPyDict_GetValuesIter(PyObject *dict);

mypyc/lib-rt/dict_ops.c

+7
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,13 @@ char CPyDict_Clear(PyObject *dict) {
238238
return 1;
239239
}
240240

241+
PyObject *CPyDict_Copy(PyObject *dict) {
242+
if (PyDict_CheckExact(dict)) {
243+
return PyDict_Copy(dict);
244+
}
245+
return PyObject_CallMethod(dict, "copy", NULL);
246+
}
247+
241248
PyObject *CPyDict_GetKeysIter(PyObject *dict) {
242249
if (PyDict_CheckExact(dict)) {
243250
// Return dict itself to indicate we can use fast path instead.

mypyc/primitives/dict_ops.py

+8
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@
150150
c_function_name='CPyDict_Clear',
151151
error_kind=ERR_FALSE)
152152

153+
# dict.copy()
154+
method_op(
155+
name='copy',
156+
arg_types=[dict_rprimitive],
157+
return_type=dict_rprimitive,
158+
c_function_name='CPyDict_Copy',
159+
error_kind=ERR_MAGIC)
160+
153161
# list(dict.keys())
154162
dict_keys_op = custom_op(
155163
arg_types=[dict_rprimitive],

mypyc/test-data/fixtures/ir.py

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ def keys(self) -> Iterable[K]: pass
173173
def values(self) -> Iterable[V]: pass
174174
def items(self) -> Iterable[Tuple[K, V]]: pass
175175
def clear(self) -> None: pass
176+
def copy(self) -> Dict[K, V]: pass
176177

177178
class set(Generic[T]):
178179
def __init__(self, i: Optional[Iterable[T]] = None) -> None: pass

mypyc/test-data/irbuild-dict.test

+11
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,14 @@ def f(d):
324324
L0:
325325
r0 = CPyDict_Clear(d)
326326
return 1
327+
328+
[case testDictCopy]
329+
from typing import Dict
330+
def f(d: Dict[int, int]) -> Dict[int, int]:
331+
return d.copy()
332+
[out]
333+
def f(d):
334+
d, r0 :: dict
335+
L0:
336+
r0 = CPyDict_Copy(d)
337+
return r0

mypyc/test-data/run-dicts.test

+11
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,14 @@ def test_dict_clear() -> None:
206206
dd['a'] = 1
207207
dd.clear()
208208
assert dd == {}
209+
210+
def test_dict_copy() -> None:
211+
d: Dict[str, int] = {}
212+
assert d.copy() == d
213+
d = {'a': 1, 'b': 2}
214+
assert d.copy() == d
215+
assert d.copy() is not d
216+
dd: Dict[str, int] = defaultdict(int)
217+
dd['a'] = 1
218+
assert dd.copy() == dd
219+
assert isinstance(dd.copy(), defaultdict)

0 commit comments

Comments
 (0)