Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/tupleobject.c
Line
Count
Source
1
/* Tuple object implementation */
2
3
#include "Python.h"
4
#include "pycore_abstract.h"      // _PyIndex_Check()
5
#include "pycore_ceval.h"         // _PyEval_GetBuiltin()
6
#include "pycore_freelist.h"      // _Py_FREELIST_PUSH()
7
#include "pycore_gc.h"            // _PyObject_GC_IS_TRACKED()
8
#include "pycore_list.h"          // _Py_memory_repeat()
9
#include "pycore_modsupport.h"    // _PyArg_NoKwnames()
10
#include "pycore_object.h"        // _PyObject_GC_TRACK()
11
#include "pycore_stackref.h"      // PyStackRef_AsPyObjectSteal()
12
#include "pycore_tuple.h"         // _PyTupleIterObject
13
14
15
/*[clinic input]
16
class tuple "PyTupleObject *" "&PyTuple_Type"
17
[clinic start generated code]*/
18
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f051ba3cfdf9a189]*/
19
20
#include "clinic/tupleobject.c.h"
21
22
23
static inline int maybe_freelist_push(PyTupleObject *);
24
25
26
/* Allocate an uninitialized tuple object. Before making it public, following
27
   steps must be done:
28
29
   - Initialize its items.
30
   - Call _PyObject_GC_TRACK() on it.
31
32
   Because the empty tuple is always reused and it's already tracked by GC,
33
   this function must not be called with size == 0 (unless from PyTuple_New()
34
   which wraps this function).
35
*/
36
static PyTupleObject *
37
tuple_alloc(Py_ssize_t size)
38
474M
{
39
474M
    if (size < 0) {
40
0
        PyErr_BadInternalCall();
41
0
        return NULL;
42
0
    }
43
474M
    assert(size != 0);    // The empty tuple is statically allocated.
44
474M
    Py_ssize_t index = size - 1;
45
474M
    if (index < PyTuple_MAXSAVESIZE) {
46
464M
        PyTupleObject *op = _Py_FREELIST_POP(PyTupleObject, tuples[index]);
47
464M
        if (op != NULL) {
48
357M
            _PyTuple_RESET_HASH_CACHE(op);
49
357M
            return op;
50
357M
        }
51
464M
    }
52
    /* Check for overflow */
53
117M
    if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
54
117M
                sizeof(PyObject *))) / sizeof(PyObject *)) {
55
0
        return (PyTupleObject *)PyErr_NoMemory();
56
0
    }
57
117M
    PyTupleObject *result = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
58
117M
    if (result != NULL) {
59
117M
        _PyTuple_RESET_HASH_CACHE(result);
60
117M
    }
61
117M
    return result;
62
117M
}
63
64
// The empty tuple singleton is not tracked by the GC.
65
// It does not contain any Python object.
66
// Note that tuple subclasses have their own empty instances.
67
68
static inline PyObject *
69
tuple_get_empty(void)
70
76.5M
{
71
76.5M
    return (PyObject *)&_Py_SINGLETON(tuple_empty);
72
76.5M
}
73
74
PyObject *
75
PyTuple_New(Py_ssize_t size)
76
66.5M
{
77
66.5M
    PyTupleObject *op;
78
66.5M
    if (size == 0) {
79
1.84M
        return tuple_get_empty();
80
1.84M
    }
81
64.7M
    op = tuple_alloc(size);
82
64.7M
    if (op == NULL) {
83
0
        return NULL;
84
0
    }
85
1.55G
    for (Py_ssize_t i = 0; i < size; i++) {
86
1.48G
        op->ob_item[i] = NULL;
87
1.48G
    }
88
64.7M
    _PyObject_GC_TRACK(op);
89
64.7M
    return (PyObject *) op;
90
64.7M
}
91
92
Py_ssize_t
93
PyTuple_Size(PyObject *op)
94
5.73M
{
95
5.73M
    if (!PyTuple_Check(op)) {
96
0
        PyErr_BadInternalCall();
97
0
        return -1;
98
0
    }
99
5.73M
    else
100
5.73M
        return Py_SIZE(op);
101
5.73M
}
102
103
PyObject *
104
PyTuple_GetItem(PyObject *op, Py_ssize_t i)
105
25.5M
{
106
25.5M
    if (!PyTuple_Check(op)) {
107
0
        PyErr_BadInternalCall();
108
0
        return NULL;
109
0
    }
110
25.5M
    if (i < 0 || i >= Py_SIZE(op)) {
111
0
        PyErr_SetString(PyExc_IndexError, "tuple index out of range");
112
0
        return NULL;
113
0
    }
114
25.5M
    return ((PyTupleObject *)op) -> ob_item[i];
115
25.5M
}
116
117
int
118
PyTuple_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem)
119
139k
{
120
139k
    PyObject **p;
121
139k
    if (!PyTuple_Check(op) || !_PyObject_IsUniquelyReferenced(op)) {
122
0
        Py_XDECREF(newitem);
123
0
        PyErr_BadInternalCall();
124
0
        return -1;
125
0
    }
126
139k
    if (i < 0 || i >= Py_SIZE(op)) {
127
0
        Py_XDECREF(newitem);
128
0
        PyErr_SetString(PyExc_IndexError,
129
0
                        "tuple assignment index out of range");
130
0
        return -1;
131
0
    }
132
139k
    p = ((PyTupleObject *)op) -> ob_item + i;
133
139k
    Py_XSETREF(*p, newitem);
134
139k
    return 0;
135
139k
}
136
137
void
138
_PyTuple_MaybeUntrack(PyObject *op)
139
227M
{
140
227M
    PyTupleObject *t;
141
227M
    Py_ssize_t i, n;
142
143
227M
    if (!PyTuple_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
144
0
        return;
145
227M
    t = (PyTupleObject *) op;
146
227M
    n = Py_SIZE(t);
147
539M
    for (i = 0; i < n; i++) {
148
525M
        PyObject *elt = PyTuple_GET_ITEM(t, i);
149
        /* Tuple with NULL elements aren't
150
           fully constructed, don't untrack
151
           them yet. */
152
525M
        if (!elt ||
153
525M
            _PyObject_GC_MAY_BE_TRACKED(elt))
154
213M
            return;
155
525M
    }
156
14.3M
    _PyObject_GC_UNTRACK(op);
157
14.3M
}
158
159
/* Fast, but conservative check if an object maybe tracked
160
   May return true for an object that is not tracked,
161
   Will always return true for an object that is tracked.
162
   This is a temporary workaround until _PyObject_GC_IS_TRACKED
163
   becomes fast and safe to call on non-GC objects.
164
*/
165
static bool
166
maybe_tracked(PyObject *ob)
167
1.46G
{
168
1.46G
    return _PyType_IS_GC(Py_TYPE(ob));
169
1.46G
}
170
171
PyObject *
172
PyTuple_Pack(Py_ssize_t n, ...)
173
969k
{
174
969k
    Py_ssize_t i;
175
969k
    PyObject *o;
176
969k
    PyObject **items;
177
969k
    va_list vargs;
178
969k
    bool track = false;
179
180
969k
    if (n == 0) {
181
0
        return tuple_get_empty();
182
0
    }
183
184
969k
    va_start(vargs, n);
185
969k
    PyTupleObject *result = tuple_alloc(n);
186
969k
    if (result == NULL) {
187
0
        va_end(vargs);
188
0
        return NULL;
189
0
    }
190
969k
    items = result->ob_item;
191
3.66M
    for (i = 0; i < n; i++) {
192
2.69M
        o = va_arg(vargs, PyObject *);
193
2.69M
        if (!track && maybe_tracked(o)) {
194
746k
            track = true;
195
746k
        }
196
2.69M
        items[i] = Py_NewRef(o);
197
2.69M
    }
198
969k
    va_end(vargs);
199
969k
    if (track) {
200
746k
        _PyObject_GC_TRACK(result);
201
746k
    }
202
969k
    return (PyObject *)result;
203
969k
}
204
205
PyObject *
206
_PyTuple_FromPair(PyObject *first, PyObject *second)
207
278k
{
208
278k
    assert(first != NULL);
209
278k
    assert(second != NULL);
210
211
278k
    return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
212
278k
}
213
214
PyObject *
215
_PyTuple_FromPairSteal(PyObject *first, PyObject *second)
216
18.2M
{
217
18.2M
    assert(first != NULL);
218
18.2M
    assert(second != NULL);
219
220
18.2M
    PyTupleObject *op = tuple_alloc(2);
221
18.2M
    if (op == NULL) {
222
0
        Py_DECREF(first);
223
0
        Py_DECREF(second);
224
0
        return NULL;
225
0
    }
226
18.2M
    PyObject **items = op->ob_item;
227
18.2M
    items[0] = first;
228
18.2M
    items[1] = second;
229
18.2M
    if (maybe_tracked(first) || maybe_tracked(second)) {
230
122k
        _PyObject_GC_TRACK(op);
231
122k
    }
232
18.2M
    return (PyObject *)op;
233
18.2M
}
234
235
/* Methods */
236
237
/*
238
 Free of a tuple where all contents have been stolen and
239
 is now untracked by GC. This operation is thus non-escaping.
240
 */
241
void
242
_PyStolenTuple_Free(PyObject *obj)
243
0
{
244
0
    assert(PyTuple_CheckExact(obj));
245
0
    PyTupleObject *op = _PyTuple_CAST(obj);
246
0
    assert(Py_SIZE(op) != 0);
247
0
    assert(!_PyObject_GC_IS_TRACKED(obj));
248
    // This will abort on the empty singleton (if there is one).
249
0
    if (!maybe_freelist_push(op)) {
250
0
        PyTuple_Type.tp_free((PyObject *)op);
251
0
    }
252
0
}
253
254
static void
255
tuple_dealloc(PyObject *self)
256
474M
{
257
474M
    PyTupleObject *op = _PyTuple_CAST(self);
258
474M
    if (Py_SIZE(op) == 0) {
259
        /* The empty tuple is statically allocated. */
260
8
        if (op == &_Py_SINGLETON(tuple_empty)) {
261
#ifdef Py_DEBUG
262
            _Py_FatalRefcountError("deallocating the empty tuple singleton");
263
#else
264
0
            return;
265
0
#endif
266
0
        }
267
#ifdef Py_DEBUG
268
        /* tuple subclasses have their own empty instances. */
269
        assert(!PyTuple_CheckExact(op));
270
#endif
271
8
    }
272
273
474M
    PyObject_GC_UnTrack(op);
274
275
474M
    Py_ssize_t i = Py_SIZE(op);
276
4.25G
    while (--i >= 0) {
277
3.78G
        Py_XDECREF(op->ob_item[i]);
278
3.78G
    }
279
    // This will abort on the empty singleton (if there is one).
280
474M
    if (!maybe_freelist_push(op)) {
281
116M
        Py_TYPE(op)->tp_free((PyObject *)op);
282
116M
    }
283
474M
}
284
285
static PyObject *
286
tuple_repr(PyObject *self)
287
53.4k
{
288
53.4k
    PyTupleObject *v = _PyTuple_CAST(self);
289
53.4k
    Py_ssize_t n = PyTuple_GET_SIZE(v);
290
53.4k
    if (n == 0) {
291
0
        return PyUnicode_FromString("()");
292
0
    }
293
294
    /* While not mutable, it is still possible to end up with a cycle in a
295
       tuple through an object that stores itself within a tuple (and thus
296
       infinitely asks for the repr of itself). This should only be
297
       possible within a type. */
298
53.4k
    int res = Py_ReprEnter((PyObject *)v);
299
53.4k
    if (res != 0) {
300
0
        return res > 0 ? PyUnicode_FromString("(...)") : NULL;
301
0
    }
302
303
53.4k
    Py_ssize_t prealloc;
304
53.4k
    if (n > 1) {
305
        // "(" + "1" + ", 2" * (len - 1) + ")"
306
27.0k
        prealloc = 1 + 1 + (2 + 1) * (n - 1) + 1;
307
27.0k
    }
308
26.3k
    else {
309
        // "(1,)"
310
26.3k
        prealloc = 4;
311
26.3k
    }
312
53.4k
    PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc);
313
53.4k
    if (writer == NULL) {
314
0
        goto error;
315
0
    }
316
317
53.4k
    if (PyUnicodeWriter_WriteChar(writer, '(') < 0) {
318
0
        goto error;
319
0
    }
320
321
    /* Do repr() on each element. */
322
144k
    for (Py_ssize_t i = 0; i < n; ++i) {
323
90.8k
        if (i > 0) {
324
37.4k
            if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
325
0
                goto error;
326
0
            }
327
37.4k
            if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) {
328
0
                goto error;
329
0
            }
330
37.4k
        }
331
332
90.8k
        if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) {
333
0
            goto error;
334
0
        }
335
90.8k
    }
336
337
53.4k
    if (n == 1) {
338
26.3k
        if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
339
0
            goto error;
340
0
        }
341
26.3k
    }
342
53.4k
    if (PyUnicodeWriter_WriteChar(writer, ')') < 0) {
343
0
        goto error;
344
0
    }
345
346
53.4k
    Py_ReprLeave((PyObject *)v);
347
53.4k
    return PyUnicodeWriter_Finish(writer);
348
349
0
error:
350
0
    PyUnicodeWriter_Discard(writer);
351
0
    Py_ReprLeave((PyObject *)v);
352
0
    return NULL;
353
53.4k
}
354
355
356
/* Hash for tuples. This is a slightly simplified version of the xxHash
357
   non-cryptographic hash:
358
   - we do not use any parallelism, there is only 1 accumulator.
359
   - we drop the final mixing since this is just a permutation of the
360
     output space: it does not help against collisions.
361
   - at the end, we mangle the length with a single constant.
362
   For the xxHash specification, see
363
   https://github.com/Cyan4973/xxHash/blob/master/doc/xxhash_spec.md
364
365
   The constants for the hash function are defined in pycore_tuple.h.
366
367
   If you update this code, update also frozendict_pair_hash() which copied
368
   this code.
369
*/
370
371
static Py_hash_t
372
tuple_hash(PyObject *op)
373
26.0M
{
374
26.0M
    PyTupleObject *v = _PyTuple_CAST(op);
375
376
26.0M
    Py_uhash_t acc = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->ob_hash);
377
26.0M
    if (acc != (Py_uhash_t)-1) {
378
4.26M
        return acc;
379
4.26M
    }
380
381
21.8M
    Py_ssize_t len = Py_SIZE(v);
382
21.8M
    PyObject **item = v->ob_item;
383
384
    /* Hashing an item recurses back into tuple_hash() when that item is
385
       itself a tuple, so guard the descent to raise RecursionError rather
386
       than overflow the C stack on a deeply nested tuple. */
387
21.8M
    if (_Py_EnterRecursiveCall(" while hashing a tuple")) {
388
0
        return -1;
389
0
    }
390
391
21.8M
    acc = _PyTuple_HASH_XXPRIME_5;
392
376M
    for (Py_ssize_t i = 0; i < len; i++) {
393
354M
        Py_uhash_t lane = PyObject_Hash(item[i]);
394
354M
        if (lane == (Py_uhash_t)-1) {
395
0
            _Py_LeaveRecursiveCall();
396
0
            return -1;
397
0
        }
398
354M
        acc += lane * _PyTuple_HASH_XXPRIME_2;
399
354M
        acc = _PyTuple_HASH_XXROTATE(acc);
400
354M
        acc *= _PyTuple_HASH_XXPRIME_1;
401
354M
    }
402
21.8M
    _Py_LeaveRecursiveCall();
403
404
    /* Add input length, mangled to keep the historical value of hash(()). */
405
21.8M
    acc += len ^ (_PyTuple_HASH_XXPRIME_5 ^ 3527539UL);
406
407
21.8M
    if (acc == (Py_uhash_t)-1) {
408
0
        acc = 1546275796;
409
0
    }
410
411
21.8M
    FT_ATOMIC_STORE_SSIZE_RELAXED(v->ob_hash, acc);
412
413
21.8M
    return acc;
414
21.8M
}
415
416
static Py_ssize_t
417
tuple_length(PyObject *self)
418
14.0M
{
419
14.0M
    PyTupleObject *a = _PyTuple_CAST(self);
420
14.0M
    return Py_SIZE(a);
421
14.0M
}
422
423
static int
424
tuple_contains(PyObject *self, PyObject *el)
425
57.6M
{
426
57.6M
    PyTupleObject *a = _PyTuple_CAST(self);
427
57.6M
    int cmp = 0;
428
190M
    for (Py_ssize_t i = 0; cmp == 0 && i < Py_SIZE(a); ++i) {
429
133M
        cmp = PyObject_RichCompareBool(PyTuple_GET_ITEM(a, i), el, Py_EQ);
430
133M
    }
431
57.6M
    return cmp;
432
57.6M
}
433
434
static PyObject *
435
tuple_item(PyObject *op, Py_ssize_t i)
436
20.6M
{
437
20.6M
    PyTupleObject *a = _PyTuple_CAST(op);
438
20.6M
    if (i < 0 || i >= Py_SIZE(a)) {
439
37
        PyErr_SetString(PyExc_IndexError, "tuple index out of range");
440
37
        return NULL;
441
37
    }
442
20.6M
    return Py_NewRef(a->ob_item[i]);
443
20.6M
}
444
445
PyObject *
446
PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
447
203M
{
448
203M
    if (n == 0) {
449
74.4M
        return tuple_get_empty();
450
74.4M
    }
451
452
128M
    PyTupleObject *tuple = tuple_alloc(n);
453
128M
    if (tuple == NULL) {
454
0
        return NULL;
455
0
    }
456
128M
    PyObject **dst = tuple->ob_item;
457
128M
    bool track = false;
458
1.22G
    for (Py_ssize_t i = 0; i < n; i++) {
459
1.09G
        PyObject *item = src[i];
460
1.09G
        if (!track && maybe_tracked(item)) {
461
39.2M
            track = true;
462
39.2M
        }
463
1.09G
        dst[i] = Py_NewRef(item);
464
1.09G
    }
465
128M
    if (track) {
466
39.2M
        _PyObject_GC_TRACK(tuple);
467
39.2M
    }
468
128M
    return (PyObject *)tuple;
469
128M
}
470
471
PyObject *
472
_PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
473
250M
{
474
250M
    if (n == 0) {
475
0
        return tuple_get_empty();
476
0
    }
477
250M
    PyTupleObject *tuple = tuple_alloc(n);
478
250M
    if (tuple == NULL) {
479
0
        return NULL;
480
0
    }
481
250M
    PyObject **dst = tuple->ob_item;
482
250M
    bool track = false;
483
765M
    for (Py_ssize_t i = 0; i < n; i++) {
484
515M
        PyObject *item = PyStackRef_AsPyObjectSteal(src[i]);
485
515M
        if (!track && maybe_tracked(item)) {
486
172M
            track = true;
487
172M
        }
488
515M
        dst[i] = item;
489
515M
    }
490
250M
    if (track) {
491
172M
        _PyObject_GC_TRACK(tuple);
492
172M
    }
493
250M
    return (PyObject *)tuple;
494
250M
}
495
496
PyObject *
497
_PyTuple_FromArraySteal(PyObject *const *src, Py_ssize_t n)
498
5.58M
{
499
5.58M
    if (n == 0) {
500
67
        return tuple_get_empty();
501
67
    }
502
5.58M
    PyTupleObject *tuple = tuple_alloc(n);
503
5.58M
    if (tuple == NULL) {
504
0
        for (Py_ssize_t i = 0; i < n; i++) {
505
0
            Py_DECREF(src[i]);
506
0
        }
507
0
        return NULL;
508
0
    }
509
5.58M
    PyObject **dst = tuple->ob_item;
510
30.2M
    for (Py_ssize_t i = 0; i < n; i++) {
511
24.6M
        PyObject *item = src[i];
512
24.6M
        dst[i] = item;
513
24.6M
    }
514
5.58M
    _PyObject_GC_TRACK(tuple);
515
5.58M
    return (PyObject *)tuple;
516
5.58M
}
517
518
static PyObject *
519
tuple_slice(PyTupleObject *a, Py_ssize_t ilow,
520
           Py_ssize_t ihigh)
521
18.7M
{
522
18.7M
    if (ilow < 0)
523
0
        ilow = 0;
524
18.7M
    if (ihigh > Py_SIZE(a))
525
206
        ihigh = Py_SIZE(a);
526
18.7M
    if (ihigh < ilow)
527
0
        ihigh = ilow;
528
18.7M
    if (ilow == 0 && ihigh == Py_SIZE(a) && PyTuple_CheckExact(a)) {
529
0
        return Py_NewRef(a);
530
0
    }
531
18.7M
    return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
532
18.7M
}
533
534
PyObject *
535
_PyTuple_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
536
5.94M
{
537
5.94M
    assert(PyTuple_CheckExact(container));
538
5.94M
    Py_ssize_t len = Py_SIZE(container);
539
5.94M
    Py_ssize_t istart, istop;
540
5.94M
    if (!_PyEval_UnpackIndices(start, stop, len, &istart, &istop)) {
541
0
        return NULL;
542
0
    }
543
5.94M
    if (istart == 0 && istop == len) {
544
1.11k
        return Py_NewRef(container);
545
1.11k
    }
546
5.94M
    if (istop < istart) {
547
0
        istop = istart;
548
0
    }
549
5.94M
    return PyTuple_FromArray(((PyTupleObject *)container)->ob_item + istart,
550
5.94M
                             istop - istart);
551
5.94M
}
552
553
PyObject *
554
PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j)
555
18.7M
{
556
18.7M
    if (op == NULL || !PyTuple_Check(op)) {
557
0
        PyErr_BadInternalCall();
558
0
        return NULL;
559
0
    }
560
18.7M
    return tuple_slice((PyTupleObject *)op, i, j);
561
18.7M
}
562
563
PyObject *
564
_PyTuple_Concat(PyObject *aa, PyObject *bb)
565
5.42M
{
566
5.42M
    PyTupleObject *a = _PyTuple_CAST(aa);
567
5.42M
    if (Py_SIZE(a) == 0 && PyTuple_CheckExact(bb)) {
568
134k
        return Py_NewRef(bb);
569
134k
    }
570
5.29M
    if (!PyTuple_Check(bb)) {
571
0
        PyErr_Format(PyExc_TypeError,
572
0
             "can only concatenate tuple (not \"%.200s\") to tuple",
573
0
                 Py_TYPE(bb)->tp_name);
574
0
        return NULL;
575
0
    }
576
5.29M
    PyTupleObject *b = (PyTupleObject *)bb;
577
578
5.29M
    if (Py_SIZE(b) == 0 && PyTuple_CheckExact(a)) {
579
25.8k
        return Py_NewRef(a);
580
25.8k
    }
581
5.29M
    assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX);
582
5.26M
    Py_ssize_t size = Py_SIZE(a) + Py_SIZE(b);
583
5.26M
    if (size == 0) {
584
0
        return tuple_get_empty();
585
0
    }
586
587
5.26M
    PyTupleObject *np = tuple_alloc(size);
588
5.26M
    if (np == NULL) {
589
0
        return NULL;
590
0
    }
591
592
5.26M
    PyObject **src = a->ob_item;
593
5.26M
    PyObject **dest = np->ob_item;
594
337M
    for (Py_ssize_t i = 0; i < Py_SIZE(a); i++) {
595
332M
        PyObject *v = src[i];
596
332M
        dest[i] = Py_NewRef(v);
597
332M
    }
598
599
5.26M
    src = b->ob_item;
600
5.26M
    dest = np->ob_item + Py_SIZE(a);
601
284M
    for (Py_ssize_t i = 0; i < Py_SIZE(b); i++) {
602
278M
        PyObject *v = src[i];
603
278M
        dest[i] = Py_NewRef(v);
604
278M
    }
605
606
5.26M
    _PyObject_GC_TRACK(np);
607
5.26M
    return (PyObject *)np;
608
5.26M
}
609
610
PyObject *
611
_PyTuple_Repeat(PyObject *self, Py_ssize_t n)
612
0
{
613
0
    PyTupleObject *a = _PyTuple_CAST(self);
614
0
    const Py_ssize_t input_size = Py_SIZE(a);
615
0
    if (input_size == 0 || n == 1) {
616
0
        if (PyTuple_CheckExact(a)) {
617
            /* Since tuples are immutable, we can return a shared
618
               copy in this case */
619
0
            return Py_NewRef(a);
620
0
        }
621
0
    }
622
0
    if (input_size == 0 || n <= 0) {
623
0
        return tuple_get_empty();
624
0
    }
625
0
    assert(n>0);
626
627
0
    if (input_size > PY_SSIZE_T_MAX / n)
628
0
        return PyErr_NoMemory();
629
0
    Py_ssize_t output_size = input_size * n;
630
631
0
    PyTupleObject *np = tuple_alloc(output_size);
632
0
    if (np == NULL)
633
0
        return NULL;
634
635
0
    PyObject **dest = np->ob_item;
636
0
    if (input_size == 1) {
637
0
        PyObject *elem = a->ob_item[0];
638
0
        _Py_RefcntAdd(elem, n);
639
0
        PyObject **dest_end = dest + output_size;
640
0
        while (dest < dest_end) {
641
0
            *dest++ = elem;
642
0
        }
643
0
    }
644
0
    else {
645
0
        PyObject **src = a->ob_item;
646
0
        PyObject **src_end = src + input_size;
647
0
        while (src < src_end) {
648
0
            _Py_RefcntAdd(*src, n);
649
0
            *dest++ = *src++;
650
0
        }
651
652
0
        _Py_memory_repeat((char *)np->ob_item, sizeof(PyObject *)*output_size,
653
0
                          sizeof(PyObject *)*input_size);
654
0
    }
655
0
    _PyObject_GC_TRACK(np);
656
0
    return (PyObject *) np;
657
0
}
658
659
/*[clinic input]
660
tuple.index
661
662
    value: object
663
    start: slice_index(accept={int}) = 0
664
    stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize
665
    /
666
667
Return first index of value.
668
669
Raises ValueError if the value is not present.
670
[clinic start generated code]*/
671
672
static PyObject *
673
tuple_index_impl(PyTupleObject *self, PyObject *value, Py_ssize_t start,
674
                 Py_ssize_t stop)
675
/*[clinic end generated code: output=07b6f9f3cb5c33eb input=fb39e9874a21fe3f]*/
676
724
{
677
724
    Py_ssize_t i;
678
679
724
    if (start < 0) {
680
0
        start += Py_SIZE(self);
681
0
        if (start < 0)
682
0
            start = 0;
683
0
    }
684
724
    if (stop < 0) {
685
0
        stop += Py_SIZE(self);
686
0
    }
687
724
    else if (stop > Py_SIZE(self)) {
688
724
        stop = Py_SIZE(self);
689
724
    }
690
932
    for (i = start; i < stop; i++) {
691
372
        int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
692
372
        if (cmp > 0)
693
164
            return PyLong_FromSsize_t(i);
694
208
        else if (cmp < 0)
695
0
            return NULL;
696
372
    }
697
560
    PyErr_SetString(PyExc_ValueError, "tuple.index(x): x not in tuple");
698
560
    return NULL;
699
724
}
700
701
/*[clinic input]
702
tuple.count
703
704
     value: object
705
     /
706
707
Return number of occurrences of value.
708
[clinic start generated code]*/
709
710
static PyObject *
711
tuple_count_impl(PyTupleObject *self, PyObject *value)
712
/*[clinic end generated code: output=cf02888d4bc15d7a input=531721aff65bd772]*/
713
0
{
714
0
    Py_ssize_t count = 0;
715
0
    Py_ssize_t i;
716
717
0
    for (i = 0; i < Py_SIZE(self); i++) {
718
0
        int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
719
0
        if (cmp > 0)
720
0
            count++;
721
0
        else if (cmp < 0)
722
0
            return NULL;
723
0
    }
724
0
    return PyLong_FromSsize_t(count);
725
0
}
726
727
static int
728
tuple_traverse(PyObject *self, visitproc visit, void *arg)
729
456M
{
730
456M
    PyTupleObject *o = _PyTuple_CAST(self);
731
1.92G
    for (Py_ssize_t i = Py_SIZE(o); --i >= 0; ) {
732
1.46G
        Py_VISIT(o->ob_item[i]);
733
1.46G
    }
734
456M
    return 0;
735
456M
}
736
737
static PyObject *
738
tuple_richcompare(PyObject *v, PyObject *w, int op)
739
18.5M
{
740
18.5M
    PyTupleObject *vt, *wt;
741
18.5M
    Py_ssize_t i;
742
18.5M
    Py_ssize_t vlen, wlen;
743
744
18.5M
    if (!PyTuple_Check(v) || !PyTuple_Check(w))
745
8
        Py_RETURN_NOTIMPLEMENTED;
746
747
18.5M
    vt = (PyTupleObject *)v;
748
18.5M
    wt = (PyTupleObject *)w;
749
750
18.5M
    vlen = Py_SIZE(vt);
751
18.5M
    wlen = Py_SIZE(wt);
752
753
    /* Note:  the corresponding code for lists has an "early out" test
754
     * here when op is EQ or NE and the lengths differ.  That pays there,
755
     * but Tim was unable to find any real code where EQ/NE tuple
756
     * compares don't have the same length, so testing for it here would
757
     * have cost without benefit.
758
     */
759
760
    /* Search for the first index where items are different.
761
     * Note that because tuples are immutable, it's safe to reuse
762
     * vlen and wlen across the comparison calls.
763
     */
764
57.0M
    for (i = 0; i < vlen && i < wlen; i++) {
765
39.8M
        int k = PyObject_RichCompareBool(vt->ob_item[i],
766
39.8M
                                         wt->ob_item[i], Py_EQ);
767
39.8M
        if (k < 0)
768
0
            return NULL;
769
39.8M
        if (!k)
770
1.44M
            break;
771
39.8M
    }
772
773
18.5M
    if (i >= vlen || i >= wlen) {
774
        /* No more items to compare -- compare sizes */
775
17.1M
        Py_RETURN_RICHCOMPARE(vlen, wlen, op);
776
17.1M
    }
777
778
    /* We have an item that differs -- shortcuts for EQ/NE */
779
1.44M
    if (op == Py_EQ) {
780
292k
        Py_RETURN_FALSE;
781
292k
    }
782
1.15M
    if (op == Py_NE) {
783
150k
        Py_RETURN_TRUE;
784
150k
    }
785
786
    /* Compare the final item again using the proper operator */
787
1.00M
    return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op);
788
1.15M
}
789
790
static PyObject *
791
tuple_subtype_new(PyTypeObject *type, PyObject *iterable);
792
793
/*[clinic input]
794
@vectorcall
795
@classmethod
796
tuple.__new__ as tuple_new
797
    iterable: object(c_default="NULL") = ()
798
    /
799
800
Built-in immutable sequence.
801
802
If no argument is given, the constructor returns an empty tuple.
803
If iterable is specified the tuple is initialized from iterable's items.
804
805
If the argument is a tuple, the return value is the same object.
806
[clinic start generated code]*/
807
808
static PyObject *
809
tuple_new_impl(PyTypeObject *type, PyObject *iterable)
810
/*[clinic end generated code: output=4546d9f0d469bce7 input=8fdda913493ebe48]*/
811
1.16M
{
812
1.16M
    if (type != &PyTuple_Type)
813
584k
        return tuple_subtype_new(type, iterable);
814
815
584k
    if (iterable == NULL) {
816
0
        return tuple_get_empty();
817
0
    }
818
584k
    else {
819
584k
        return PySequence_Tuple(iterable);
820
584k
    }
821
584k
}
822
823
static PyObject *
824
tuple_subtype_new(PyTypeObject *type, PyObject *iterable)
825
584k
{
826
584k
    PyObject *tmp, *newobj, *item;
827
584k
    Py_ssize_t i, n;
828
829
584k
    assert(PyType_IsSubtype(type, &PyTuple_Type));
830
    // tuple subclasses must implement the GC protocol
831
584k
    assert(_PyType_IS_GC(type));
832
833
584k
    tmp = tuple_new_impl(&PyTuple_Type, iterable);
834
584k
    if (tmp == NULL)
835
0
        return NULL;
836
584k
    assert(PyTuple_Check(tmp));
837
    /* This may allocate an empty tuple that is not the global one. */
838
584k
    newobj = type->tp_alloc(type, n = PyTuple_GET_SIZE(tmp));
839
584k
    if (newobj == NULL) {
840
0
        Py_DECREF(tmp);
841
0
        return NULL;
842
0
    }
843
2.23M
    for (i = 0; i < n; i++) {
844
1.65M
        item = PyTuple_GET_ITEM(tmp, i);
845
1.65M
        PyTuple_SET_ITEM(newobj, i, Py_NewRef(item));
846
1.65M
    }
847
584k
    Py_DECREF(tmp);
848
849
584k
    _PyTuple_RESET_HASH_CACHE(newobj);
850
851
    // Don't track if a subclass tp_alloc is PyType_GenericAlloc()
852
584k
    if (!_PyObject_GC_IS_TRACKED(newobj)) {
853
0
        _PyObject_GC_TRACK(newobj);
854
0
    }
855
584k
    return newobj;
856
584k
}
857
858
static PySequenceMethods tuple_as_sequence = {
859
    tuple_length,                               /* sq_length */
860
    _PyTuple_Concat,                            /* sq_concat */
861
    _PyTuple_Repeat,                            /* sq_repeat */
862
    tuple_item,                                 /* sq_item */
863
    0,                                          /* sq_slice */
864
    0,                                          /* sq_ass_item */
865
    0,                                          /* sq_ass_slice */
866
    tuple_contains,                             /* sq_contains */
867
};
868
869
static _PyObjectIndexPair
870
tuple_iteritem(PyObject *obj, Py_ssize_t index)
871
6.37k
{
872
6.37k
    if (index >= PyTuple_GET_SIZE(obj)) {
873
460
        return (_PyObjectIndexPair) { .object = NULL, .index = index };
874
460
    }
875
5.91k
    PyObject *result = PyTuple_GET_ITEM(obj, index);
876
5.91k
    Py_INCREF(result);
877
5.91k
    return (_PyObjectIndexPair) { .object = result, .index = index + 1 };
878
6.37k
}
879
880
static PyObject*
881
tuple_subscript(PyObject *op, PyObject* item)
882
3.89M
{
883
3.89M
    PyTupleObject *self = _PyTuple_CAST(op);
884
3.89M
    if (_PyIndex_Check(item)) {
885
2.66M
        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
886
2.66M
        if (i == -1 && PyErr_Occurred())
887
0
            return NULL;
888
2.66M
        if (i < 0)
889
2.66M
            i += PyTuple_GET_SIZE(self);
890
2.66M
        return tuple_item(op, i);
891
2.66M
    }
892
1.22M
    else if (PySlice_Check(item)) {
893
1.22M
        Py_ssize_t start, stop, step, slicelength, i;
894
1.22M
        size_t cur;
895
1.22M
        PyObject* it;
896
1.22M
        PyObject **src, **dest;
897
898
1.22M
        if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
899
0
            return NULL;
900
0
        }
901
1.22M
        slicelength = PySlice_AdjustIndices(PyTuple_GET_SIZE(self), &start,
902
1.22M
                                            &stop, step);
903
904
1.22M
        if (slicelength <= 0) {
905
265k
            return tuple_get_empty();
906
265k
        }
907
963k
        else if (start == 0 && step == 1 &&
908
8.83k
                 slicelength == PyTuple_GET_SIZE(self) &&
909
0
                 PyTuple_CheckExact(self)) {
910
0
            return Py_NewRef(self);
911
0
        }
912
963k
        else {
913
963k
            PyTupleObject* result = tuple_alloc(slicelength);
914
963k
            if (!result) return NULL;
915
916
963k
            src = self->ob_item;
917
963k
            dest = result->ob_item;
918
7.69M
            for (cur = start, i = 0; i < slicelength;
919
6.73M
                 cur += step, i++) {
920
6.73M
                it = Py_NewRef(src[cur]);
921
6.73M
                dest[i] = it;
922
6.73M
            }
923
924
963k
            _PyObject_GC_TRACK(result);
925
963k
            return (PyObject *)result;
926
963k
        }
927
1.22M
    }
928
0
    else {
929
0
        PyErr_Format(PyExc_TypeError,
930
0
                     "tuple indices must be integers or slices, not %.200s",
931
0
                     Py_TYPE(item)->tp_name);
932
0
        return NULL;
933
0
    }
934
3.89M
}
935
936
/*[clinic input]
937
tuple.__getnewargs__
938
[clinic start generated code]*/
939
940
static PyObject *
941
tuple___getnewargs___impl(PyTupleObject *self)
942
/*[clinic end generated code: output=25e06e3ee56027e2 input=1aeb4b286a21639a]*/
943
0
{
944
0
    return Py_BuildValue("(N)", tuple_slice(self, 0, Py_SIZE(self)));
945
0
}
946
947
948
PyDoc_STRVAR(tuple_class_getitem_doc,
949
"Tuples are generic over the types of their contents.\n\n\
950
For example, use ``tuple[int, str]`` for a pair whose first element\n\
951
is an int and second element is a string.\n\n\
952
Tuples also support the form ``tuple[T, ...]`` to indicate\n\
953
an arbitrary length tuple of elements of type T.");
954
955
static PyMethodDef tuple_methods[] = {
956
    TUPLE___GETNEWARGS___METHODDEF
957
    TUPLE_INDEX_METHODDEF
958
    TUPLE_COUNT_METHODDEF
959
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, tuple_class_getitem_doc},
960
    {NULL,              NULL}           /* sentinel */
961
};
962
963
static PyMappingMethods tuple_as_mapping = {
964
    tuple_length,
965
    tuple_subscript,
966
    0
967
};
968
969
static PyObject *tuple_iter(PyObject *seq);
970
971
PyTypeObject PyTuple_Type = {
972
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
973
    "tuple",
974
    sizeof(PyTupleObject) - sizeof(PyObject *),
975
    sizeof(PyObject *),
976
    tuple_dealloc,                              /* tp_dealloc */
977
    0,                                          /* tp_vectorcall_offset */
978
    0,                                          /* tp_getattr */
979
    0,                                          /* tp_setattr */
980
    0,                                          /* tp_as_async */
981
    tuple_repr,                                 /* tp_repr */
982
    0,                                          /* tp_as_number */
983
    &tuple_as_sequence,                         /* tp_as_sequence */
984
    &tuple_as_mapping,                          /* tp_as_mapping */
985
    tuple_hash,                                 /* tp_hash */
986
    0,                                          /* tp_call */
987
    0,                                          /* tp_str */
988
    PyObject_GenericGetAttr,                    /* tp_getattro */
989
    0,                                          /* tp_setattro */
990
    0,                                          /* tp_as_buffer */
991
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
992
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS |
993
        _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE,  /* tp_flags */
994
    tuple_new__doc__,                           /* tp_doc */
995
    tuple_traverse,                             /* tp_traverse */
996
    0,                                          /* tp_clear */
997
    tuple_richcompare,                          /* tp_richcompare */
998
    0,                                          /* tp_weaklistoffset */
999
    tuple_iter,                                 /* tp_iter */
1000
    0,                                          /* tp_iternext */
1001
    tuple_methods,                              /* tp_methods */
1002
    0,                                          /* tp_members */
1003
    0,                                          /* tp_getset */
1004
    0,                                          /* tp_base */
1005
    0,                                          /* tp_dict */
1006
    0,                                          /* tp_descr_get */
1007
    0,                                          /* tp_descr_set */
1008
    0,                                          /* tp_dictoffset */
1009
    0,                                          /* tp_init */
1010
    0,                                          /* tp_alloc */
1011
    tuple_new,                                  /* tp_new */
1012
    PyObject_GC_Del,                            /* tp_free */
1013
    .tp_vectorcall = tuple_vectorcall,
1014
    .tp_version_tag = _Py_TYPE_VERSION_TUPLE,
1015
    ._tp_iteritem = tuple_iteritem,
1016
};
1017
1018
/* The following function breaks the notion that tuples are immutable:
1019
   it changes the size of a tuple.  We get away with this only if there
1020
   is only one module referencing the object.  You can also think of it
1021
   as creating a new tuple object and destroying the old one, only more
1022
   efficiently.  In any case, don't use this if the tuple may already be
1023
   known to some other part of the code. */
1024
1025
int
1026
_PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
1027
798
{
1028
798
    PyTupleObject *v;
1029
798
    PyTupleObject *sv;
1030
798
    Py_ssize_t i;
1031
798
    Py_ssize_t oldsize;
1032
1033
798
    v = (PyTupleObject *) *pv;
1034
798
    if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) || newsize < 0 ||
1035
798
        (Py_SIZE(v) != 0 && !_PyObject_IsUniquelyReferenced(*pv))) {
1036
0
        *pv = 0;
1037
0
        Py_XDECREF(v);
1038
0
        PyErr_BadInternalCall();
1039
0
        return -1;
1040
0
    }
1041
1042
798
    oldsize = Py_SIZE(v);
1043
798
    if (oldsize == newsize) {
1044
681
        return 0;
1045
681
    }
1046
117
    if (newsize == 0) {
1047
76
        Py_DECREF(v);
1048
76
        *pv = tuple_get_empty();
1049
76
        return 0;
1050
76
    }
1051
41
    if (oldsize == 0) {
1052
#ifdef Py_DEBUG
1053
        assert(v == &_Py_SINGLETON(tuple_empty));
1054
#endif
1055
        /* The empty tuple is statically allocated so we never
1056
           resize it in-place. */
1057
0
        Py_DECREF(v);
1058
0
        *pv = PyTuple_New(newsize);
1059
0
        return *pv == NULL ? -1 : 0;
1060
0
    }
1061
    /* Check for overflow */
1062
41
    if ((size_t)newsize > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
1063
41
                sizeof(PyObject *))) / sizeof(PyObject *)) {
1064
0
        *pv = NULL;
1065
0
        Py_DECREF(v);
1066
0
        PyErr_NoMemory();
1067
0
        return -1;
1068
0
    }
1069
1070
41
    if (_PyObject_GC_IS_TRACKED(v)) {
1071
41
        _PyObject_GC_UNTRACK(v);
1072
41
    }
1073
#ifdef Py_TRACE_REFS
1074
    _Py_ForgetReference((PyObject *) v);
1075
#endif
1076
    /* DECREF items deleted by shrinkage */
1077
156
    for (i = newsize; i < oldsize; i++) {
1078
115
        Py_CLEAR(v->ob_item[i]);
1079
115
    }
1080
41
    _PyReftracerTrack((PyObject *)v, PyRefTracer_DESTROY);
1081
41
    sv = PyObject_GC_Resize(PyTupleObject, v, newsize);
1082
41
    if (sv == NULL) {
1083
0
        *pv = NULL;
1084
#ifdef Py_REF_DEBUG
1085
        _Py_DecRefTotal(_PyThreadState_GET());
1086
#endif
1087
        /* The failed reallocation leaves the original items owned by v. */
1088
0
        i = oldsize;
1089
0
        while (--i >= 0) {
1090
0
            Py_XDECREF(v->ob_item[i]);
1091
0
        }
1092
0
        PyObject_GC_Del(v);
1093
0
        return -1;
1094
0
    }
1095
41
    _Py_NewReferenceNoTotal((PyObject *) sv);
1096
    /* Zero out items added by growing */
1097
41
    if (newsize > oldsize)
1098
0
        memset(&sv->ob_item[oldsize], 0,
1099
0
               sizeof(*sv->ob_item) * (newsize - oldsize));
1100
41
    *pv = (PyObject *) sv;
1101
41
    _PyObject_GC_TRACK(sv);
1102
41
    return 0;
1103
41
}
1104
1105
/*********************** Tuple Iterator **************************/
1106
1107
1.35G
#define _PyTupleIterObject_CAST(op) ((_PyTupleIterObject *)(op))
1108
1109
static void
1110
tupleiter_dealloc(PyObject *self)
1111
7.96M
{
1112
7.96M
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1113
7.96M
    _PyObject_GC_UNTRACK(it);
1114
7.96M
    Py_XDECREF(it->it_seq);
1115
7.96M
    assert(Py_IS_TYPE(self, &PyTupleIter_Type));
1116
7.96M
    _Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del);
1117
7.96M
}
1118
1119
static int
1120
tupleiter_traverse(PyObject *self, visitproc visit, void *arg)
1121
8.75M
{
1122
8.75M
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1123
8.75M
    Py_VISIT(it->it_seq);
1124
8.75M
    return 0;
1125
8.75M
}
1126
1127
static PyObject *
1128
tupleiter_next(PyObject *self)
1129
1.34G
{
1130
1.34G
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1131
1.34G
    PyTupleObject *seq;
1132
1.34G
    PyObject *item;
1133
1134
1.34G
    assert(it != NULL);
1135
1.34G
    seq = it->it_seq;
1136
1.34G
#ifndef Py_GIL_DISABLED
1137
1.34G
    if (seq == NULL)
1138
0
        return NULL;
1139
1.34G
#endif
1140
1.34G
    assert(PyTuple_Check(seq));
1141
1142
1.34G
    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1143
1.34G
    if (index < PyTuple_GET_SIZE(seq)) {
1144
1.33G
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index + 1);
1145
1.33G
        item = PyTuple_GET_ITEM(seq, index);
1146
1.33G
        return Py_NewRef(item);
1147
1.33G
    }
1148
1149
3.48M
#ifndef Py_GIL_DISABLED
1150
3.48M
    it->it_seq = NULL;
1151
3.48M
    Py_DECREF(seq);
1152
3.48M
#endif
1153
3.48M
    return NULL;
1154
1.34G
}
1155
1156
static PyObject *
1157
tupleiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
1158
0
{
1159
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1160
0
    Py_ssize_t len = 0;
1161
#ifdef Py_GIL_DISABLED
1162
    Py_ssize_t idx = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1163
    Py_ssize_t seq_len = PyTuple_GET_SIZE(it->it_seq);
1164
    if (idx < seq_len)
1165
        len = seq_len - idx;
1166
#else
1167
0
    if (it->it_seq)
1168
0
        len = PyTuple_GET_SIZE(it->it_seq) - it->it_index;
1169
0
#endif
1170
0
    return PyLong_FromSsize_t(len);
1171
0
}
1172
1173
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
1174
1175
static PyObject *
1176
tupleiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
1177
0
{
1178
0
    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
1179
1180
    /* _PyEval_GetBuiltin can invoke arbitrary code,
1181
     * call must be before access of iterator pointers.
1182
     * see issue #101765 */
1183
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1184
1185
#ifdef Py_GIL_DISABLED
1186
    Py_ssize_t idx = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1187
    if (idx < PyTuple_GET_SIZE(it->it_seq))
1188
        return Py_BuildValue("N(O)n", iter, it->it_seq, idx);
1189
#else
1190
0
    if (it->it_seq)
1191
0
        return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
1192
0
#endif
1193
0
    return Py_BuildValue("N(())", iter);
1194
0
}
1195
1196
static PyObject *
1197
tupleiter_setstate(PyObject *self, PyObject *state)
1198
0
{
1199
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1200
0
    Py_ssize_t index = PyLong_AsSsize_t(state);
1201
0
    if (index == -1 && PyErr_Occurred())
1202
0
        return NULL;
1203
0
    if (it->it_seq != NULL) {
1204
0
        if (index < 0)
1205
0
            index = 0;
1206
0
        else if (index > PyTuple_GET_SIZE(it->it_seq))
1207
0
            index = PyTuple_GET_SIZE(it->it_seq); /* exhausted iterator */
1208
0
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index);
1209
0
    }
1210
0
    Py_RETURN_NONE;
1211
0
}
1212
1213
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
1214
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
1215
1216
static PyMethodDef tupleiter_methods[] = {
1217
    {"__length_hint__", tupleiter_len, METH_NOARGS, length_hint_doc},
1218
    {"__reduce__", tupleiter_reduce, METH_NOARGS, reduce_doc},
1219
    {"__setstate__", tupleiter_setstate, METH_O, setstate_doc},
1220
    {NULL, NULL, 0, NULL} /* sentinel */
1221
};
1222
1223
PyTypeObject PyTupleIter_Type = {
1224
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
1225
    "tuple_iterator",                           /* tp_name */
1226
    sizeof(_PyTupleIterObject),                 /* tp_basicsize */
1227
    0,                                          /* tp_itemsize */
1228
    /* methods */
1229
    tupleiter_dealloc,                          /* tp_dealloc */
1230
    0,                                          /* tp_vectorcall_offset */
1231
    0,                                          /* tp_getattr */
1232
    0,                                          /* tp_setattr */
1233
    0,                                          /* tp_as_async */
1234
    0,                                          /* tp_repr */
1235
    0,                                          /* tp_as_number */
1236
    0,                                          /* tp_as_sequence */
1237
    0,                                          /* tp_as_mapping */
1238
    0,                                          /* tp_hash */
1239
    0,                                          /* tp_call */
1240
    0,                                          /* tp_str */
1241
    PyObject_GenericGetAttr,                    /* tp_getattro */
1242
    0,                                          /* tp_setattro */
1243
    0,                                          /* tp_as_buffer */
1244
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
1245
    0,                                          /* tp_doc */
1246
    tupleiter_traverse,                         /* tp_traverse */
1247
    0,                                          /* tp_clear */
1248
    0,                                          /* tp_richcompare */
1249
    0,                                          /* tp_weaklistoffset */
1250
    PyObject_SelfIter,                          /* tp_iter */
1251
    tupleiter_next,                             /* tp_iternext */
1252
    tupleiter_methods,                          /* tp_methods */
1253
    0,
1254
};
1255
1256
static PyObject *
1257
tuple_iter(PyObject *seq)
1258
7.96M
{
1259
7.96M
    if (!PyTuple_Check(seq)) {
1260
0
        PyErr_BadInternalCall();
1261
0
        return NULL;
1262
0
    }
1263
7.96M
    _PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters);
1264
7.96M
    if (it == NULL) {
1265
4.46M
        it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
1266
4.46M
        if (it == NULL)
1267
0
            return NULL;
1268
4.46M
    }
1269
7.96M
    it->it_index = 0;
1270
7.96M
    it->it_seq = (PyTupleObject *)Py_NewRef(seq);
1271
7.96M
    _PyObject_GC_TRACK(it);
1272
7.96M
    return (PyObject *)it;
1273
7.96M
}
1274
1275
1276
/*************
1277
 * freelists *
1278
 *************/
1279
1280
static inline int
1281
maybe_freelist_push(PyTupleObject *op)
1282
474M
{
1283
474M
    if (!Py_IS_TYPE(op, &PyTuple_Type)) {
1284
582k
        return 0;
1285
582k
    }
1286
474M
    Py_ssize_t index = Py_SIZE(op) - 1;
1287
474M
    if (index < PyTuple_MAXSAVESIZE) {
1288
463M
        return _Py_FREELIST_PUSH(tuples[index], op, Py_tuple_MAXFREELIST);
1289
463M
    }
1290
10.4M
    return 0;
1291
474M
}
1292
1293
/* Print summary info about the state of the optimized allocator */
1294
void
1295
_PyTuple_DebugMallocStats(FILE *out)
1296
0
{
1297
0
    for (int i = 0; i < PyTuple_MAXSAVESIZE; i++) {
1298
0
        int len = i + 1;
1299
0
        char buf[128];
1300
0
        PyOS_snprintf(buf, sizeof(buf),
1301
0
                      "free %d-sized PyTupleObject", len);
1302
0
        _PyDebugAllocatorStats(out, buf, _Py_FREELIST_SIZE(tuples[i]),
1303
0
                               _PyType_PreHeaderSize(&PyTuple_Type) + _PyObject_VAR_SIZE(&PyTuple_Type, len));
1304
0
    }
1305
0
}