Nuitka
The Python compiler
Loading...
Searching...
No Matches
HelpersDeepcopy.c
1// Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
7// This file is included from another C file, help IDEs to still parse it on
8// its own.
9#ifdef __IDE_ONLY__
10#include "nuitka/prelude.h"
11#endif
12
13#if PYTHON_VERSION >= 0x390
14typedef struct {
15 PyObject_HEAD PyObject *origin;
16 PyObject *args;
17 PyObject *parameters;
18} GenericAliasObject;
19#endif
20
21typedef PyObject *(*copy_func)(PyThreadState *tstate, PyObject *);
22
23static PyObject *DEEP_COPY_ITEM(PyThreadState *tstate, PyObject *value, PyTypeObject **type, copy_func *copy_function);
24
25PyObject *DEEP_COPY_LIST(PyThreadState *tstate, PyObject *value) {
26 assert(PyList_CheckExact(value));
27
28 Py_ssize_t n = PyList_GET_SIZE(value);
29 PyObject *result = MAKE_LIST_EMPTY(tstate, n);
30
31 PyTypeObject *type = NULL;
32 copy_func copy_function = NULL;
33
34 for (Py_ssize_t i = 0; i < n; i++) {
35 PyObject *item = PyList_GET_ITEM(value, i);
36 if (i == 0) {
37 PyList_SET_ITEM(result, i, DEEP_COPY_ITEM(tstate, item, &type, &copy_function));
38 } else {
39 PyObject *new_item;
40
41 if (likely(type == Py_TYPE(item))) {
42 if (copy_function) {
43 new_item = copy_function(tstate, item);
44 } else {
45 new_item = item;
46 Py_INCREF(item);
47 }
48 } else {
49 new_item = DEEP_COPY_ITEM(tstate, item, &type, &copy_function);
50 }
51
52 PyList_SET_ITEM(result, i, new_item);
53 }
54 }
55
56 return result;
57}
58
59PyObject *DEEP_COPY_TUPLE(PyThreadState *tstate, PyObject *value) {
60 assert(PyTuple_CheckExact(value));
61
62 Py_ssize_t n = PyTuple_GET_SIZE(value);
63
64 PyObject *result = MAKE_TUPLE_EMPTY_VAR(tstate, n);
65
66 for (Py_ssize_t i = 0; i < n; i++) {
67 PyTuple_SET_ITEM(result, i, DEEP_COPY(tstate, PyTuple_GET_ITEM(value, i)));
68 }
69
70 return result;
71}
72
73static PyObject *_DEEP_COPY_SET(PyObject *value) {
74 // Sets cannot contain non-hashable types, so these all must be immutable,
75 // but the set itself might be changed, so we need to copy it.
76 return PySet_New(value);
77}
78
79PyObject *DEEP_COPY_SET(PyThreadState *tstate, PyObject *value) { return _DEEP_COPY_SET(value); }
80
81#if PYTHON_VERSION >= 0x390
82PyObject *DEEP_COPY_GENERICALIAS(PyThreadState *tstate, PyObject *value) {
83 assert(Py_TYPE(value) == &Py_GenericAliasType);
84
85 GenericAliasObject *generic_alias = (GenericAliasObject *)value;
86
87 PyObject *args = DEEP_COPY(tstate, generic_alias->args);
88 PyObject *origin = DEEP_COPY(tstate, generic_alias->origin);
89
90 if (generic_alias->args == args && generic_alias->origin == origin) {
91 Py_INCREF(value);
92 return value;
93 } else {
94 return Py_GenericAlias(origin, args);
95 }
96}
97#endif
98
99static PyObject *_deep_copy_dispatch = NULL;
100static PyObject *_deep_noop = NULL;
101
102static PyObject *Nuitka_CapsuleNew(void *pointer) {
103#if PYTHON_VERSION < 0x300
104 return PyCObject_FromVoidPtr(pointer, NULL);
105#else
106 return PyCapsule_New(pointer, "", NULL);
107#endif
108}
109
110#if PYTHON_VERSION >= 0x300
111typedef struct {
112 PyObject_HEAD void *pointer;
113 const char *name;
114 void *context;
115 PyCapsule_Destructor destructor;
116} Nuitka_PyCapsule;
117
118#define Nuitka_CapsuleGetPointer(capsule) (((Nuitka_PyCapsule *)(capsule))->pointer)
119
120#else
121#define Nuitka_CapsuleGetPointer(capsule) (PyCObject_AsVoidPtr(capsule))
122#endif
123
124#if PYTHON_VERSION >= 0x3a0
125PyTypeObject *Nuitka_PyUnion_Type;
126#endif
127
128static PyObject *_makeDeepCopyFunctionCapsule(copy_func func) { return Nuitka_CapsuleNew((void *)func); }
129
130static void _initDeepCopy(PyThreadState *tstate) {
131 // Once only
132 assert(_deep_copy_dispatch == NULL);
133
134 _deep_copy_dispatch = PyDict_New();
135 _deep_noop = Py_None;
136
137 CHECK_OBJECT(_deep_noop);
138
139 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyDict_Type, _makeDeepCopyFunctionCapsule(DEEP_COPY_DICT));
140 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyList_Type, _makeDeepCopyFunctionCapsule(DEEP_COPY_LIST));
141 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyTuple_Type, _makeDeepCopyFunctionCapsule(DEEP_COPY_TUPLE));
142 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PySet_Type, _makeDeepCopyFunctionCapsule(DEEP_COPY_SET));
143 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyByteArray_Type, _makeDeepCopyFunctionCapsule(BYTEARRAY_COPY));
144
145#if PYTHON_VERSION >= 0x390
146 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&Py_GenericAliasType,
147 _makeDeepCopyFunctionCapsule(DEEP_COPY_GENERICALIAS));
148#endif
149
150#if PYTHON_VERSION >= 0x3a0
151 {
152 PyObject *args[2] = {(PyObject *)&PyFloat_Type, (PyObject *)&PyTuple_Type};
153 PyObject *args_tuple = MAKE_TUPLE(tstate, args, 2);
154 PyObject *union_value = MAKE_UNION_TYPE(args_tuple);
155
156 Nuitka_PyUnion_Type = Py_TYPE(union_value);
157
158 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)Nuitka_PyUnion_Type, _deep_noop);
159
160 Py_DECREF(union_value);
161 Py_DECREF(args_tuple);
162 }
163
164#endif
165
166#if PYTHON_VERSION < 0x300
167 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyString_Type, _deep_noop);
168 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyInt_Type, _deep_noop);
169#else
170 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyBytes_Type, _deep_noop);
171#endif
172 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyUnicode_Type, _deep_noop);
173 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyLong_Type, _deep_noop);
174 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)Py_TYPE(Py_None), _deep_noop);
175 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyBool_Type, _deep_noop);
176 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyFloat_Type, _deep_noop);
177 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyRange_Type, _deep_noop);
178 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyType_Type, _deep_noop);
179 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PySlice_Type, _deep_noop);
180 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyComplex_Type, _deep_noop);
181 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyCFunction_Type, _deep_noop);
182 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)Py_TYPE(Py_Ellipsis), _deep_noop);
183 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)Py_TYPE(Py_NotImplemented), _deep_noop);
184
185 // Sets can be changed, but not a frozenset.
186 PyDict_SetItem(_deep_copy_dispatch, (PyObject *)&PyFrozenSet_Type, _deep_noop);
187}
188
189static PyObject *DEEP_COPY_ITEM(PyThreadState *tstate, PyObject *value, PyTypeObject **type, copy_func *copy_function) {
190 *type = Py_TYPE(value);
191
192 PyObject *dispatcher = DICT_GET_ITEM0(tstate, _deep_copy_dispatch, (PyObject *)*type);
193
194 if (unlikely(dispatcher == NULL)) {
195 NUITKA_CANNOT_GET_HERE("DEEP_COPY encountered unknown type");
196 }
197
198 if (dispatcher == Py_None) {
199 *copy_function = NULL;
200
201 Py_INCREF(value);
202 return value;
203 } else {
204 *copy_function = (copy_func)(Nuitka_CapsuleGetPointer(dispatcher));
205 return (*copy_function)(tstate, value);
206 }
207}
208
209PyObject *DEEP_COPY(PyThreadState *tstate, PyObject *value) {
210 PyObject *dispatcher = DICT_GET_ITEM0(tstate, _deep_copy_dispatch, (PyObject *)Py_TYPE(value));
211
212 if (unlikely(dispatcher == NULL)) {
213 NUITKA_CANNOT_GET_HERE("DEEP_COPY encountered unknown type");
214 }
215
216 if (dispatcher == Py_None) {
217 Py_INCREF(value);
218 return value;
219 } else {
220 copy_func copy_function = (copy_func)(Nuitka_CapsuleGetPointer(dispatcher));
221 return copy_function(tstate, value);
222 }
223}
224
225#ifndef __NUITKA_NO_ASSERT__
226
227static Py_hash_t DEEP_HASH_INIT(PyThreadState *tstate, PyObject *value) {
228 // To avoid warnings about reduced sizes, we put an intermediate value
229 // that is size_t.
230 size_t value2 = (size_t)value;
231 Py_hash_t result = (Py_hash_t)(value2);
232
233 if (Py_TYPE(value) != &PyType_Type) {
234 result ^= DEEP_HASH(tstate, (PyObject *)Py_TYPE(value));
235 }
236
237 return result;
238}
239
240static void DEEP_HASH_BLOB(Py_hash_t *hash, char const *s, Py_ssize_t size) {
241 while (size > 0) {
242 *hash = (1000003 * (*hash)) ^ (Py_hash_t)(*s++);
243 size--;
244 }
245}
246
247static void DEEP_HASH_CSTR(Py_hash_t *hash, char const *s) { DEEP_HASH_BLOB(hash, s, strlen(s)); }
248
249// Hash function that actually verifies things done to the bit level. Can be
250// used to detect corruption.
251Py_hash_t DEEP_HASH(PyThreadState *tstate, PyObject *value) {
252 assert(value != NULL);
253
254 if (PyType_Check(value)) {
255 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
256
257 DEEP_HASH_CSTR(&result, ((PyTypeObject *)value)->tp_name);
258 return result;
259 } else if (PyDict_Check(value)) {
260 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
261
262 Py_ssize_t pos = 0;
263 PyObject *key, *dict_value;
264
265 while (Nuitka_DictNext(value, &pos, &key, &dict_value)) {
266 if (key != NULL && dict_value != NULL) {
267 result ^= DEEP_HASH(tstate, key);
268 result ^= DEEP_HASH(tstate, dict_value);
269 }
270 }
271
272 return result;
273 } else if (PyTuple_Check(value)) {
274 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
275
276 Py_ssize_t n = PyTuple_GET_SIZE(value);
277
278 for (Py_ssize_t i = 0; i < n; i++) {
279 result ^= DEEP_HASH(tstate, PyTuple_GET_ITEM(value, i));
280 }
281
282 return result;
283 } else if (PyList_CheckExact(value)) {
284 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
285
286 Py_ssize_t n = PyList_GET_SIZE(value);
287
288 for (Py_ssize_t i = 0; i < n; i++) {
289 result ^= DEEP_HASH(tstate, PyList_GET_ITEM(value, i));
290 }
291
292 return result;
293 } else if (PySet_Check(value) || PyFrozenSet_Check(value)) {
294 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
295
296 PyObject *iterator = PyObject_GetIter(value);
297 CHECK_OBJECT(iterator);
298
299 while (true) {
300 PyObject *item = PyIter_Next(iterator);
301 if (!item) {
302 assert(!HAS_ERROR_OCCURRED(tstate));
303 break;
304 }
305
306 CHECK_OBJECT(item);
307
308 result ^= DEEP_HASH(tstate, item);
309
310 Py_DECREF(item);
311 }
312
313 Py_DECREF(iterator);
314
315 return result;
316 } else if (PyLong_Check(value)) {
317 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
318
319 struct Nuitka_ExceptionPreservationItem saved_exception_state;
320
321 FETCH_ERROR_OCCURRED_STATE_UNTRACED(tstate, &saved_exception_state);
322
323 // Use string to hash the long value, which relies on that to not
324 // use the object address.
325 PyObject *str = PyObject_Str(value);
326 CHECK_OBJECT(str);
327 result ^= DEEP_HASH(tstate, str);
328 Py_DECREF(str);
329
330 RESTORE_ERROR_OCCURRED_STATE_UNTRACED(tstate, &saved_exception_state);
331
332 return result;
333 } else if (PyUnicode_Check(value)) {
334 Py_hash_t result = DEEP_HASH(tstate, (PyObject *)Py_TYPE(value));
335
336 struct Nuitka_ExceptionPreservationItem saved_exception_state;
337
338 FETCH_ERROR_OCCURRED_STATE_UNTRACED(tstate, &saved_exception_state);
339
340#if PYTHON_VERSION >= 0x300
341 char const *s = (char const *)PyUnicode_DATA(value);
342 Py_ssize_t size = PyUnicode_GET_LENGTH(value) * PyUnicode_KIND(value);
343
344 DEEP_HASH_BLOB(&result, s, size);
345#else
346 PyObject *str = PyUnicode_AsUTF8String(value);
347 CHECK_OBJECT(str);
348 result ^= DEEP_HASH(tstate, str);
349
350 Py_DECREF(str);
351#endif
352 RESTORE_ERROR_OCCURRED_STATE_UNTRACED(tstate, &saved_exception_state);
353
354 return result;
355 }
356#if PYTHON_VERSION < 0x300
357 else if (PyString_Check(value)) {
358 Py_hash_t result = DEEP_HASH(tstate, (PyObject *)Py_TYPE(value));
359
360 Py_ssize_t size;
361 char *s;
362
363 int res = PyString_AsStringAndSize(value, &s, &size);
364 assert(res != -1);
365
366 DEEP_HASH_BLOB(&result, s, size);
367
368 return result;
369 }
370#else
371 else if (PyBytes_Check(value)) {
372 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
373
374 Py_ssize_t size;
375 char *s;
376
377 int res = PyBytes_AsStringAndSize(value, &s, &size);
378 assert(res != -1);
379
380 DEEP_HASH_BLOB(&result, s, size);
381
382 return result;
383 }
384#endif
385 else if (PyByteArray_Check(value)) {
386 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
387
388 Py_ssize_t size = PyByteArray_Size(value);
389 assert(size >= 0);
390
391 char *s = PyByteArray_AsString(value);
392
393 DEEP_HASH_BLOB(&result, s, size);
394
395 return result;
396 } else if (value == Py_None || value == Py_Ellipsis || value == Py_NotImplemented) {
397 return DEEP_HASH_INIT(tstate, value);
398 } else if (PyComplex_Check(value)) {
399 Py_complex c = PyComplex_AsCComplex(value);
400
401 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
402
403 Py_ssize_t size = sizeof(c);
404 char *s = (char *)&c;
405
406 DEEP_HASH_BLOB(&result, s, size);
407
408 return result;
409 } else if (PyFloat_Check(value)) {
410 double f = PyFloat_AsDouble(value);
411
412 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
413
414 Py_ssize_t size = sizeof(f);
415 char *s = (char *)&f;
416
417 DEEP_HASH_BLOB(&result, s, size);
418
419 return result;
420 } else if (
421#if PYTHON_VERSION < 0x300
422 PyInt_Check(value) ||
423#endif
424 PyBool_Check(value) || PyRange_Check(value) || PySlice_Check(value) || PyCFunction_Check(value)) {
425 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
426
427#if 0
428 printf("Too simple deep hash: %s\n", Py_TYPE(value)->tp_name);
429#endif
430
431 return result;
432#if PYTHON_VERSION >= 0x390
433 } else if (Py_TYPE(value) == &Py_GenericAliasType) {
434 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
435
436 GenericAliasObject *generic_alias = (GenericAliasObject *)value;
437 CHECK_OBJECT(generic_alias->args);
438 CHECK_OBJECT(generic_alias->origin);
439
440 result ^= DEEP_HASH(tstate, generic_alias->args);
441 result ^= DEEP_HASH(tstate, generic_alias->origin);
442
443 return result;
444#endif
445#if PYTHON_VERSION >= 0x3a0
446 } else if (Py_TYPE(value) == Nuitka_PyUnion_Type) {
447 Py_hash_t result = DEEP_HASH_INIT(tstate, value);
448 PyObject *args = LOOKUP_ATTRIBUTE(tstate, value, const_str_plain___args__);
449 CHECK_OBJECT(args);
450
451 result ^= DEEP_HASH(tstate, args);
452 Py_DECREF(args);
453
454 return result;
455#endif
456 } else if (PyCode_Check(value)) {
457 return DEEP_HASH_INIT(tstate, value);
458 } else {
459 NUITKA_CANNOT_GET_HERE("Unknown type hashed");
460
461 return -1;
462 }
463}
464#endif
465
466static void abortCorruptNamedObject(char const *name, char const *reason) {
467 fprintf(stderr, "Corrupt object at %s: %s\n", name, reason);
468 fflush(stderr);
469 abort();
470}
471
472static void abortCorruptNamedRefcount(char const *name, PyObject *value) {
473 fprintf(stderr, "Corrupt object at %s: refcount %ld\n", name, (long)Py_REFCNT(value));
474 fflush(stderr);
475 abort();
476}
477
478static void CHECK_OBJECT_TYPE_NAMED(char const *name, PyObject *value) {
479 char type_name[1024];
480 PyTypeObject *type = Py_TYPE(value);
481
482 PyOS_snprintf(type_name, sizeof(type_name), "%s.__class__", name);
483
484 if (type == NULL) {
485 abortCorruptNamedObject(type_name, "NULL");
486 }
487
488 if (Py_REFCNT((PyObject *)type) <= 0) {
489 abortCorruptNamedRefcount(type_name, (PyObject *)type);
490 }
491}
492
493static void CHECK_OBJECT_DEEP_NAMED_RECURSIVE(char const *name, PyObject *value) {
494 if (value == NULL) {
495 abortCorruptNamedObject(name, "NULL");
496 }
497
498 if (Py_REFCNT(value) <= 0) {
499 abortCorruptNamedRefcount(name, value);
500 }
501
502 CHECK_OBJECT_TYPE_NAMED(name, value);
503
504 if (PyTuple_Check(value)) {
505 for (Py_ssize_t i = 0, size = PyTuple_GET_SIZE(value); i < size; i++) {
506 char element_name[1024];
507 PyObject *element = PyTuple_GET_ITEM(value, i);
508
509 PyOS_snprintf(element_name, sizeof(element_name), "%s[%ld]", name, (long)i);
510 CHECK_OBJECT_DEEP_NAMED_RECURSIVE(element_name, element);
511 }
512 } else if (PyList_CheckExact(value)) {
513 for (Py_ssize_t i = 0, size = PyList_GET_SIZE(value); i < size; i++) {
514 char element_name[1024];
515 PyObject *element = PyList_GET_ITEM(value, i);
516
517 PyOS_snprintf(element_name, sizeof(element_name), "%s[%ld]", name, (long)i);
518 CHECK_OBJECT_DEEP_NAMED_RECURSIVE(element_name, element);
519 }
520 } else if (PyDict_Check(value)) {
521 Py_ssize_t pos = 0;
522 PyObject *dict_key, *dict_value;
523 int item_index = 0;
524
525 while (Nuitka_DictNext(value, &pos, &dict_key, &dict_value)) {
526 char key_name[1024];
527 char value_name[1024];
528
529 PyOS_snprintf(key_name, sizeof(key_name), "%s{key %d}", name, item_index);
530 PyOS_snprintf(value_name, sizeof(value_name), "%s{value %d}", name, item_index);
531
532 CHECK_OBJECT_DEEP_NAMED_RECURSIVE(key_name, dict_key);
533 CHECK_OBJECT_DEEP_NAMED_RECURSIVE(value_name, dict_value);
534
535 item_index += 1;
536 }
537 } else if (PySet_Check(value) || PyFrozenSet_Check(value)) {
538 PyObject *iterator = PyObject_GetIter(value);
539
540 if (iterator == NULL) {
541 abortCorruptNamedObject(name, "set iteration failed");
542 }
543
544 Py_ssize_t item_index = 0;
545
546 while (true) {
547 PyObject *item = PyIter_Next(iterator);
548
549 if (item == NULL) {
550 if (PyErr_Occurred()) {
551 Py_DECREF(iterator);
552 abortCorruptNamedObject(name, "set iteration raised");
553 }
554
555 break;
556 }
557
558 char item_name[1024];
559
560 PyOS_snprintf(item_name, sizeof(item_name), "%s{item %ld}", name, (long)item_index);
561 CHECK_OBJECT_DEEP_NAMED_RECURSIVE(item_name, item);
562 Py_DECREF(item);
563
564 item_index += 1;
565 }
566
567 Py_DECREF(iterator);
568 }
569}
570
571// Note: Not recursion safe, cannot do this everywhere.
572void CHECK_OBJECT_DEEP(PyObject *value) { CHECK_OBJECT_DEEP_NAMED_RECURSIVE("<unnamed>", value); }
573
574void CHECK_OBJECT_DEEP_NAMED(char const *name, PyObject *value) { CHECK_OBJECT_DEEP_NAMED_RECURSIVE(name, value); }
575
576void CHECK_OBJECTS_DEEP(PyObject *const *values, Py_ssize_t size) {
577 for (Py_ssize_t i = 0; i < size; i++) {
578 CHECK_OBJECT_DEEP(values[i]);
579 }
580}
581
582static PyObject *_DEEP_COPY_LIST_GUIDED(PyThreadState *tstate, PyObject *value, char const **guide);
583static PyObject *_DEEP_COPY_TUPLE_GUIDED(PyThreadState *tstate, PyObject *value, char const **guide);
584
585static PyObject *_DEEP_COPY_ELEMENT_GUIDED(PyThreadState *tstate, PyObject *value, char const **guide) {
586 char code = **guide;
587 *guide += 1;
588
589 switch (code) {
590 case 'i':
591 Py_INCREF(value);
592 return value;
593 case 'L':
594 return _DEEP_COPY_LIST_GUIDED(tstate, value, guide);
595 case 'l':
596 return LIST_COPY(tstate, value);
597 case 'T':
598 return _DEEP_COPY_TUPLE_GUIDED(tstate, value, guide);
599 case 't':
600 return TUPLE_COPY(tstate, value);
601 case 'D':
602 return DEEP_COPY_DICT(tstate, value);
603 case 'd':
604 return DICT_COPY(tstate, value);
605 case 'S':
606 return DEEP_COPY_SET(tstate, value);
607 case 'B':
608 return BYTEARRAY_COPY(tstate, value);
609 case '?':
610 return DEEP_COPY(tstate, value);
611 default:
612 NUITKA_CANNOT_GET_HERE("Illegal type guide");
613 abort();
614 }
615}
616
617static PyObject *_DEEP_COPY_LIST_GUIDED(PyThreadState *tstate, PyObject *value, char const **guide) {
618 assert(PyList_CheckExact(value));
619
620 Py_ssize_t size = PyList_GET_SIZE(value);
621
622 PyObject *result = MAKE_LIST_EMPTY(tstate, size);
623
624 for (Py_ssize_t i = 0; i < size; i++) {
625 PyObject *item = _DEEP_COPY_ELEMENT_GUIDED(tstate, PyList_GET_ITEM(value, i), guide);
626
627 PyList_SET_ITEM(result, i, item);
628 }
629
630 return result;
631}
632
633static PyObject *_DEEP_COPY_TUPLE_GUIDED(PyThreadState *tstate, PyObject *value, char const **guide) {
634 assert(PyTuple_CheckExact(value));
635
636 Py_ssize_t size = PyTuple_GET_SIZE(value);
637
638 // We cannot have size 0, so this is safe.
639 assert(size > 0);
640 PyObject *result = MAKE_TUPLE_EMPTY(tstate, size);
641
642 for (Py_ssize_t i = 0; i < size; i++) {
643 PyObject *item = _DEEP_COPY_ELEMENT_GUIDED(tstate, PyTuple_GET_ITEM(value, i), guide);
644
645 PyTuple_SET_ITEM(result, i, item);
646 }
647
648 return result;
649}
650
651PyObject *DEEP_COPY_LIST_GUIDED(PyThreadState *tstate, PyObject *value, char const *guide) {
652 PyObject *result = _DEEP_COPY_LIST_GUIDED(tstate, value, &guide);
653 assert(*guide == 0);
654 return result;
655}
656
657PyObject *DEEP_COPY_TUPLE_GUIDED(PyThreadState *tstate, PyObject *value, char const *guide) {
658 PyObject *result = _DEEP_COPY_TUPLE_GUIDED(tstate, value, &guide);
659 assert(*guide == 0);
660 return result;
661}
662
663// Part of "Nuitka", an optimizing Python compiler that is compatible and
664// integrates with CPython, but also works on its own.
665//
666// Licensed under the GNU Affero General Public License, Version 3 (the "License");
667// you may not use this file except in compliance with the License.
668// You may obtain a copy of the License at
669//
670// http://www.gnu.org/licenses/agpl.txt
671//
672// Unless required by applicable law or agreed to in writing, software
673// distributed under the License is distributed on an "AS IS" BASIS,
674// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
675// See the License for the specific language governing permissions and
676// limitations under the License.
Definition exceptions.h:712