Nuitka
The Python compiler
Loading...
Searching...
No Matches
HelpersTuples.c
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3/* These helpers are used to work with tuples.
4
5*/
6
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 NUITKA_TUPLE_HAS_FREELIST
14
15PyObject *MAKE_TUPLE_EMPTY(PyThreadState *tstate, Py_ssize_t size) {
16 PyTupleObject *result_tuple;
17
18 // Lets not get called other than this
19 assert(size > 0);
20
21#if PYTHON_VERSION >= 0x3e0
22 Py_ssize_t index = size - 1;
23
24 if (index < PyTuple_MAXSAVESIZE) {
25 result_tuple = (PyTupleObject *)Nuitka_PyFreeList_Pop(&_Py_freelists_GET()->tuples[index]);
26 } else {
27 result_tuple = NULL;
28 }
29
30 if (result_tuple == NULL) {
31 result_tuple = (PyTupleObject *)Nuitka_GC_NewVar(&PyTuple_Type, size);
32 } else {
33 _PyTuple_RESET_HASH_CACHE(result_tuple);
34 Nuitka_Py_NewReference((PyObject *)result_tuple);
35 }
36#else
37 // This is the CPython name, spell-checker: ignore numfree
38#if PYTHON_VERSION < 0x3d0
39 PyTupleObject **items = tstate->interp->tuple.free_list;
40 int *numfree = tstate->interp->tuple.numfree;
41#else
42 struct _Py_object_freelists *freelists = _Nuitka_object_freelists_GET(tstate);
43 struct _Py_tuple_freelist *state = &freelists->tuples;
44 PyTupleObject **items = state->items;
45 int *numfree = state->numfree;
46#endif
47
48#if PYTHON_VERSION < 0x3b0
49 Py_ssize_t index = size;
50#else
51 Py_ssize_t index = size - 1;
52#endif
53
54 if ((size < PyTuple_MAXSAVESIZE) && (result_tuple = items[index]) != NULL) {
55 items[index] = (PyTupleObject *)result_tuple->ob_item[0];
56 numfree[index] -= 1;
57
58 assert(Py_SIZE(result_tuple) == size);
59 assert(Py_TYPE(result_tuple) == &PyTuple_Type);
60
61 Nuitka_Py_NewReference((PyObject *)result_tuple);
62 } else {
63 // Check for overflow
64 if ((size_t)size >
65 ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) - sizeof(PyObject *))) / sizeof(PyObject *)) {
66 return PyErr_NoMemory();
67 }
68
69 result_tuple = (PyTupleObject *)Nuitka_GC_NewVar(&PyTuple_Type, size);
70 }
71#endif
72
73 // TODO: Why not use memset here, and can we rely on memory being cleared
74 // by allocator?
75
76 // TODO: When first initializing the tuple, we might skip this and use
77 // assignments that ignore this.
78 for (Py_ssize_t i = 0; i < size; i++) {
79 result_tuple->ob_item[i] = NULL;
80 }
81
82 Nuitka_GC_Track(result_tuple);
83
84 assert(PyTuple_CheckExact(result_tuple));
85 assert(PyTuple_GET_SIZE(result_tuple) == size);
86
87 return (PyObject *)result_tuple;
88}
89
90PyObject *MAKE_TUPLE_EMPTY_VAR(PyThreadState *tstate, Py_ssize_t size) {
91 if (size == 0) {
92 PyObject *result = const_tuple_empty;
93 Py_INCREF(result);
94 return result;
95 } else {
96 return MAKE_TUPLE_EMPTY(tstate, size);
97 }
98}
99
100#endif
101
102PyObject *TUPLE_CONCAT(PyThreadState *tstate, PyObject *tuple1, PyObject *tuple2) {
103 Py_ssize_t size = Py_SIZE(tuple1) + Py_SIZE(tuple2);
104
105 // Do not ignore MemoryError, may actually happen.
106 PyTupleObject *result = (PyTupleObject *)MAKE_TUPLE_EMPTY_VAR(tstate, size);
107 if (unlikely(result == NULL)) {
108 return NULL;
109 }
110
111 PyObject **src = ((PyTupleObject *)tuple1)->ob_item;
112 PyObject **dest = result->ob_item;
113
114 for (Py_ssize_t i = 0; i < Py_SIZE(tuple1); i++) {
115 PyObject *v = src[i];
116 Py_INCREF(v);
117 dest[i] = v;
118 }
119
120 src = ((PyTupleObject *)tuple2)->ob_item;
121 dest = result->ob_item + Py_SIZE(tuple1);
122
123 for (Py_ssize_t i = 0; i < Py_SIZE(tuple2); i++) {
124 PyObject *v = src[i];
125 Py_INCREF(v);
126 dest[i] = v;
127 }
128
129 return (PyObject *)result;
130}
131
132PyObject *TUPLE_COPY(PyThreadState *tstate, PyObject *tuple) {
133 CHECK_OBJECT(tuple);
134 assert(PyTuple_CheckExact(tuple));
135
136 Py_ssize_t size = PyTuple_GET_SIZE(tuple);
137 PyObject *result = MAKE_TUPLE_EMPTY_VAR(tstate, size);
138
139 if (unlikely(result == NULL)) {
140 return NULL;
141 }
142
143 for (Py_ssize_t i = 0; i < size; i++) {
144 PyObject *item = PyTuple_GET_ITEM(tuple, i);
145 Py_INCREF(item);
146 PyList_SET_ITEM(result, i, item);
147 }
148
149 return result;
150}
151
152// Part of "Nuitka", an optimizing Python compiler that is compatible and
153// integrates with CPython, but also works on its own.
154//
155// Licensed under the Apache License, Version 2.0 (the "License");
156// you may not use this file except in compliance with the License.
157// You may obtain a copy of the License at
158//
159// http://www.apache.org/licenses/LICENSE-2.0
160//
161// Unless required by applicable law or agreed to in writing, software
162// distributed under the License is distributed on an "AS IS" BASIS,
163// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
164// See the License for the specific language governing permissions and
165// limitations under the License.