Coverage Report

Created: 2026-07-16 07:04

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