Coverage Report

Created: 2026-06-09 06:53

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
414M
{
39
414M
    if (size < 0) {
40
0
        PyErr_BadInternalCall();
41
0
        return NULL;
42
0
    }
43
414M
    assert(size != 0);    // The empty tuple is statically allocated.
44
414M
    Py_ssize_t index = size - 1;
45
414M
    if (index < PyTuple_MAXSAVESIZE) {
46
408M
        PyTupleObject *op = _Py_FREELIST_POP(PyTupleObject, tuples[index]);
47
408M
        if (op != NULL) {
48
321M
            _PyTuple_RESET_HASH_CACHE(op);
49
321M
            return op;
50
321M
        }
51
408M
    }
52
    /* Check for overflow */
53
92.3M
    if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
54
92.3M
                sizeof(PyObject *))) / sizeof(PyObject *)) {
55
0
        return (PyTupleObject *)PyErr_NoMemory();
56
0
    }
57
92.3M
    PyTupleObject *result = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
58
92.3M
    if (result != NULL) {
59
92.3M
        _PyTuple_RESET_HASH_CACHE(result);
60
92.3M
    }
61
92.3M
    return result;
62
92.3M
}
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
82.8M
{
71
82.8M
    return (PyObject *)&_Py_SINGLETON(tuple_empty);
72
82.8M
}
73
74
PyObject *
75
PyTuple_New(Py_ssize_t size)
76
64.1M
{
77
64.1M
    PyTupleObject *op;
78
64.1M
    if (size == 0) {
79
3.08M
        return tuple_get_empty();
80
3.08M
    }
81
61.0M
    op = tuple_alloc(size);
82
61.0M
    if (op == NULL) {
83
0
        return NULL;
84
0
    }
85
1.89G
    for (Py_ssize_t i = 0; i < size; i++) {
86
1.83G
        op->ob_item[i] = NULL;
87
1.83G
    }
88
61.0M
    _PyObject_GC_TRACK(op);
89
61.0M
    return (PyObject *) op;
90
61.0M
}
91
92
Py_ssize_t
93
PyTuple_Size(PyObject *op)
94
7.87M
{
95
7.87M
    if (!PyTuple_Check(op)) {
96
0
        PyErr_BadInternalCall();
97
0
        return -1;
98
0
    }
99
7.87M
    else
100
7.87M
        return Py_SIZE(op);
101
7.87M
}
102
103
PyObject *
104
PyTuple_GetItem(PyObject *op, Py_ssize_t i)
105
19.1M
{
106
19.1M
    if (!PyTuple_Check(op)) {
107
0
        PyErr_BadInternalCall();
108
0
        return NULL;
109
0
    }
110
19.1M
    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
19.1M
    return ((PyTupleObject *)op) -> ob_item[i];
115
19.1M
}
116
117
int
118
PyTuple_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem)
119
138k
{
120
138k
    PyObject **p;
121
138k
    if (!PyTuple_Check(op) || !_PyObject_IsUniquelyReferenced(op)) {
122
0
        Py_XDECREF(newitem);
123
0
        PyErr_BadInternalCall();
124
0
        return -1;
125
0
    }
126
138k
    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
138k
    p = ((PyTupleObject *)op) -> ob_item + i;
133
138k
    Py_XSETREF(*p, newitem);
134
138k
    return 0;
135
138k
}
136
137
void
138
_PyTuple_MaybeUntrack(PyObject *op)
139
174M
{
140
174M
    PyTupleObject *t;
141
174M
    Py_ssize_t i, n;
142
143
174M
    if (!PyTuple_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
144
0
        return;
145
174M
    t = (PyTupleObject *) op;
146
174M
    n = Py_SIZE(t);
147
226M
    for (i = 0; i < n; i++) {
148
219M
        PyObject *elt = PyTuple_GET_ITEM(t, i);
149
        /* Tuple with NULL elements aren't
150
           fully constructed, don't untrack
151
           them yet. */
152
219M
        if (!elt ||
153
219M
            _PyObject_GC_MAY_BE_TRACKED(elt))
154
167M
            return;
155
219M
    }
156
7.02M
    _PyObject_GC_UNTRACK(op);
157
7.02M
}
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
636M
{
168
636M
    return _PyType_IS_GC(Py_TYPE(ob));
169
636M
}
170
171
PyObject *
172
PyTuple_Pack(Py_ssize_t n, ...)
173
1.38M
{
174
1.38M
    Py_ssize_t i;
175
1.38M
    PyObject *o;
176
1.38M
    PyObject **items;
177
1.38M
    va_list vargs;
178
1.38M
    bool track = false;
179
180
1.38M
    if (n == 0) {
181
0
        return tuple_get_empty();
182
0
    }
183
184
1.38M
    va_start(vargs, n);
185
1.38M
    PyTupleObject *result = tuple_alloc(n);
186
1.38M
    if (result == NULL) {
187
0
        va_end(vargs);
188
0
        return NULL;
189
0
    }
190
1.38M
    items = result->ob_item;
191
5.29M
    for (i = 0; i < n; i++) {
192
3.90M
        o = va_arg(vargs, PyObject *);
193
3.90M
        if (!track && maybe_tracked(o)) {
194
1.10M
            track = true;
195
1.10M
        }
196
3.90M
        items[i] = Py_NewRef(o);
197
3.90M
    }
198
1.38M
    va_end(vargs);
199
1.38M
    if (track) {
200
1.10M
        _PyObject_GC_TRACK(result);
201
1.10M
    }
202
1.38M
    return (PyObject *)result;
203
1.38M
}
204
205
PyObject *
206
_PyTuple_FromPair(PyObject *first, PyObject *second)
207
140k
{
208
140k
    assert(first != NULL);
209
140k
    assert(second != NULL);
210
211
140k
    return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
212
140k
}
213
214
PyObject *
215
_PyTuple_FromPairSteal(PyObject *first, PyObject *second)
216
14.4M
{
217
14.4M
    assert(first != NULL);
218
14.4M
    assert(second != NULL);
219
220
14.4M
    PyTupleObject *op = tuple_alloc(2);
221
14.4M
    if (op == NULL) {
222
0
        Py_DECREF(first);
223
0
        Py_DECREF(second);
224
0
        return NULL;
225
0
    }
226
14.4M
    PyObject **items = op->ob_item;
227
14.4M
    items[0] = first;
228
14.4M
    items[1] = second;
229
14.4M
    if (maybe_tracked(first) || maybe_tracked(second)) {
230
162k
        _PyObject_GC_TRACK(op);
231
162k
    }
232
14.4M
    return (PyObject *)op;
233
14.4M
}
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
414M
{
257
414M
    PyTupleObject *op = _PyTuple_CAST(self);
258
414M
    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
414M
    PyObject_GC_UnTrack(op);
274
275
414M
    Py_ssize_t i = Py_SIZE(op);
276
3.27G
    while (--i >= 0) {
277
2.86G
        Py_XDECREF(op->ob_item[i]);
278
2.86G
    }
279
    // This will abort on the empty singleton (if there is one).
280
414M
    if (!maybe_freelist_push(op)) {
281
91.6M
        Py_TYPE(op)->tp_free((PyObject *)op);
282
91.6M
    }
283
414M
}
284
285
static PyObject *
286
tuple_repr(PyObject *self)
287
82.3k
{
288
82.3k
    PyTupleObject *v = _PyTuple_CAST(self);
289
82.3k
    Py_ssize_t n = PyTuple_GET_SIZE(v);
290
82.3k
    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
82.3k
    int res = Py_ReprEnter((PyObject *)v);
299
82.3k
    if (res != 0) {
300
0
        return res > 0 ? PyUnicode_FromString("(...)") : NULL;
301
0
    }
302
303
82.3k
    Py_ssize_t prealloc;
304
82.3k
    if (n > 1) {
305
        // "(" + "1" + ", 2" * (len - 1) + ")"
306
41.5k
        prealloc = 1 + 1 + (2 + 1) * (n - 1) + 1;
307
41.5k
    }
308
40.8k
    else {
309
        // "(1,)"
310
40.8k
        prealloc = 4;
311
40.8k
    }
312
82.3k
    PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc);
313
82.3k
    if (writer == NULL) {
314
0
        goto error;
315
0
    }
316
317
82.3k
    if (PyUnicodeWriter_WriteChar(writer, '(') < 0) {
318
0
        goto error;
319
0
    }
320
321
    /* Do repr() on each element. */
322
223k
    for (Py_ssize_t i = 0; i < n; ++i) {
323
140k
        if (i > 0) {
324
58.6k
            if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
325
0
                goto error;
326
0
            }
327
58.6k
            if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) {
328
0
                goto error;
329
0
            }
330
58.6k
        }
331
332
140k
        if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) {
333
0
            goto error;
334
0
        }
335
140k
    }
336
337
82.3k
    if (n == 1) {
338
40.8k
        if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
339
0
            goto error;
340
0
        }
341
40.8k
    }
342
82.3k
    if (PyUnicodeWriter_WriteChar(writer, ')') < 0) {
343
0
        goto error;
344
0
    }
345
346
82.3k
    Py_ReprLeave((PyObject *)v);
347
82.3k
    return PyUnicodeWriter_Finish(writer);
348
349
0
error:
350
0
    PyUnicodeWriter_Discard(writer);
351
0
    Py_ReprLeave((PyObject *)v);
352
0
    return NULL;
353
82.3k
}
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
20.6M
{
374
20.6M
    PyTupleObject *v = _PyTuple_CAST(op);
375
376
20.6M
    Py_uhash_t acc = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->ob_hash);
377
20.6M
    if (acc != (Py_uhash_t)-1) {
378
4.65M
        return acc;
379
4.65M
    }
380
381
15.9M
    Py_ssize_t len = Py_SIZE(v);
382
15.9M
    PyObject **item = v->ob_item;
383
15.9M
    acc = _PyTuple_HASH_XXPRIME_5;
384
119M
    for (Py_ssize_t i = 0; i < len; i++) {
385
103M
        Py_uhash_t lane = PyObject_Hash(item[i]);
386
103M
        if (lane == (Py_uhash_t)-1) {
387
0
            return -1;
388
0
        }
389
103M
        acc += lane * _PyTuple_HASH_XXPRIME_2;
390
103M
        acc = _PyTuple_HASH_XXROTATE(acc);
391
103M
        acc *= _PyTuple_HASH_XXPRIME_1;
392
103M
    }
393
394
    /* Add input length, mangled to keep the historical value of hash(()). */
395
15.9M
    acc += len ^ (_PyTuple_HASH_XXPRIME_5 ^ 3527539UL);
396
397
15.9M
    if (acc == (Py_uhash_t)-1) {
398
0
        acc = 1546275796;
399
0
    }
400
401
15.9M
    FT_ATOMIC_STORE_SSIZE_RELAXED(v->ob_hash, acc);
402
403
15.9M
    return acc;
404
15.9M
}
405
406
static Py_ssize_t
407
tuple_length(PyObject *self)
408
11.9M
{
409
11.9M
    PyTupleObject *a = _PyTuple_CAST(self);
410
11.9M
    return Py_SIZE(a);
411
11.9M
}
412
413
static int
414
tuple_contains(PyObject *self, PyObject *el)
415
23.2M
{
416
23.2M
    PyTupleObject *a = _PyTuple_CAST(self);
417
23.2M
    int cmp = 0;
418
73.8M
    for (Py_ssize_t i = 0; cmp == 0 && i < Py_SIZE(a); ++i) {
419
50.5M
        cmp = PyObject_RichCompareBool(PyTuple_GET_ITEM(a, i), el, Py_EQ);
420
50.5M
    }
421
23.2M
    return cmp;
422
23.2M
}
423
424
static PyObject *
425
tuple_item(PyObject *op, Py_ssize_t i)
426
17.6M
{
427
17.6M
    PyTupleObject *a = _PyTuple_CAST(op);
428
17.6M
    if (i < 0 || i >= Py_SIZE(a)) {
429
108
        PyErr_SetString(PyExc_IndexError, "tuple index out of range");
430
108
        return NULL;
431
108
    }
432
17.6M
    return Py_NewRef(a->ob_item[i]);
433
17.6M
}
434
435
PyObject *
436
PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
437
229M
{
438
229M
    if (n == 0) {
439
79.7M
        return tuple_get_empty();
440
79.7M
    }
441
442
149M
    PyTupleObject *tuple = tuple_alloc(n);
443
149M
    if (tuple == NULL) {
444
0
        return NULL;
445
0
    }
446
149M
    PyObject **dst = tuple->ob_item;
447
149M
    bool track = false;
448
513M
    for (Py_ssize_t i = 0; i < n; i++) {
449
363M
        PyObject *item = src[i];
450
363M
        if (!track && maybe_tracked(item)) {
451
24.6M
            track = true;
452
24.6M
        }
453
363M
        dst[i] = Py_NewRef(item);
454
363M
    }
455
149M
    if (track) {
456
24.6M
        _PyObject_GC_TRACK(tuple);
457
24.6M
    }
458
149M
    return (PyObject *)tuple;
459
149M
}
460
461
PyObject *
462
_PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
463
171M
{
464
171M
    if (n == 0) {
465
0
        return tuple_get_empty();
466
0
    }
467
171M
    PyTupleObject *tuple = tuple_alloc(n);
468
171M
    if (tuple == NULL) {
469
0
        return NULL;
470
0
    }
471
171M
    PyObject **dst = tuple->ob_item;
472
171M
    bool track = false;
473
525M
    for (Py_ssize_t i = 0; i < n; i++) {
474
353M
        PyObject *item = PyStackRef_AsPyObjectSteal(src[i]);
475
353M
        if (!track && maybe_tracked(item)) {
476
108M
            track = true;
477
108M
        }
478
353M
        dst[i] = item;
479
353M
    }
480
171M
    if (track) {
481
108M
        _PyObject_GC_TRACK(tuple);
482
108M
    }
483
171M
    return (PyObject *)tuple;
484
171M
}
485
486
PyObject *
487
_PyTuple_FromArraySteal(PyObject *const *src, Py_ssize_t n)
488
9.94M
{
489
9.94M
    if (n == 0) {
490
52
        return tuple_get_empty();
491
52
    }
492
9.94M
    PyTupleObject *tuple = tuple_alloc(n);
493
9.94M
    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
9.94M
    PyObject **dst = tuple->ob_item;
500
33.4M
    for (Py_ssize_t i = 0; i < n; i++) {
501
23.5M
        PyObject *item = src[i];
502
23.5M
        dst[i] = item;
503
23.5M
    }
504
9.94M
    _PyObject_GC_TRACK(tuple);
505
9.94M
    return (PyObject *)tuple;
506
9.94M
}
507
508
static PyObject *
509
tuple_slice(PyTupleObject *a, Py_ssize_t ilow,
510
           Py_ssize_t ihigh)
511
14.4M
{
512
14.4M
    if (ilow < 0)
513
0
        ilow = 0;
514
14.4M
    if (ihigh > Py_SIZE(a))
515
192
        ihigh = Py_SIZE(a);
516
14.4M
    if (ihigh < ilow)
517
0
        ihigh = ilow;
518
14.4M
    if (ilow == 0 && ihigh == Py_SIZE(a) && PyTuple_CheckExact(a)) {
519
0
        return Py_NewRef(a);
520
0
    }
521
14.4M
    return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
522
14.4M
}
523
524
PyObject *
525
_PyTuple_BinarySlice(PyObject *container, PyObject *start, PyObject *stop)
526
1.39M
{
527
1.39M
    assert(PyTuple_CheckExact(container));
528
1.39M
    Py_ssize_t len = Py_SIZE(container);
529
1.39M
    Py_ssize_t istart, istop;
530
1.39M
    if (!_PyEval_UnpackIndices(start, stop, len, &istart, &istop)) {
531
0
        return NULL;
532
0
    }
533
1.39M
    if (istart == 0 && istop == len) {
534
23.2k
        return Py_NewRef(container);
535
23.2k
    }
536
1.37M
    if (istop < istart) {
537
0
        istop = istart;
538
0
    }
539
1.37M
    return PyTuple_FromArray(((PyTupleObject *)container)->ob_item + istart,
540
1.37M
                             istop - istart);
541
1.39M
}
542
543
PyObject *
544
PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j)
545
14.4M
{
546
14.4M
    if (op == NULL || !PyTuple_Check(op)) {
547
0
        PyErr_BadInternalCall();
548
0
        return NULL;
549
0
    }
550
14.4M
    return tuple_slice((PyTupleObject *)op, i, j);
551
14.4M
}
552
553
PyObject *
554
_PyTuple_Concat(PyObject *aa, PyObject *bb)
555
4.78M
{
556
4.78M
    PyTupleObject *a = _PyTuple_CAST(aa);
557
4.78M
    if (Py_SIZE(a) == 0 && PyTuple_CheckExact(bb)) {
558
183k
        return Py_NewRef(bb);
559
183k
    }
560
4.60M
    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
4.60M
    PyTupleObject *b = (PyTupleObject *)bb;
567
568
4.60M
    if (Py_SIZE(b) == 0 && PyTuple_CheckExact(a)) {
569
3.50k
        return Py_NewRef(a);
570
3.50k
    }
571
4.60M
    assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX);
572
4.59M
    Py_ssize_t size = Py_SIZE(a) + Py_SIZE(b);
573
4.59M
    if (size == 0) {
574
0
        return tuple_get_empty();
575
0
    }
576
577
4.59M
    PyTupleObject *np = tuple_alloc(size);
578
4.59M
    if (np == NULL) {
579
0
        return NULL;
580
0
    }
581
582
4.59M
    PyObject **src = a->ob_item;
583
4.59M
    PyObject **dest = np->ob_item;
584
220M
    for (Py_ssize_t i = 0; i < Py_SIZE(a); i++) {
585
215M
        PyObject *v = src[i];
586
215M
        dest[i] = Py_NewRef(v);
587
215M
    }
588
589
4.59M
    src = b->ob_item;
590
4.59M
    dest = np->ob_item + Py_SIZE(a);
591
33.1M
    for (Py_ssize_t i = 0; i < Py_SIZE(b); i++) {
592
28.5M
        PyObject *v = src[i];
593
28.5M
        dest[i] = Py_NewRef(v);
594
28.5M
    }
595
596
4.59M
    _PyObject_GC_TRACK(np);
597
4.59M
    return (PyObject *)np;
598
4.59M
}
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
756
{
667
756
    Py_ssize_t i;
668
669
756
    if (start < 0) {
670
0
        start += Py_SIZE(self);
671
0
        if (start < 0)
672
0
            start = 0;
673
0
    }
674
756
    if (stop < 0) {
675
0
        stop += Py_SIZE(self);
676
0
    }
677
756
    else if (stop > Py_SIZE(self)) {
678
756
        stop = Py_SIZE(self);
679
756
    }
680
976
    for (i = start; i < stop; i++) {
681
392
        int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
682
392
        if (cmp > 0)
683
172
            return PyLong_FromSsize_t(i);
684
220
        else if (cmp < 0)
685
0
            return NULL;
686
392
    }
687
584
    PyErr_SetString(PyExc_ValueError, "tuple.index(x): x not in tuple");
688
584
    return NULL;
689
756
}
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
352M
{
720
352M
    PyTupleObject *o = _PyTuple_CAST(self);
721
1.13G
    for (Py_ssize_t i = Py_SIZE(o); --i >= 0; ) {
722
785M
        Py_VISIT(o->ob_item[i]);
723
785M
    }
724
352M
    return 0;
725
352M
}
726
727
static PyObject *
728
tuple_richcompare(PyObject *v, PyObject *w, int op)
729
18.1M
{
730
18.1M
    PyTupleObject *vt, *wt;
731
18.1M
    Py_ssize_t i;
732
18.1M
    Py_ssize_t vlen, wlen;
733
734
18.1M
    if (!PyTuple_Check(v) || !PyTuple_Check(w))
735
8
        Py_RETURN_NOTIMPLEMENTED;
736
737
18.1M
    vt = (PyTupleObject *)v;
738
18.1M
    wt = (PyTupleObject *)w;
739
740
18.1M
    vlen = Py_SIZE(vt);
741
18.1M
    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
57.5M
    for (i = 0; i < vlen && i < wlen; i++) {
755
41.1M
        int k = PyObject_RichCompareBool(vt->ob_item[i],
756
41.1M
                                         wt->ob_item[i], Py_EQ);
757
41.1M
        if (k < 0)
758
0
            return NULL;
759
41.1M
        if (!k)
760
1.80M
            break;
761
41.1M
    }
762
763
18.1M
    if (i >= vlen || i >= wlen) {
764
        /* No more items to compare -- compare sizes */
765
16.3M
        Py_RETURN_RICHCOMPARE(vlen, wlen, op);
766
16.3M
    }
767
768
    /* We have an item that differs -- shortcuts for EQ/NE */
769
1.80M
    if (op == Py_EQ) {
770
446k
        Py_RETURN_FALSE;
771
446k
    }
772
1.35M
    if (op == Py_NE) {
773
236k
        Py_RETURN_TRUE;
774
236k
    }
775
776
    /* Compare the final item again using the proper operator */
777
1.11M
    return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op);
778
1.35M
}
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
1.24M
{
801
1.24M
    if (type != &PyTuple_Type)
802
622k
        return tuple_subtype_new(type, iterable);
803
804
623k
    if (iterable == NULL) {
805
0
        return tuple_get_empty();
806
0
    }
807
623k
    else {
808
623k
        return PySequence_Tuple(iterable);
809
623k
    }
810
623k
}
811
812
static PyObject *
813
tuple_vectorcall(PyObject *type, PyObject * const*args,
814
                 size_t nargsf, PyObject *kwnames)
815
203
{
816
203
    if (!_PyArg_NoKwnames("tuple", kwnames)) {
817
0
        return NULL;
818
0
    }
819
820
203
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
821
203
    if (!_PyArg_CheckPositional("tuple", nargs, 0, 1)) {
822
0
        return NULL;
823
0
    }
824
825
203
    if (nargs) {
826
203
        return tuple_new_impl(_PyType_CAST(type), args[0]);
827
203
    }
828
0
    else {
829
0
        return tuple_get_empty();
830
0
    }
831
203
}
832
833
static PyObject *
834
tuple_subtype_new(PyTypeObject *type, PyObject *iterable)
835
622k
{
836
622k
    PyObject *tmp, *newobj, *item;
837
622k
    Py_ssize_t i, n;
838
839
622k
    assert(PyType_IsSubtype(type, &PyTuple_Type));
840
    // tuple subclasses must implement the GC protocol
841
622k
    assert(_PyType_IS_GC(type));
842
843
622k
    tmp = tuple_new_impl(&PyTuple_Type, iterable);
844
622k
    if (tmp == NULL)
845
0
        return NULL;
846
622k
    assert(PyTuple_Check(tmp));
847
    /* This may allocate an empty tuple that is not the global one. */
848
622k
    newobj = type->tp_alloc(type, n = PyTuple_GET_SIZE(tmp));
849
622k
    if (newobj == NULL) {
850
0
        Py_DECREF(tmp);
851
0
        return NULL;
852
0
    }
853
2.33M
    for (i = 0; i < n; i++) {
854
1.71M
        item = PyTuple_GET_ITEM(tmp, i);
855
1.71M
        PyTuple_SET_ITEM(newobj, i, Py_NewRef(item));
856
1.71M
    }
857
622k
    Py_DECREF(tmp);
858
859
622k
    _PyTuple_RESET_HASH_CACHE(newobj);
860
861
    // Don't track if a subclass tp_alloc is PyType_GenericAlloc()
862
622k
    if (!_PyObject_GC_IS_TRACKED(newobj)) {
863
0
        _PyObject_GC_TRACK(newobj);
864
0
    }
865
622k
    return newobj;
866
622k
}
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
6.37k
{
882
6.37k
    if (index >= PyTuple_GET_SIZE(obj)) {
883
461
        return (_PyObjectIndexPair) { .object = NULL, .index = index };
884
461
    }
885
5.91k
    PyObject *result = PyTuple_GET_ITEM(obj, index);
886
5.91k
    Py_INCREF(result);
887
5.91k
    return (_PyObjectIndexPair) { .object = result, .index = index + 1 };
888
6.37k
}
889
890
static PyObject*
891
tuple_subscript(PyObject *op, PyObject* item)
892
2.47M
{
893
2.47M
    PyTupleObject *self = _PyTuple_CAST(op);
894
2.47M
    if (_PyIndex_Check(item)) {
895
1.05M
        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
896
1.05M
        if (i == -1 && PyErr_Occurred())
897
0
            return NULL;
898
1.05M
        if (i < 0)
899
1.04M
            i += PyTuple_GET_SIZE(self);
900
1.05M
        return tuple_item(op, i);
901
1.05M
    }
902
1.42M
    else if (PySlice_Check(item)) {
903
1.42M
        Py_ssize_t start, stop, step, slicelength, i;
904
1.42M
        size_t cur;
905
1.42M
        PyObject* it;
906
1.42M
        PyObject **src, **dest;
907
908
1.42M
        if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
909
0
            return NULL;
910
0
        }
911
1.42M
        slicelength = PySlice_AdjustIndices(PyTuple_GET_SIZE(self), &start,
912
1.42M
                                            &stop, step);
913
914
1.42M
        if (slicelength <= 0) {
915
22.3k
            return tuple_get_empty();
916
22.3k
        }
917
1.40M
        else if (start == 0 && step == 1 &&
918
11.8k
                 slicelength == PyTuple_GET_SIZE(self) &&
919
0
                 PyTuple_CheckExact(self)) {
920
0
            return Py_NewRef(self);
921
0
        }
922
1.40M
        else {
923
1.40M
            PyTupleObject* result = tuple_alloc(slicelength);
924
1.40M
            if (!result) return NULL;
925
926
1.40M
            src = self->ob_item;
927
1.40M
            dest = result->ob_item;
928
11.1M
            for (cur = start, i = 0; i < slicelength;
929
9.78M
                 cur += step, i++) {
930
9.78M
                it = Py_NewRef(src[cur]);
931
9.78M
                dest[i] = it;
932
9.78M
            }
933
934
1.40M
            _PyObject_GC_TRACK(result);
935
1.40M
            return (PyObject *)result;
936
1.40M
        }
937
1.42M
    }
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
2.47M
}
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 is an int and second element is a string.\n\n\
961
Tuples also support the form ``tuple[T, ...]`` to indicate an arbitrary length tuple of elements of type T.");
962
963
static PyMethodDef tuple_methods[] = {
964
    TUPLE___GETNEWARGS___METHODDEF
965
    TUPLE_INDEX_METHODDEF
966
    TUPLE_COUNT_METHODDEF
967
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, tuple_class_getitem_doc},
968
    {NULL,              NULL}           /* sentinel */
969
};
970
971
static PyMappingMethods tuple_as_mapping = {
972
    tuple_length,
973
    tuple_subscript,
974
    0
975
};
976
977
static PyObject *tuple_iter(PyObject *seq);
978
979
PyTypeObject PyTuple_Type = {
980
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
981
    "tuple",
982
    sizeof(PyTupleObject) - sizeof(PyObject *),
983
    sizeof(PyObject *),
984
    tuple_dealloc,                              /* tp_dealloc */
985
    0,                                          /* tp_vectorcall_offset */
986
    0,                                          /* tp_getattr */
987
    0,                                          /* tp_setattr */
988
    0,                                          /* tp_as_async */
989
    tuple_repr,                                 /* tp_repr */
990
    0,                                          /* tp_as_number */
991
    &tuple_as_sequence,                         /* tp_as_sequence */
992
    &tuple_as_mapping,                          /* tp_as_mapping */
993
    tuple_hash,                                 /* tp_hash */
994
    0,                                          /* tp_call */
995
    0,                                          /* tp_str */
996
    PyObject_GenericGetAttr,                    /* tp_getattro */
997
    0,                                          /* tp_setattro */
998
    0,                                          /* tp_as_buffer */
999
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1000
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS |
1001
        _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE,  /* tp_flags */
1002
    tuple_new__doc__,                           /* tp_doc */
1003
    tuple_traverse,                             /* tp_traverse */
1004
    0,                                          /* tp_clear */
1005
    tuple_richcompare,                          /* tp_richcompare */
1006
    0,                                          /* tp_weaklistoffset */
1007
    tuple_iter,                                 /* tp_iter */
1008
    0,                                          /* tp_iternext */
1009
    tuple_methods,                              /* tp_methods */
1010
    0,                                          /* tp_members */
1011
    0,                                          /* tp_getset */
1012
    0,                                          /* tp_base */
1013
    0,                                          /* tp_dict */
1014
    0,                                          /* tp_descr_get */
1015
    0,                                          /* tp_descr_set */
1016
    0,                                          /* tp_dictoffset */
1017
    0,                                          /* tp_init */
1018
    0,                                          /* tp_alloc */
1019
    tuple_new,                                  /* tp_new */
1020
    PyObject_GC_Del,                            /* tp_free */
1021
    .tp_vectorcall = tuple_vectorcall,
1022
    .tp_version_tag = _Py_TYPE_VERSION_TUPLE,
1023
    ._tp_iteritem = tuple_iteritem,
1024
};
1025
1026
/* The following function breaks the notion that tuples are immutable:
1027
   it changes the size of a tuple.  We get away with this only if there
1028
   is only one module referencing the object.  You can also think of it
1029
   as creating a new tuple object and destroying the old one, only more
1030
   efficiently.  In any case, don't use this if the tuple may already be
1031
   known to some other part of the code. */
1032
1033
int
1034
_PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
1035
744
{
1036
744
    PyTupleObject *v;
1037
744
    PyTupleObject *sv;
1038
744
    Py_ssize_t i;
1039
744
    Py_ssize_t oldsize;
1040
1041
744
    v = (PyTupleObject *) *pv;
1042
744
    if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) ||
1043
744
        (Py_SIZE(v) != 0 && !_PyObject_IsUniquelyReferenced(*pv))) {
1044
0
        *pv = 0;
1045
0
        Py_XDECREF(v);
1046
0
        PyErr_BadInternalCall();
1047
0
        return -1;
1048
0
    }
1049
1050
744
    oldsize = Py_SIZE(v);
1051
744
    if (oldsize == newsize) {
1052
628
        return 0;
1053
628
    }
1054
116
    if (newsize == 0) {
1055
76
        Py_DECREF(v);
1056
76
        *pv = tuple_get_empty();
1057
76
        return 0;
1058
76
    }
1059
40
    if (oldsize == 0) {
1060
#ifdef Py_DEBUG
1061
        assert(v == &_Py_SINGLETON(tuple_empty));
1062
#endif
1063
        /* The empty tuple is statically allocated so we never
1064
           resize it in-place. */
1065
0
        Py_DECREF(v);
1066
0
        *pv = PyTuple_New(newsize);
1067
0
        return *pv == NULL ? -1 : 0;
1068
0
    }
1069
1070
40
    if (_PyObject_GC_IS_TRACKED(v)) {
1071
40
        _PyObject_GC_UNTRACK(v);
1072
40
    }
1073
#ifdef Py_TRACE_REFS
1074
    _Py_ForgetReference((PyObject *) v);
1075
#endif
1076
    /* DECREF items deleted by shrinkage */
1077
152
    for (i = newsize; i < oldsize; i++) {
1078
112
        Py_CLEAR(v->ob_item[i]);
1079
112
    }
1080
40
    _PyReftracerTrack((PyObject *)v, PyRefTracer_DESTROY);
1081
40
    sv = PyObject_GC_Resize(PyTupleObject, v, newsize);
1082
40
    if (sv == NULL) {
1083
0
        *pv = NULL;
1084
#ifdef Py_REF_DEBUG
1085
        _Py_DecRefTotal(_PyThreadState_GET());
1086
#endif
1087
0
        PyObject_GC_Del(v);
1088
0
        return -1;
1089
0
    }
1090
40
    _Py_NewReferenceNoTotal((PyObject *) sv);
1091
    /* Zero out items added by growing */
1092
40
    if (newsize > oldsize)
1093
0
        memset(&sv->ob_item[oldsize], 0,
1094
0
               sizeof(*sv->ob_item) * (newsize - oldsize));
1095
40
    *pv = (PyObject *) sv;
1096
40
    _PyObject_GC_TRACK(sv);
1097
40
    return 0;
1098
40
}
1099
1100
/*********************** Tuple Iterator **************************/
1101
1102
1.69G
#define _PyTupleIterObject_CAST(op) ((_PyTupleIterObject *)(op))
1103
1104
static void
1105
tupleiter_dealloc(PyObject *self)
1106
4.63M
{
1107
4.63M
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1108
4.63M
    _PyObject_GC_UNTRACK(it);
1109
4.63M
    Py_XDECREF(it->it_seq);
1110
4.63M
    assert(Py_IS_TYPE(self, &PyTupleIter_Type));
1111
4.63M
    _Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del);
1112
4.63M
}
1113
1114
static int
1115
tupleiter_traverse(PyObject *self, visitproc visit, void *arg)
1116
816k
{
1117
816k
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1118
816k
    Py_VISIT(it->it_seq);
1119
816k
    return 0;
1120
816k
}
1121
1122
static PyObject *
1123
tupleiter_next(PyObject *self)
1124
1.69G
{
1125
1.69G
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1126
1.69G
    PyTupleObject *seq;
1127
1.69G
    PyObject *item;
1128
1129
1.69G
    assert(it != NULL);
1130
1.69G
    seq = it->it_seq;
1131
1.69G
#ifndef Py_GIL_DISABLED
1132
1.69G
    if (seq == NULL)
1133
0
        return NULL;
1134
1.69G
#endif
1135
1.69G
    assert(PyTuple_Check(seq));
1136
1137
1.69G
    Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1138
1.69G
    if (index < PyTuple_GET_SIZE(seq)) {
1139
1.68G
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index + 1);
1140
1.68G
        item = PyTuple_GET_ITEM(seq, index);
1141
1.68G
        return Py_NewRef(item);
1142
1.68G
    }
1143
1144
4.14M
#ifndef Py_GIL_DISABLED
1145
4.14M
    it->it_seq = NULL;
1146
4.14M
    Py_DECREF(seq);
1147
4.14M
#endif
1148
4.14M
    return NULL;
1149
1.69G
}
1150
1151
static PyObject *
1152
tupleiter_len(PyObject *self, PyObject *Py_UNUSED(ignored))
1153
0
{
1154
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1155
0
    Py_ssize_t len = 0;
1156
#ifdef Py_GIL_DISABLED
1157
    Py_ssize_t idx = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1158
    Py_ssize_t seq_len = PyTuple_GET_SIZE(it->it_seq);
1159
    if (idx < seq_len)
1160
        len = seq_len - idx;
1161
#else
1162
0
    if (it->it_seq)
1163
0
        len = PyTuple_GET_SIZE(it->it_seq) - it->it_index;
1164
0
#endif
1165
0
    return PyLong_FromSsize_t(len);
1166
0
}
1167
1168
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
1169
1170
static PyObject *
1171
tupleiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
1172
0
{
1173
0
    PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
1174
1175
    /* _PyEval_GetBuiltin can invoke arbitrary code,
1176
     * call must be before access of iterator pointers.
1177
     * see issue #101765 */
1178
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1179
1180
#ifdef Py_GIL_DISABLED
1181
    Py_ssize_t idx = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->it_index);
1182
    if (idx < PyTuple_GET_SIZE(it->it_seq))
1183
        return Py_BuildValue("N(O)n", iter, it->it_seq, idx);
1184
#else
1185
0
    if (it->it_seq)
1186
0
        return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
1187
0
#endif
1188
0
    return Py_BuildValue("N(())", iter);
1189
0
}
1190
1191
static PyObject *
1192
tupleiter_setstate(PyObject *self, PyObject *state)
1193
0
{
1194
0
    _PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
1195
0
    Py_ssize_t index = PyLong_AsSsize_t(state);
1196
0
    if (index == -1 && PyErr_Occurred())
1197
0
        return NULL;
1198
0
    if (it->it_seq != NULL) {
1199
0
        if (index < 0)
1200
0
            index = 0;
1201
0
        else if (index > PyTuple_GET_SIZE(it->it_seq))
1202
0
            index = PyTuple_GET_SIZE(it->it_seq); /* exhausted iterator */
1203
0
        FT_ATOMIC_STORE_SSIZE_RELAXED(it->it_index, index);
1204
0
    }
1205
0
    Py_RETURN_NONE;
1206
0
}
1207
1208
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
1209
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
1210
1211
static PyMethodDef tupleiter_methods[] = {
1212
    {"__length_hint__", tupleiter_len, METH_NOARGS, length_hint_doc},
1213
    {"__reduce__", tupleiter_reduce, METH_NOARGS, reduce_doc},
1214
    {"__setstate__", tupleiter_setstate, METH_O, setstate_doc},
1215
    {NULL, NULL, 0, NULL} /* sentinel */
1216
};
1217
1218
PyTypeObject PyTupleIter_Type = {
1219
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
1220
    "tuple_iterator",                           /* tp_name */
1221
    sizeof(_PyTupleIterObject),                 /* tp_basicsize */
1222
    0,                                          /* tp_itemsize */
1223
    /* methods */
1224
    tupleiter_dealloc,                          /* tp_dealloc */
1225
    0,                                          /* tp_vectorcall_offset */
1226
    0,                                          /* tp_getattr */
1227
    0,                                          /* tp_setattr */
1228
    0,                                          /* tp_as_async */
1229
    0,                                          /* tp_repr */
1230
    0,                                          /* tp_as_number */
1231
    0,                                          /* tp_as_sequence */
1232
    0,                                          /* tp_as_mapping */
1233
    0,                                          /* tp_hash */
1234
    0,                                          /* tp_call */
1235
    0,                                          /* tp_str */
1236
    PyObject_GenericGetAttr,                    /* tp_getattro */
1237
    0,                                          /* tp_setattro */
1238
    0,                                          /* tp_as_buffer */
1239
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
1240
    0,                                          /* tp_doc */
1241
    tupleiter_traverse,                         /* tp_traverse */
1242
    0,                                          /* tp_clear */
1243
    0,                                          /* tp_richcompare */
1244
    0,                                          /* tp_weaklistoffset */
1245
    PyObject_SelfIter,                          /* tp_iter */
1246
    tupleiter_next,                             /* tp_iternext */
1247
    tupleiter_methods,                          /* tp_methods */
1248
    0,
1249
};
1250
1251
static PyObject *
1252
tuple_iter(PyObject *seq)
1253
4.63M
{
1254
4.63M
    if (!PyTuple_Check(seq)) {
1255
0
        PyErr_BadInternalCall();
1256
0
        return NULL;
1257
0
    }
1258
4.63M
    _PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters);
1259
4.63M
    if (it == NULL) {
1260
481k
        it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
1261
481k
        if (it == NULL)
1262
0
            return NULL;
1263
481k
    }
1264
4.63M
    it->it_index = 0;
1265
4.63M
    it->it_seq = (PyTupleObject *)Py_NewRef(seq);
1266
4.63M
    _PyObject_GC_TRACK(it);
1267
4.63M
    return (PyObject *)it;
1268
4.63M
}
1269
1270
1271
/*************
1272
 * freelists *
1273
 *************/
1274
1275
static inline int
1276
maybe_freelist_push(PyTupleObject *op)
1277
414M
{
1278
414M
    if (!Py_IS_TYPE(op, &PyTuple_Type)) {
1279
620k
        return 0;
1280
620k
    }
1281
413M
    Py_ssize_t index = Py_SIZE(op) - 1;
1282
413M
    if (index < PyTuple_MAXSAVESIZE) {
1283
408M
        return _Py_FREELIST_PUSH(tuples[index], op, Py_tuple_MAXFREELIST);
1284
408M
    }
1285
5.18M
    return 0;
1286
413M
}
1287
1288
/* Print summary info about the state of the optimized allocator */
1289
void
1290
_PyTuple_DebugMallocStats(FILE *out)
1291
0
{
1292
0
    for (int i = 0; i < PyTuple_MAXSAVESIZE; i++) {
1293
0
        int len = i + 1;
1294
0
        char buf[128];
1295
0
        PyOS_snprintf(buf, sizeof(buf),
1296
0
                      "free %d-sized PyTupleObject", len);
1297
0
        _PyDebugAllocatorStats(out, buf, _Py_FREELIST_SIZE(tuples[i]),
1298
0
                               _PyType_PreHeaderSize(&PyTuple_Type) + _PyObject_VAR_SIZE(&PyTuple_Type, len));
1299
0
    }
1300
0
}