Coverage Report

Created: 2026-07-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/setobject.c
Line
Count
Source
1
2
/* set object implementation
3
4
   Written and maintained by Raymond D. Hettinger <python@rcn.com>
5
   Derived from Objects/dictobject.c.
6
7
   The basic lookup function used by all operations.
8
   This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
9
10
   The initial probe index is computed as hash mod the table size.
11
   Subsequent probe indices are computed as explained in Objects/dictobject.c.
12
13
   To improve cache locality, each probe inspects a series of consecutive
14
   nearby entries before moving on to probes elsewhere in memory.  This leaves
15
   us with a hybrid of linear probing and randomized probing.  The linear probing
16
   reduces the cost of hash collisions because consecutive memory accesses
17
   tend to be much cheaper than scattered probes.  After LINEAR_PROBES steps,
18
   we then use more of the upper bits from the hash value and apply a simple
19
   linear congruential random number generator.  This helps break-up long
20
   chains of collisions.
21
22
   All arithmetic on hash should ignore overflow.
23
24
   Unlike the dictionary implementation, the lookkey function can return
25
   NULL if the rich comparison returns an error.
26
27
   Use cases for sets differ considerably from dictionaries where looked-up
28
   keys are more likely to be present.  In contrast, sets are primarily
29
   about membership testing where the presence of an element is not known in
30
   advance.  Accordingly, the set implementation needs to optimize for both
31
   the found and not-found case.
32
*/
33
34
#include "Python.h"
35
#include "pycore_ceval.h"               // _PyEval_GetBuiltin()
36
#include "pycore_critical_section.h"    // Py_BEGIN_CRITICAL_SECTION, Py_END_CRITICAL_SECTION
37
#include "pycore_dict.h"                // _PyDict_Contains_KnownHash()
38
#include "pycore_modsupport.h"          // _PyArg_NoKwnames()
39
#include "pycore_object.h"              // _PyObject_GC_UNTRACK()
40
#include "pycore_pyatomic_ft_wrappers.h"  // FT_ATOMIC_LOAD_SSIZE_RELAXED()
41
#include "pycore_pyerrors.h"            // _PyErr_SetKeyError()
42
#include "pycore_setobject.h"           // _PySet_NextEntry() definition
43
#include "pycore_weakref.h"             // FT_CLEAR_WEAKREFS()
44
45
#include "stringlib/eq.h"               // unicode_eq()
46
#include <stddef.h>                     // offsetof()
47
#include "clinic/setobject.c.h"
48
49
/*[clinic input]
50
class set "PySetObject *" "&PySet_Type"
51
class frozenset "PySetObject *" "&PyFrozenSet_Type"
52
[clinic start generated code]*/
53
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=97ad1d3e9f117079]*/
54
55
/*[python input]
56
class setobject_converter(self_converter):
57
    type = "PySetObject *"
58
[python start generated code]*/
59
/*[python end generated code: output=da39a3ee5e6b4b0d input=33a44506d4d57793]*/
60
61
/* Object used as dummy key to fill deleted entries */
62
static PyObject _dummy_struct;
63
64
5.63M
#define dummy (&_dummy_struct)
65
66
59.3M
#define SET_LOOKKEY_FOUND 1
67
380M
#define SET_LOOKKEY_NO_MATCH 0
68
0
#define SET_LOOKKEY_ERROR (-1)
69
61.7M
#define SET_LOOKKEY_CHANGED (-2)
70
266M
#define SET_LOOKKEY_EMPTY (-3)
71
72
typedef int (*compare_func)(PySetObject *so, setentry *table, setentry *ep,
73
                            PyObject *key, Py_hash_t hash);
74
75
#ifdef Py_GIL_DISABLED
76
77
#define SET_IS_SHARED(so) _PyObject_GC_IS_SHARED(so)
78
#define SET_MARK_SHARED(so) _PyObject_GC_SET_SHARED(so)
79
80
static void
81
ensure_shared_on_read(PySetObject *so)
82
{
83
    if (!_Py_IsOwnedByCurrentThread((PyObject *)so) && !SET_IS_SHARED(so)) {
84
        // The first time we access a set from a non-owning thread we mark it
85
        // as shared. This ensures that a concurrent resize operation will
86
        // delay freeing the old entries using QSBR, which is necessary
87
        // to safely allow concurrent reads without locking...
88
        Py_BEGIN_CRITICAL_SECTION(so);
89
        if (!SET_IS_SHARED(so)) {
90
            SET_MARK_SHARED(so);
91
        }
92
        Py_END_CRITICAL_SECTION();
93
    }
94
}
95
96
static inline Py_ALWAYS_INLINE int
97
set_compare_threadsafe(PySetObject *so, setentry *table, setentry *ep,
98
                       PyObject *key, Py_hash_t hash)
99
{
100
    PyObject *startkey = FT_ATOMIC_LOAD_PTR_ACQUIRE(ep->key);
101
    if (startkey == NULL) {
102
        return SET_LOOKKEY_EMPTY;
103
    }
104
    if (startkey == key) {
105
        return SET_LOOKKEY_FOUND;
106
    }
107
    Py_ssize_t ep_hash = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(ep->hash);
108
    if (ep_hash == hash) {
109
        if (!_Py_TryIncrefCompare(&ep->key, startkey)) {
110
            return SET_LOOKKEY_CHANGED;
111
        }
112
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
113
        Py_DECREF(startkey);
114
        if (cmp < 0) {
115
            return SET_LOOKKEY_ERROR;
116
        }
117
        if (table == FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table) &&
118
            startkey == FT_ATOMIC_LOAD_PTR_ACQUIRE(ep->key)) {
119
            assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH);
120
            return cmp;
121
        }
122
        else {
123
            /* The set was mutated, restart */
124
            return SET_LOOKKEY_CHANGED;
125
        }
126
    }
127
    return SET_LOOKKEY_NO_MATCH;
128
}
129
130
#else
131
132
113k
#define SET_IS_SHARED(so) 0
133
#define SET_MARK_SHARED(so)
134
135
#endif
136
137
static inline Py_ALWAYS_INLINE int
138
set_compare_entry_lock_held(PySetObject *so, setentry *table, setentry *entry,
139
                            PyObject *key, Py_hash_t hash)
140
102M
{
141
102M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
142
102M
    if (entry->hash == 0 && entry->key == NULL)
143
32.2M
        return SET_LOOKKEY_EMPTY;
144
69.9M
    if (entry->hash == hash) {
145
29.5M
        PyObject *startkey = entry->key;
146
29.5M
        assert(startkey != dummy);
147
29.5M
        if (startkey == key)
148
29.4M
            return SET_LOOKKEY_FOUND;
149
131k
        if (PyUnicode_CheckExact(startkey)
150
131k
            && PyUnicode_CheckExact(key)
151
6.27k
            && unicode_eq(startkey, key))
152
6.27k
            return SET_LOOKKEY_FOUND;
153
124k
        table = so->table;
154
124k
        Py_INCREF(startkey);
155
124k
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
156
124k
        Py_DECREF(startkey);
157
124k
        if (cmp < 0)
158
0
            return SET_LOOKKEY_ERROR;
159
124k
        if (table != so->table || entry->key != startkey)
160
0
            return SET_LOOKKEY_CHANGED;
161
124k
        if (cmp > 0)
162
124k
            return SET_LOOKKEY_FOUND;
163
124k
    }
164
40.4M
    return SET_LOOKKEY_NO_MATCH;
165
69.9M
}
166
167
// This is similar to set_compare_entry_lock_held() but we don't need to
168
// incref startkey before comparing and we don't need to check if the set has
169
// changed.  This also omits the PyUnicode_CheckExact() special case since it
170
// doesn't help much for frozensets.
171
static inline Py_ALWAYS_INLINE int
172
set_compare_frozenset(PySetObject *so, setentry *table, setentry *ep,
173
                                 PyObject *key, Py_hash_t hash)
174
117M
{
175
117M
    assert(PyFrozenSet_Check(so));
176
117M
    PyObject *startkey = ep->key;
177
117M
    if (startkey == NULL) {
178
71.3M
        return SET_LOOKKEY_EMPTY;
179
71.3M
    }
180
46.3M
    if (startkey == key) {
181
29.7M
        return SET_LOOKKEY_FOUND;
182
29.7M
    }
183
16.5M
    Py_ssize_t ep_hash = ep->hash;
184
16.5M
    if (ep_hash == hash) {
185
134k
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
186
134k
        if (cmp < 0) {
187
0
            return SET_LOOKKEY_ERROR;
188
0
        }
189
134k
        assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH);
190
134k
        return cmp;
191
134k
    }
192
16.4M
    return SET_LOOKKEY_NO_MATCH;
193
16.5M
}
194
195
static void
196
set_zero_table(setentry *table, size_t size)
197
120k
{
198
#ifdef Py_GIL_DISABLED
199
    for (size_t i = 0; i < size; i++) {
200
        setentry *entry = &table[i];
201
        FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, 0);
202
        FT_ATOMIC_STORE_PTR_RELEASE(entry->key, NULL);
203
    }
204
#else
205
120k
    memset(table, 0, sizeof(setentry)*size);
206
120k
#endif
207
120k
}
208
209
/* ======================================================================== */
210
/* ======= Begin logic for probing the hash table ========================= */
211
212
/* Set this to zero to turn-off linear probing */
213
#ifndef LINEAR_PROBES
214
259M
#define LINEAR_PROBES 9
215
#endif
216
217
/* This must be >= 1 */
218
10.6M
#define PERTURB_SHIFT 5
219
220
static int
221
set_do_lookup(PySetObject *so, setentry *table, size_t mask, PyObject *key,
222
              Py_hash_t hash, setentry **epp, compare_func compare_entry)
223
163M
{
224
163M
    setentry *entry;
225
163M
    size_t perturb = hash;
226
163M
    size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
227
163M
    int probes;
228
163M
    int status;
229
230
173M
    while (1) {
231
173M
        entry = &table[i];
232
173M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
233
219M
        do {
234
219M
            status = compare_entry(so, table, entry, key, hash);
235
219M
            if (status != SET_LOOKKEY_NO_MATCH) {
236
163M
                if (status == SET_LOOKKEY_EMPTY) {
237
103M
                    return SET_LOOKKEY_NO_MATCH;
238
103M
                }
239
59.4M
                *epp = entry;
240
59.4M
                return status;
241
163M
            }
242
56.8M
            entry++;
243
56.8M
        } while (probes--);
244
10.5M
        perturb >>= PERTURB_SHIFT;
245
10.5M
        i = (i * 5 + 1 + perturb) & mask;
246
10.5M
    }
247
163M
    Py_UNREACHABLE();
248
163M
}
249
250
static int set_table_resize(PySetObject *, Py_ssize_t);
251
252
static int
253
set_add_entry_takeref(PySetObject *so, PyObject *key, Py_hash_t hash)
254
2.75M
{
255
2.75M
    setentry *table;
256
2.75M
    setentry *freeslot;
257
2.75M
    setentry *entry;
258
2.75M
    size_t perturb;
259
2.75M
    size_t mask;
260
2.75M
    size_t i;                       /* Unsigned for defined overflow behavior */
261
2.75M
    int probes;
262
2.75M
    int cmp;
263
264
2.75M
  restart:
265
266
2.75M
    mask = so->mask;
267
2.75M
    i = (size_t)hash & mask;
268
2.75M
    freeslot = NULL;
269
2.75M
    perturb = hash;
270
271
2.92M
    while (1) {
272
2.92M
        entry = &so->table[i];
273
2.92M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
274
3.17M
        do {
275
3.17M
            if (entry->hash == 0 && entry->key == NULL)
276
2.14M
                goto found_unused_or_dummy;
277
1.02M
            if (entry->hash == hash) {
278
610k
                PyObject *startkey = entry->key;
279
610k
                assert(startkey != dummy);
280
610k
                if (startkey == key)
281
251k
                    goto found_active;
282
359k
                if (PyUnicode_CheckExact(startkey)
283
359k
                    && PyUnicode_CheckExact(key)
284
218k
                    && unicode_eq(startkey, key))
285
218k
                    goto found_active;
286
140k
                table = so->table;
287
140k
                Py_INCREF(startkey);
288
140k
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
289
140k
                Py_DECREF(startkey);
290
140k
                if (cmp > 0)
291
140k
                    goto found_active;
292
98
                if (cmp < 0)
293
0
                    goto comparison_error;
294
98
                if (table != so->table || entry->key != startkey)
295
0
                    goto restart;
296
98
                mask = so->mask;
297
98
            }
298
414k
            else if (entry->hash == -1) {
299
6
                assert (entry->key == dummy);
300
6
                freeslot = entry;
301
6
            }
302
415k
            entry++;
303
415k
        } while (probes--);
304
165k
        perturb >>= PERTURB_SHIFT;
305
165k
        i = (i * 5 + 1 + perturb) & mask;
306
165k
    }
307
308
2.14M
  found_unused_or_dummy:
309
2.14M
    if (freeslot == NULL)
310
2.14M
        goto found_unused;
311
6
    if (freeslot->hash != -1) {
312
0
        goto restart;
313
0
    }
314
6
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
315
6
    FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash);
316
6
    FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key);
317
6
    return 0;
318
319
2.14M
  found_unused:
320
2.14M
    so->fill++;
321
2.14M
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
322
2.14M
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
323
2.14M
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
324
2.14M
    if ((size_t)so->fill*5 < mask*3)
325
2.05M
        return 0;
326
92.2k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
327
328
610k
  found_active:
329
610k
    Py_DECREF(key);
330
610k
    return 0;
331
332
0
  comparison_error:
333
0
    Py_DECREF(key);
334
0
    return -1;
335
2.14M
}
336
337
static int
338
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
339
2.23M
{
340
2.23M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
341
342
2.23M
    return set_add_entry_takeref(so, Py_NewRef(key), hash);
343
2.23M
}
344
345
static void
346
set_unhashable_type(PyObject *key)
347
0
{
348
0
    PyObject *exc = PyErr_GetRaisedException();
349
0
    assert(exc != NULL);
350
0
    if (!Py_IS_TYPE(exc, (PyTypeObject*)PyExc_TypeError)) {
351
0
        PyErr_SetRaisedException(exc);
352
0
        return;
353
0
    }
354
355
0
    PyErr_Format(PyExc_TypeError,
356
0
                 "cannot use '%T' as a set element (%S)",
357
0
                 key, exc);
358
0
    Py_DECREF(exc);
359
0
}
360
361
int
362
_PySet_AddTakeRef(PySetObject *so, PyObject *key)
363
521k
{
364
521k
    Py_hash_t hash = PyObject_Hash(key);
365
521k
    if (hash == -1) {
366
0
        set_unhashable_type(key);
367
0
        Py_DECREF(key);
368
0
        return -1;
369
0
    }
370
    // We don't pre-increment here, the caller holds a strong
371
    // reference to the object which we are stealing.
372
521k
    return set_add_entry_takeref(so, key, hash);
373
521k
}
374
375
/*
376
Internal routine used by set_table_resize() to insert an item which is
377
known to be absent from the set.  Besides the performance benefit,
378
there is also safety benefit since using set_add_entry() risks making
379
a callback in the middle of a set_table_resize(), see issue 1456209.
380
The caller is responsible for updating the key's reference count and
381
the setobject's fill and used fields.
382
*/
383
static void
384
set_insert_clean(setentry *table, size_t mask, PyObject *key, Py_hash_t hash)
385
621k
{
386
621k
    setentry *entry;
387
621k
    size_t perturb = hash;
388
621k
    size_t i = (size_t)hash & mask;
389
621k
    size_t j;
390
391
634k
    while (1) {
392
634k
        entry = &table[i];
393
634k
        if (entry->key == NULL)
394
607k
            goto found_null;
395
27.1k
        if (i + LINEAR_PROBES <= mask) {
396
110k
            for (j = 0; j < LINEAR_PROBES; j++) {
397
101k
                entry++;
398
101k
                if (entry->key == NULL)
399
13.5k
                    goto found_null;
400
101k
            }
401
22.4k
        }
402
13.5k
        perturb >>= PERTURB_SHIFT;
403
13.5k
        i = (i * 5 + 1 + perturb) & mask;
404
13.5k
    }
405
621k
  found_null:
406
621k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
407
621k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
408
621k
}
409
410
/* ======== End logic for probing the hash table ========================== */
411
/* ======================================================================== */
412
413
static int
414
set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash, setentry **epp)
415
163M
{
416
163M
    int status;
417
163M
    if (PyFrozenSet_CheckExact(so)) {
418
101M
        status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
419
101M
                               set_compare_frozenset);
420
101M
    }
421
61.7M
    else {
422
61.7M
        Py_BEGIN_CRITICAL_SECTION(so);
423
61.7M
        do {
424
61.7M
            status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
425
61.7M
                                   set_compare_entry_lock_held);
426
61.7M
        } while (status == SET_LOOKKEY_CHANGED);
427
61.7M
        Py_END_CRITICAL_SECTION();
428
61.7M
    }
429
163M
    assert(status == SET_LOOKKEY_FOUND ||
430
163M
           status == SET_LOOKKEY_NO_MATCH ||
431
163M
           status == SET_LOOKKEY_ERROR);
432
163M
    return status;
433
163M
}
434
435
#ifdef Py_GIL_DISABLED
436
static int
437
set_lookkey_threadsafe(PySetObject *so, PyObject *key, Py_hash_t hash)
438
{
439
    int status;
440
    setentry *entry;
441
    if (PyFrozenSet_CheckExact(so)) {
442
        status = set_do_lookup(so, so->table, so->mask, key, hash, &entry,
443
                               set_compare_frozenset);
444
        assert(status == SET_LOOKKEY_FOUND ||
445
               status == SET_LOOKKEY_NO_MATCH ||
446
               status == SET_LOOKKEY_ERROR);
447
        return status;
448
    }
449
    ensure_shared_on_read(so);
450
    setentry *table = FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table);
451
    size_t mask = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->mask);
452
    if (table == NULL || table != FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table)) {
453
        return set_lookkey(so, key, hash, &entry);
454
    }
455
    status = set_do_lookup(so, table, mask, key, hash, &entry,
456
                           set_compare_threadsafe);
457
    if (status == SET_LOOKKEY_CHANGED) {
458
        return set_lookkey(so, key, hash, &entry);
459
    }
460
    assert(status == SET_LOOKKEY_FOUND ||
461
           status == SET_LOOKKEY_NO_MATCH ||
462
           status == SET_LOOKKEY_ERROR);
463
    return status;
464
}
465
#endif
466
467
static void free_entries(setentry *entries, size_t size, bool use_qsbr)
468
113k
{
469
#ifdef Py_GIL_DISABLED
470
    if (use_qsbr) {
471
        _PyMem_FreeDelayed(entries, size * sizeof(setentry));
472
        return;
473
    }
474
#endif
475
113k
    PyMem_Free(entries);
476
113k
}
477
478
/*
479
Restructure the table by allocating a new table and reinserting all
480
keys again.  When entries have been deleted, the new table may
481
actually be smaller than the old one.
482
*/
483
static int
484
set_table_resize(PySetObject *so, Py_ssize_t minused)
485
115k
{
486
115k
    setentry *oldtable, *newtable, *entry;
487
115k
    Py_ssize_t oldmask = so->mask;
488
115k
    Py_ssize_t oldsize = (size_t)oldmask + 1;
489
115k
    size_t newmask;
490
115k
    int is_oldtable_malloced;
491
115k
    setentry small_copy[PySet_MINSIZE];
492
493
115k
    assert(minused >= 0);
494
495
    /* Find the smallest table size > minused. */
496
    /* XXX speed-up with intrinsics */
497
115k
    size_t newsize = PySet_MINSIZE;
498
344k
    while (newsize <= (size_t)minused) {
499
229k
        newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
500
229k
    }
501
502
    /* Get space for a new table. */
503
115k
    oldtable = so->table;
504
115k
    assert(oldtable != NULL);
505
115k
    is_oldtable_malloced = oldtable != so->smalltable;
506
507
115k
    if (newsize == PySet_MINSIZE) {
508
        /* A large table is shrinking, or we can't get any smaller. */
509
0
        newtable = so->smalltable;
510
0
        if (newtable == oldtable) {
511
0
            if (so->fill == so->used) {
512
                /* No dummies, so no point doing anything. */
513
0
                return 0;
514
0
            }
515
            /* We're not going to resize it, but rebuild the
516
               table anyway to purge old dummy entries.
517
               Subtle:  This is *necessary* if fill==size,
518
               as set_lookkey needs at least one virgin slot to
519
               terminate failing searches.  If fill < size, it's
520
               merely desirable, as dummies slow searches. */
521
0
            assert(so->fill > so->used);
522
0
            memcpy(small_copy, oldtable, sizeof(small_copy));
523
0
            oldtable = small_copy;
524
0
        }
525
0
    }
526
115k
    else {
527
115k
        newtable = PyMem_NEW(setentry, newsize);
528
115k
        if (newtable == NULL) {
529
0
            PyErr_NoMemory();
530
0
            return -1;
531
0
        }
532
115k
    }
533
534
    /* Make the set empty, using the new table. */
535
115k
    assert(newtable != oldtable);
536
115k
    set_zero_table(newtable, newsize);
537
115k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
538
115k
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, newsize - 1);
539
540
    /* Copy the data over; this is refcount-neutral for active entries;
541
       dummy entries aren't copied over, of course */
542
115k
    newmask = (size_t)so->mask;
543
115k
    if (so->fill == so->used) {
544
1.21M
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
545
1.10M
            if (entry->key != NULL) {
546
614k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
547
614k
            }
548
1.10M
        }
549
115k
    } else {
550
5
        so->fill = so->used;
551
141
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
552
136
            if (entry->key != NULL && entry->key != dummy) {
553
72
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
554
72
            }
555
136
        }
556
5
    }
557
558
115k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, newtable);
559
560
115k
    if (is_oldtable_malloced)
561
8.43k
        free_entries(oldtable, oldsize, SET_IS_SHARED(so));
562
115k
    return 0;
563
115k
}
564
565
static int
566
set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
567
162M
{
568
#ifdef Py_GIL_DISABLED
569
    return set_lookkey_threadsafe(so, key, hash);
570
#else
571
162M
    setentry *entry; // unused
572
162M
    return set_lookkey(so, key, hash, &entry);
573
162M
#endif
574
162M
}
575
576
37.7k
#define DISCARD_NOTFOUND 0
577
1.01k
#define DISCARD_FOUND 1
578
579
static int
580
set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
581
38.7k
{
582
38.7k
    setentry *entry;
583
38.7k
    PyObject *old_key;
584
38.7k
    int status = set_lookkey(so, key, hash, &entry);
585
38.7k
    if (status < 0) {
586
0
        return -1;
587
0
    }
588
38.7k
    if (status == SET_LOOKKEY_NO_MATCH) {
589
37.7k
        return DISCARD_NOTFOUND;
590
37.7k
    }
591
38.7k
    assert(status == SET_LOOKKEY_FOUND);
592
1.01k
    old_key = entry->key;
593
1.01k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
594
1.01k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
595
1.01k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
596
1.01k
    Py_DECREF(old_key);
597
1.01k
    return DISCARD_FOUND;
598
38.7k
}
599
600
static int
601
set_add_key(PySetObject *so, PyObject *key)
602
1.63M
{
603
1.63M
    Py_hash_t hash = PyObject_Hash(key);
604
1.63M
    if (hash == -1) {
605
0
        set_unhashable_type(key);
606
0
        return -1;
607
0
    }
608
1.63M
    return set_add_entry(so, key, hash);
609
1.63M
}
610
611
static int
612
set_contains_key(PySetObject *so, PyObject *key)
613
25.6k
{
614
25.6k
    Py_hash_t hash = PyObject_Hash(key);
615
25.6k
    if (hash == -1) {
616
0
        set_unhashable_type(key);
617
0
        return -1;
618
0
    }
619
25.6k
    return set_contains_entry(so, key, hash);
620
25.6k
}
621
622
static int
623
set_discard_key(PySetObject *so, PyObject *key)
624
38.7k
{
625
38.7k
    Py_hash_t hash = PyObject_Hash(key);
626
38.7k
    if (hash == -1) {
627
0
        set_unhashable_type(key);
628
0
        return -1;
629
0
    }
630
38.7k
    return set_discard_entry(so, key, hash);
631
38.7k
}
632
633
static void
634
set_empty_to_minsize(PySetObject *so)
635
4.83k
{
636
4.83k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
637
4.83k
    set_zero_table(so->smalltable, PySet_MINSIZE);
638
4.83k
    so->fill = 0;
639
4.83k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0);
640
4.83k
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, PySet_MINSIZE - 1);
641
4.83k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1);
642
4.83k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, so->smalltable);
643
4.83k
}
644
645
static int
646
set_clear_internal(PyObject *self)
647
9.13k
{
648
9.13k
    PySetObject *so = _PySet_CAST(self);
649
9.13k
    setentry *entry;
650
9.13k
    setentry *table = so->table;
651
9.13k
    Py_ssize_t fill = so->fill;
652
9.13k
    Py_ssize_t used = so->used;
653
9.13k
    Py_ssize_t oldsize = (size_t)so->mask + 1;
654
9.13k
    int table_is_malloced = table != so->smalltable;
655
9.13k
    setentry small_copy[PySet_MINSIZE];
656
657
9.13k
    assert (PyAnySet_Check(so));
658
9.13k
    assert(table != NULL);
659
660
    /* This is delicate.  During the process of clearing the set,
661
     * decrefs can cause the set to mutate.  To avoid fatal confusion
662
     * (voice of experience), we have to make the set empty before
663
     * clearing the slots, and never refer to anything via so->ref while
664
     * clearing.
665
     */
666
9.13k
    if (table_is_malloced)
667
1.35k
        set_empty_to_minsize(so);
668
669
7.78k
    else if (fill > 0) {
670
        /* It's a small table with something that needs to be cleared.
671
         * Afraid the only safe way is to copy the set entries into
672
         * another small table first.
673
         */
674
3.48k
        memcpy(small_copy, table, sizeof(small_copy));
675
3.48k
        table = small_copy;
676
3.48k
        set_empty_to_minsize(so);
677
3.48k
    }
678
    /* else it's a small table that's already empty */
679
680
    /* Now we can finally clear things.  If C had refcounts, we could
681
     * assert that the refcount on table is 1 now, i.e. that this function
682
     * has unique access to it, so decref side-effects can't alter it.
683
     */
684
169k
    for (entry = table; used > 0; entry++) {
685
160k
        if (entry->key && entry->key != dummy) {
686
46.2k
            used--;
687
46.2k
            Py_DECREF(entry->key);
688
46.2k
        }
689
160k
    }
690
691
9.13k
    if (table_is_malloced)
692
1.35k
        free_entries(table, oldsize, SET_IS_SHARED(so));
693
9.13k
    return 0;
694
9.13k
}
695
696
/*
697
 * Iterate over a set table.  Use like so:
698
 *
699
 *     Py_ssize_t pos;
700
 *     setentry *entry;
701
 *     pos = 0;   # important!  pos should not otherwise be changed by you
702
 *     while (set_next(yourset, &pos, &entry)) {
703
 *              Refer to borrowed reference in entry->key.
704
 *     }
705
 *
706
 * CAUTION:  In general, it isn't safe to use set_next in a loop that
707
 * mutates the table.
708
 */
709
static int
710
set_next(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr)
711
3.23M
{
712
3.23M
    Py_ssize_t i;
713
3.23M
    Py_ssize_t mask;
714
3.23M
    setentry *entry;
715
716
3.23M
    assert (PyAnySet_Check(so));
717
3.23M
    i = *pos_ptr;
718
3.23M
    assert(i >= 0);
719
3.23M
    mask = so->mask;
720
3.23M
    entry = &so->table[i];
721
12.2M
    while (i <= mask && (entry->key == NULL || entry->key == dummy)) {
722
9.06M
        i++;
723
9.06M
        entry++;
724
9.06M
    }
725
3.23M
    *pos_ptr = i+1;
726
3.23M
    if (i > mask)
727
823k
        return 0;
728
3.23M
    assert(entry != NULL);
729
2.41M
    *entry_ptr = entry;
730
2.41M
    return 1;
731
3.23M
}
732
733
static void
734
set_dealloc(PyObject *self)
735
1.82M
{
736
1.82M
    PySetObject *so = _PySet_CAST(self);
737
1.82M
    setentry *entry;
738
1.82M
    Py_ssize_t used = so->used;
739
1.82M
    Py_ssize_t oldsize = (size_t)so->mask + 1;
740
741
    /* bpo-31095: UnTrack is needed before calling any callbacks */
742
1.82M
    PyObject_GC_UnTrack(so);
743
1.82M
    FT_CLEAR_WEAKREFS(self, so->weakreflist);
744
745
9.84M
    for (entry = so->table; used > 0; entry++) {
746
8.01M
        if (entry->key && entry->key != dummy) {
747
2.47M
                used--;
748
2.47M
                Py_DECREF(entry->key);
749
2.47M
        }
750
8.01M
    }
751
1.82M
    if (so->table != so->smalltable)
752
103k
        free_entries(so->table, oldsize, SET_IS_SHARED(so));
753
1.82M
    Py_TYPE(so)->tp_free(so);
754
1.82M
}
755
756
static PyObject *
757
set_repr_lock_held(PySetObject *so)
758
0
{
759
0
    PyObject *result=NULL, *keys, *listrepr, *tmp;
760
0
    int status = Py_ReprEnter((PyObject*)so);
761
762
0
    if (status != 0) {
763
0
        if (status < 0)
764
0
            return NULL;
765
0
        return PyUnicode_FromFormat("%s(...)", Py_TYPE(so)->tp_name);
766
0
    }
767
768
    /* shortcut for the empty set */
769
0
    if (!so->used) {
770
0
        Py_ReprLeave((PyObject*)so);
771
0
        return PyUnicode_FromFormat("%s()", Py_TYPE(so)->tp_name);
772
0
    }
773
774
    // gh-129967: avoid PySequence_List because it might re-lock the object
775
    // lock or the GIL and allow something to clear the set from underneath us.
776
0
    keys = PyList_New(so->used);
777
0
    if (keys == NULL) {
778
0
        goto done;
779
0
    }
780
781
0
    Py_ssize_t pos = 0, idx = 0;
782
0
    setentry *entry;
783
0
    while (set_next(so, &pos, &entry)) {
784
0
        PyList_SET_ITEM(keys, idx++, Py_NewRef(entry->key));
785
0
    }
786
787
    /* repr(keys)[1:-1] */
788
0
    listrepr = PyObject_Repr(keys);
789
0
    Py_DECREF(keys);
790
0
    if (listrepr == NULL)
791
0
        goto done;
792
0
    tmp = PyUnicode_Substring(listrepr, 1, PyUnicode_GET_LENGTH(listrepr)-1);
793
0
    Py_DECREF(listrepr);
794
0
    if (tmp == NULL)
795
0
        goto done;
796
0
    listrepr = tmp;
797
798
0
    if (!PySet_CheckExact(so))
799
0
        result = PyUnicode_FromFormat("%s({%U})",
800
0
                                      Py_TYPE(so)->tp_name,
801
0
                                      listrepr);
802
0
    else
803
0
        result = PyUnicode_FromFormat("{%U}", listrepr);
804
0
    Py_DECREF(listrepr);
805
0
done:
806
0
    Py_ReprLeave((PyObject*)so);
807
0
    return result;
808
0
}
809
810
static PyObject *
811
set_repr(PyObject *self)
812
0
{
813
0
    PySetObject *so = _PySet_CAST(self);
814
0
    PyObject *result;
815
0
    Py_BEGIN_CRITICAL_SECTION(so);
816
0
    result = set_repr_lock_held(so);
817
0
    Py_END_CRITICAL_SECTION();
818
0
    return result;
819
0
}
820
821
static Py_ssize_t
822
set_len(PyObject *self)
823
99.0k
{
824
99.0k
    PySetObject *so = _PySet_CAST(self);
825
99.0k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
826
99.0k
}
827
828
static int
829
set_merge_lock_held(PySetObject *so, PyObject *otherset)
830
726k
{
831
726k
    PySetObject *other;
832
726k
    PyObject *key;
833
726k
    Py_ssize_t i;
834
726k
    setentry *so_entry;
835
726k
    setentry *other_entry;
836
837
726k
    assert (PyAnySet_Check(so));
838
726k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
839
726k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(otherset);
840
841
726k
    other = _PySet_CAST(otherset);
842
726k
    if (other == so || other->used == 0)
843
        /* a.update(a) or a.update(set()); nothing to do */
844
193k
        return 0;
845
    /* Do one big resize at the start, rather than
846
     * incrementally resizing as we insert new keys.  Expect
847
     * that there will be no (or few) overlapping keys.
848
     */
849
533k
    if ((so->fill + other->used)*5 >= so->mask*3) {
850
23.0k
        if (set_table_resize(so, (so->used + other->used)*2) != 0)
851
0
            return -1;
852
23.0k
    }
853
533k
    so_entry = so->table;
854
533k
    other_entry = other->table;
855
856
    /* If our table is empty, and both tables have the same size, and
857
       there are no dummies to eliminate, then just copy the pointers. */
858
533k
    if (so->fill == 0 && so->mask == other->mask && other->fill == other->used) {
859
1.50M
        for (i = 0; i <= other->mask; i++, so_entry++, other_entry++) {
860
1.34M
            key = other_entry->key;
861
1.34M
            if (key != NULL) {
862
420k
                assert(so_entry->key == NULL);
863
420k
                FT_ATOMIC_STORE_SSIZE_RELAXED(so_entry->hash, other_entry->hash);
864
420k
                FT_ATOMIC_STORE_PTR_RELEASE(so_entry->key, Py_NewRef(key));
865
420k
            }
866
1.34M
        }
867
162k
        so->fill = other->fill;
868
162k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
869
162k
        return 0;
870
162k
    }
871
872
    /* If our table is empty, we can use set_insert_clean() */
873
371k
    if (so->fill == 0) {
874
804
        setentry *newtable = so->table;
875
804
        size_t newmask = (size_t)so->mask;
876
804
        so->fill = other->used;
877
804
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
878
34.6k
        for (i = other->mask + 1; i > 0 ; i--, other_entry++) {
879
33.8k
            key = other_entry->key;
880
33.8k
            if (key != NULL && key != dummy) {
881
7.20k
                set_insert_clean(newtable, newmask, Py_NewRef(key),
882
7.20k
                                 other_entry->hash);
883
7.20k
            }
884
33.8k
        }
885
804
        return 0;
886
804
    }
887
888
    /* We can't assure there are no duplicates, so do normal insertions */
889
3.50M
    for (i = 0; i <= other->mask; i++) {
890
3.13M
        other_entry = &other->table[i];
891
3.13M
        key = other_entry->key;
892
3.13M
        if (key != NULL && key != dummy) {
893
600k
            if (set_add_entry(so, key, other_entry->hash))
894
0
                return -1;
895
600k
        }
896
3.13M
    }
897
370k
    return 0;
898
370k
}
899
900
/*[clinic input]
901
@critical_section
902
set.pop
903
    so: setobject
904
905
Remove and return an arbitrary set element.
906
907
Raises KeyError if the set is empty.
908
[clinic start generated code]*/
909
910
static PyObject *
911
set_pop_impl(PySetObject *so)
912
/*[clinic end generated code: output=4d65180f1271871b input=9296c84921125060]*/
913
296
{
914
    /* Make sure the search finger is in bounds */
915
296
    setentry *entry = so->table + (so->finger & so->mask);
916
296
    setentry *limit = so->table + so->mask;
917
296
    PyObject *key;
918
919
296
    if (so->used == 0) {
920
0
        PyErr_SetString(PyExc_KeyError, "pop from an empty set");
921
0
        return NULL;
922
0
    }
923
1.42k
    while (entry->key == NULL || entry->key==dummy) {
924
1.12k
        entry++;
925
1.12k
        if (entry > limit)
926
0
            entry = so->table;
927
1.12k
    }
928
296
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
929
296
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
930
296
    key = entry->key;
931
296
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
932
296
    so->finger = entry - so->table + 1;   /* next place to start */
933
296
    return key;
934
296
}
935
936
static int
937
set_traverse(PyObject *self, visitproc visit, void *arg)
938
171k
{
939
171k
    PySetObject *so = _PySet_CAST(self);
940
171k
    Py_ssize_t pos = 0;
941
171k
    setentry *entry;
942
943
1.29M
    while (set_next(so, &pos, &entry))
944
1.12M
        Py_VISIT(entry->key);
945
171k
    return 0;
946
171k
}
947
948
/* Work to increase the bit dispersion for closely spaced hash values.
949
   This is important because some use cases have many combinations of a
950
   small number of elements with nearby hashes so that many distinct
951
   combinations collapse to only a handful of distinct hash values. */
952
953
static Py_uhash_t
954
_shuffle_bits(Py_uhash_t h)
955
1.81M
{
956
1.81M
    return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL;
957
1.81M
}
958
959
/* Most of the constants in this hash algorithm are randomly chosen
960
   large primes with "interesting bit patterns" and that passed tests
961
   for good collision statistics on a variety of problematic datasets
962
   including powersets and graph structures (such as David Eppstein's
963
   graph recipes in Lib/test/test_set.py).
964
965
   This hash algorithm can be used on either a frozenset or a set.
966
   When it is used on a set, it computes the hash value of the equivalent
967
   frozenset without creating a new frozenset object.
968
969
   If you update this code, update also frozendict_hash() which copied this
970
   code. */
971
972
static Py_hash_t
973
frozenset_hash_impl(PyObject *self)
974
224k
{
975
224k
    PySetObject *so = _PySet_CAST(self);
976
224k
    Py_uhash_t hash = 0;
977
224k
    setentry *entry;
978
979
    /* Xor-in shuffled bits from every entry's hash field because xor is
980
       commutative and a frozenset hash should be independent of order.
981
982
       For speed, include null entries and dummy entries and then
983
       subtract out their effect afterwards so that the final hash
984
       depends only on active entries.  This allows the code to be
985
       vectorized by the compiler and it saves the unpredictable
986
       branches that would arise when trying to exclude null and dummy
987
       entries on every iteration. */
988
989
2.03M
    for (entry = so->table; entry <= &so->table[so->mask]; entry++)
990
1.81M
        hash ^= _shuffle_bits(entry->hash);
991
992
    /* Remove the effect of an odd number of NULL entries */
993
224k
    if ((so->mask + 1 - so->fill) & 1)
994
375
        hash ^= _shuffle_bits(0);
995
996
    /* Remove the effect of an odd number of dummy entries */
997
224k
    if ((so->fill - so->used) & 1)
998
0
        hash ^= _shuffle_bits(-1);
999
1000
    /* Factor in the number of active entries */
1001
224k
    hash ^= ((Py_uhash_t)PySet_GET_SIZE(self) + 1) * 1927868237UL;
1002
1003
    /* Disperse patterns arising in nested frozensets */
1004
224k
    hash ^= (hash >> 11) ^ (hash >> 25);
1005
224k
    hash = hash * 69069U + 907133923UL;
1006
1007
    /* -1 is reserved as an error code */
1008
224k
    if (hash == (Py_uhash_t)-1)
1009
0
        hash = 590923713UL;
1010
1011
224k
    return (Py_hash_t)hash;
1012
224k
}
1013
1014
static Py_hash_t
1015
frozenset_hash(PyObject *self)
1016
225k
{
1017
225k
    PySetObject *so = _PySet_CAST(self);
1018
225k
    Py_uhash_t hash;
1019
1020
225k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) {
1021
362
        return FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->hash);
1022
362
    }
1023
1024
224k
    hash = frozenset_hash_impl(self);
1025
224k
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->hash, hash);
1026
224k
    return hash;
1027
225k
}
1028
1029
/***** Set iterator type ***********************************************/
1030
1031
typedef struct {
1032
    PyObject_HEAD
1033
    PySetObject *si_set; /* Set to NULL when iterator is exhausted */
1034
    Py_ssize_t si_used;
1035
    Py_ssize_t si_pos;
1036
    Py_ssize_t len;
1037
} setiterobject;
1038
1039
static void
1040
setiter_dealloc(PyObject *self)
1041
73.0k
{
1042
73.0k
    setiterobject *si = (setiterobject*)self;
1043
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1044
73.0k
    _PyObject_GC_UNTRACK(si);
1045
73.0k
    Py_XDECREF(si->si_set);
1046
73.0k
    PyObject_GC_Del(si);
1047
73.0k
}
1048
1049
static int
1050
setiter_traverse(PyObject *self, visitproc visit, void *arg)
1051
0
{
1052
0
    setiterobject *si = (setiterobject*)self;
1053
0
    Py_VISIT(si->si_set);
1054
0
    return 0;
1055
0
}
1056
1057
static PyObject *
1058
setiter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
1059
10
{
1060
10
    setiterobject *si = (setiterobject*)op;
1061
10
    Py_ssize_t len = 0;
1062
10
    if (si->si_set != NULL && si->si_used == si->si_set->used)
1063
10
        len = si->len;
1064
10
    return PyLong_FromSsize_t(len);
1065
10
}
1066
1067
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
1068
1069
static PyObject *
1070
setiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
1071
0
{
1072
0
    setiterobject *si = (setiterobject*)op;
1073
1074
    /* copy the iterator state */
1075
0
    setiterobject tmp = *si;
1076
0
    Py_XINCREF(tmp.si_set);
1077
1078
    /* iterate the temporary into a list */
1079
0
    PyObject *list = PySequence_List((PyObject*)&tmp);
1080
0
    Py_XDECREF(tmp.si_set);
1081
0
    if (list == NULL) {
1082
0
        return NULL;
1083
0
    }
1084
0
    return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
1085
0
}
1086
1087
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
1088
1089
static PyMethodDef setiter_methods[] = {
1090
    {"__length_hint__", setiter_len, METH_NOARGS, length_hint_doc},
1091
    {"__reduce__", setiter_reduce, METH_NOARGS, reduce_doc},
1092
    {NULL,              NULL}           /* sentinel */
1093
};
1094
1095
static PyObject *setiter_iternext(PyObject *self)
1096
170k
{
1097
170k
    setiterobject *si = (setiterobject*)self;
1098
170k
    PyObject *key = NULL;
1099
170k
    Py_ssize_t i, mask;
1100
170k
    setentry *entry;
1101
170k
    PySetObject *so = si->si_set;
1102
1103
170k
    if (so == NULL)
1104
0
        return NULL;
1105
170k
    assert (PyAnySet_Check(so));
1106
1107
170k
    Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
1108
170k
    Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used);
1109
170k
    if (si_used != so_used) {
1110
0
        PyErr_SetString(PyExc_RuntimeError,
1111
0
                        "Set changed size during iteration");
1112
0
        si->si_used = -1; /* Make this state sticky */
1113
0
        return NULL;
1114
0
    }
1115
1116
170k
    Py_BEGIN_CRITICAL_SECTION(so);
1117
170k
    i = si->si_pos;
1118
170k
    assert(i>=0);
1119
170k
    entry = so->table;
1120
170k
    mask = so->mask;
1121
838k
    while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
1122
668k
        i++;
1123
668k
    }
1124
170k
    if (i <= mask) {
1125
97.7k
        key = Py_NewRef(entry[i].key);
1126
97.7k
    }
1127
170k
    Py_END_CRITICAL_SECTION();
1128
170k
    si->si_pos = i+1;
1129
170k
    if (key == NULL) {
1130
72.6k
        si->si_set = NULL;
1131
72.6k
        Py_DECREF(so);
1132
72.6k
        return NULL;
1133
72.6k
    }
1134
97.7k
    si->len--;
1135
97.7k
    return key;
1136
170k
}
1137
1138
PyTypeObject PySetIter_Type = {
1139
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
1140
    "set_iterator",                             /* tp_name */
1141
    sizeof(setiterobject),                      /* tp_basicsize */
1142
    0,                                          /* tp_itemsize */
1143
    /* methods */
1144
    setiter_dealloc,                            /* tp_dealloc */
1145
    0,                                          /* tp_vectorcall_offset */
1146
    0,                                          /* tp_getattr */
1147
    0,                                          /* tp_setattr */
1148
    0,                                          /* tp_as_async */
1149
    0,                                          /* tp_repr */
1150
    0,                                          /* tp_as_number */
1151
    0,                                          /* tp_as_sequence */
1152
    0,                                          /* tp_as_mapping */
1153
    0,                                          /* tp_hash */
1154
    0,                                          /* tp_call */
1155
    0,                                          /* tp_str */
1156
    PyObject_GenericGetAttr,                    /* tp_getattro */
1157
    0,                                          /* tp_setattro */
1158
    0,                                          /* tp_as_buffer */
1159
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
1160
    0,                                          /* tp_doc */
1161
    setiter_traverse,                           /* tp_traverse */
1162
    0,                                          /* tp_clear */
1163
    0,                                          /* tp_richcompare */
1164
    0,                                          /* tp_weaklistoffset */
1165
    PyObject_SelfIter,                          /* tp_iter */
1166
    setiter_iternext,                           /* tp_iternext */
1167
    setiter_methods,                            /* tp_methods */
1168
    0,
1169
};
1170
1171
static PyObject *
1172
set_iter(PyObject *so)
1173
73.0k
{
1174
73.0k
    Py_ssize_t size = set_len(so);
1175
73.0k
    setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
1176
73.0k
    if (si == NULL)
1177
0
        return NULL;
1178
73.0k
    si->si_set = (PySetObject*)Py_NewRef(so);
1179
73.0k
    si->si_used = size;
1180
73.0k
    si->si_pos = 0;
1181
73.0k
    si->len = size;
1182
73.0k
    _PyObject_GC_TRACK(si);
1183
73.0k
    return (PyObject *)si;
1184
73.0k
}
1185
1186
static int
1187
set_update_dict_lock_held(PySetObject *so, PyObject *other)
1188
248
{
1189
248
    assert(PyAnyDict_CheckExact(other));
1190
1191
248
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1192
#ifdef Py_DEBUG
1193
    if (!PyFrozenDict_CheckExact(other)) {
1194
        _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
1195
    }
1196
#endif
1197
1198
    /* Do one big resize at the start, rather than
1199
    * incrementally resizing as we insert new keys.  Expect
1200
    * that there will be no (or few) overlapping keys.
1201
    */
1202
248
    Py_ssize_t dictsize = PyDict_GET_SIZE(other);
1203
248
    if ((so->fill + dictsize)*5 >= so->mask*3) {
1204
24
        if (set_table_resize(so, (so->used + dictsize)*2) != 0) {
1205
0
            return -1;
1206
0
        }
1207
24
    }
1208
1209
248
    Py_ssize_t pos = 0;
1210
248
    PyObject *key;
1211
248
    PyObject *value;
1212
248
    Py_hash_t hash;
1213
700
    while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
1214
452
        if (set_add_entry(so, key, hash)) {
1215
0
            return -1;
1216
0
        }
1217
452
    }
1218
248
    return 0;
1219
248
}
1220
1221
static int
1222
set_update_iterable_lock_held(PySetObject *so, PyObject *other)
1223
32.7k
{
1224
32.7k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1225
1226
32.7k
    PyObject *it = PyObject_GetIter(other);
1227
32.7k
    if (it == NULL) {
1228
0
        return -1;
1229
0
    }
1230
1231
32.7k
    PyObject *key;
1232
193k
    while ((key = PyIter_Next(it)) != NULL) {
1233
160k
        if (set_add_key(so, key)) {
1234
0
            Py_DECREF(it);
1235
0
            Py_DECREF(key);
1236
0
            return -1;
1237
0
        }
1238
160k
        Py_DECREF(key);
1239
160k
    }
1240
32.7k
    Py_DECREF(it);
1241
32.7k
    if (PyErr_Occurred())
1242
0
        return -1;
1243
32.7k
    return 0;
1244
32.7k
}
1245
1246
static int
1247
set_update_lock_held(PySetObject *so, PyObject *other)
1248
0
{
1249
0
    if (PyAnySet_Check(other)) {
1250
0
        return set_merge_lock_held(so, other);
1251
0
    }
1252
0
    else if (PyAnyDict_CheckExact(other)) {
1253
0
        return set_update_dict_lock_held(so, other);
1254
0
    }
1255
0
    return set_update_iterable_lock_held(so, other);
1256
0
}
1257
1258
// set_update for a `so` that is only visible to the current thread
1259
static int
1260
set_update_local(PySetObject *so, PyObject *other)
1261
269k
{
1262
269k
    assert(Py_REFCNT(so) == 1);
1263
269k
    if (PyAnySet_Check(other)) {
1264
250k
        int rv;
1265
250k
        Py_BEGIN_CRITICAL_SECTION(other);
1266
250k
        rv = set_merge_lock_held(so, other);
1267
250k
        Py_END_CRITICAL_SECTION();
1268
250k
        return rv;
1269
250k
    }
1270
18.8k
    else if (PyDict_CheckExact(other)) {
1271
248
        int rv;
1272
248
        Py_BEGIN_CRITICAL_SECTION(other);
1273
248
        rv = set_update_dict_lock_held(so, other);
1274
248
        Py_END_CRITICAL_SECTION();
1275
248
        return rv;
1276
248
    }
1277
18.5k
    else if (PyFrozenDict_CheckExact(other)) {
1278
0
        return set_update_dict_lock_held(so, other);
1279
0
    }
1280
18.5k
    return set_update_iterable_lock_held(so, other);
1281
269k
}
1282
1283
static int
1284
set_update_internal(PySetObject *so, PyObject *other)
1285
489k
{
1286
489k
    if (PyAnySet_Check(other)) {
1287
475k
        if (Py_Is((PyObject *)so, other)) {
1288
0
            return 0;
1289
0
        }
1290
475k
        int rv;
1291
475k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1292
475k
        rv = set_merge_lock_held(so, other);
1293
475k
        Py_END_CRITICAL_SECTION2();
1294
475k
        return rv;
1295
475k
    }
1296
14.1k
    else if (PyDict_CheckExact(other)) {
1297
0
        int rv;
1298
0
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1299
0
        rv = set_update_dict_lock_held(so, other);
1300
0
        Py_END_CRITICAL_SECTION2();
1301
0
        return rv;
1302
0
    }
1303
14.1k
    else if (PyFrozenDict_CheckExact(other)) {
1304
0
        int rv;
1305
0
        Py_BEGIN_CRITICAL_SECTION(so);
1306
0
        rv = set_update_dict_lock_held(so, other);
1307
0
        Py_END_CRITICAL_SECTION();
1308
0
        return rv;
1309
0
    }
1310
14.1k
    else {
1311
14.1k
        int rv;
1312
14.1k
        Py_BEGIN_CRITICAL_SECTION(so);
1313
14.1k
        rv = set_update_iterable_lock_held(so, other);
1314
14.1k
        Py_END_CRITICAL_SECTION();
1315
14.1k
        return rv;
1316
14.1k
    }
1317
489k
}
1318
1319
/*[clinic input]
1320
set.update
1321
    so: setobject
1322
    *others: array
1323
1324
Update the set, adding elements from all others.
1325
[clinic start generated code]*/
1326
1327
static PyObject *
1328
set_update_impl(PySetObject *so, PyObject * const *others,
1329
                Py_ssize_t others_length)
1330
/*[clinic end generated code: output=017c781c992d5c23 input=ed5d78885b076636]*/
1331
371k
{
1332
371k
    Py_ssize_t i;
1333
1334
742k
    for (i = 0; i < others_length; i++) {
1335
371k
        PyObject *other = others[i];
1336
371k
        if (set_update_internal(so, other))
1337
0
            return NULL;
1338
371k
    }
1339
371k
    Py_RETURN_NONE;
1340
371k
}
1341
1342
/* XXX Todo:
1343
   If aligned memory allocations become available, make the
1344
   set object 64 byte aligned so that most of the fields
1345
   can be retrieved or updated in a single cache line.
1346
*/
1347
1348
// Build a set/frozenset left GC-untracked; the caller must _PyObject_GC_TRACK()
1349
// it once fully built, so a half-built set is never exposed during filling.
1350
static PyObject *
1351
make_new_set_untracked(PyTypeObject *type, PyObject *iterable)
1352
1.83M
{
1353
1.83M
    assert(PyType_Check(type));
1354
1.83M
    PySetObject *so;
1355
1356
1.83M
    so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
1357
1.83M
    if (so == NULL)
1358
0
        return NULL;
1359
1360
1.83M
    so->fill = 0;
1361
1.83M
    so->used = 0;
1362
1.83M
    so->mask = PySet_MINSIZE - 1;
1363
1.83M
    so->table = so->smalltable;
1364
1.83M
    so->hash = -1;
1365
1.83M
    so->finger = 0;
1366
1.83M
    so->weakreflist = NULL;
1367
1368
1.83M
    if (iterable != NULL) {
1369
269k
        if (set_update_local(so, iterable)) {
1370
0
            Py_DECREF(so);
1371
0
            return NULL;
1372
0
        }
1373
269k
    }
1374
1375
1.83M
    return (PyObject *)so;
1376
1.83M
}
1377
1378
static PyObject *
1379
make_new_set(PyTypeObject *type, PyObject *iterable)
1380
1.83M
{
1381
1.83M
    PyObject *so = make_new_set_untracked(type, iterable);
1382
1.83M
    if (so != NULL) {
1383
1.83M
        _PyObject_GC_TRACK(so);
1384
1.83M
    }
1385
1.83M
    return so;
1386
1.83M
}
1387
1388
static PyObject *
1389
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
1390
1.20k
{
1391
1.20k
    if (type != &PySet_Type && type != &PyFrozenSet_Type) {
1392
0
        if (PyType_IsSubtype(type, &PySet_Type))
1393
0
            type = &PySet_Type;
1394
0
        else
1395
0
            type = &PyFrozenSet_Type;
1396
0
    }
1397
1.20k
    return make_new_set_untracked(type, iterable);
1398
1.20k
}
1399
1400
static PyObject *
1401
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1402
0
{
1403
0
    PyObject *so = make_new_set_basetype_untracked(type, iterable);
1404
0
    if (so != NULL) {
1405
0
        _PyObject_GC_TRACK(so);
1406
0
    }
1407
0
    return so;
1408
0
}
1409
1410
// gh-140232: check whether a frozenset can be untracked from the GC
1411
static void
1412
_PyFrozenSet_MaybeUntrack(PyObject *op)
1413
229k
{
1414
229k
    assert(op != NULL);
1415
    // subclasses of a frozenset can generate reference cycles, so do not untrack
1416
229k
    if (!PyFrozenSet_CheckExact(op)) {
1417
0
        return;
1418
0
    }
1419
    // if no elements of a frozenset are tracked by the GC, we untrack the object
1420
229k
    Py_ssize_t pos = 0;
1421
229k
    setentry *entry;
1422
252k
    while (set_next((PySetObject *)op, &pos, &entry)) {
1423
91.0k
        if (_PyObject_GC_MAY_BE_TRACKED(entry->key)) {
1424
68.6k
            return;
1425
68.6k
        }
1426
91.0k
    }
1427
161k
    _PyObject_GC_UNTRACK(op);
1428
161k
}
1429
1430
static PyObject *
1431
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
1432
224k
{
1433
224k
    if (type != &PyFrozenSet_Type) {
1434
0
        return make_new_set(type, iterable);
1435
0
    }
1436
1437
224k
    if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
1438
        /* frozenset(f) is idempotent */
1439
0
        return Py_NewRef(iterable);
1440
0
    }
1441
224k
    PyObject *obj = make_new_set(type, iterable);
1442
224k
    if (obj != NULL) {
1443
224k
        _PyFrozenSet_MaybeUntrack(obj);
1444
224k
    }
1445
224k
    return obj;
1446
224k
}
1447
1448
static PyObject *
1449
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1450
0
{
1451
0
    PyObject *iterable = NULL;
1452
1453
0
    if ((type == &PyFrozenSet_Type ||
1454
0
         type->tp_init == PyFrozenSet_Type.tp_init) &&
1455
0
        !_PyArg_NoKeywords("frozenset", kwds)) {
1456
0
        return NULL;
1457
0
    }
1458
1459
0
    if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) {
1460
0
        return NULL;
1461
0
    }
1462
1463
0
    return make_new_frozenset(type, iterable);
1464
0
}
1465
1466
static PyObject *
1467
frozenset_vectorcall(PyObject *type, PyObject * const*args,
1468
                     size_t nargsf, PyObject *kwnames)
1469
224k
{
1470
224k
    if (!_PyArg_NoKwnames("frozenset", kwnames)) {
1471
0
        return NULL;
1472
0
    }
1473
1474
224k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1475
224k
    if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
1476
0
        return NULL;
1477
0
    }
1478
1479
224k
    PyObject *iterable = (nargs ? args[0] : NULL);
1480
224k
    return make_new_frozenset(_PyType_CAST(type), iterable);
1481
224k
}
1482
1483
static PyObject *
1484
set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1485
0
{
1486
0
    return make_new_set(type, NULL);
1487
0
}
1488
1489
#ifdef Py_GIL_DISABLED
1490
static void
1491
copy_small_table(setentry *dest, setentry *src)
1492
{
1493
    for (Py_ssize_t i = 0; i < PySet_MINSIZE; i++) {
1494
        _Py_atomic_store_ptr_release(&dest[i].key, src[i].key);
1495
        _Py_atomic_store_ssize_relaxed(&dest[i].hash, src[i].hash);
1496
    }
1497
}
1498
#endif
1499
1500
/* set_swap_bodies() switches the contents of any two sets by moving their
1501
   internal data pointers and, if needed, copying the internal smalltables.
1502
   Semantically equivalent to:
1503
1504
     t=set(a); a.clear(); a.update(b); b.clear(); b.update(t); del t
1505
1506
   The function always succeeds and it leaves both objects in a stable state.
1507
   Useful for operations that update in-place (by allowing an intermediate
1508
   result to be swapped into one of the original inputs).
1509
*/
1510
1511
static void
1512
set_swap_bodies(PySetObject *a, PySetObject *b)
1513
{
1514
    Py_ssize_t t;
1515
    setentry *u;
1516
    setentry tab[PySet_MINSIZE];
1517
    Py_hash_t h;
1518
1519
    setentry *a_table = a->table;
1520
    setentry *b_table = b->table;
1521
    FT_ATOMIC_STORE_PTR_RELEASE(a->table, NULL);
1522
    FT_ATOMIC_STORE_PTR_RELEASE(b->table, NULL);
1523
1524
    t = a->fill;     a->fill   = b->fill;        b->fill  = t;
1525
    t = a->used;
1526
    FT_ATOMIC_STORE_SSIZE_RELAXED(a->used, b->used);
1527
    FT_ATOMIC_STORE_SSIZE_RELAXED(b->used, t);
1528
    t = a->mask;
1529
    FT_ATOMIC_STORE_SSIZE_RELEASE(a->mask, b->mask);
1530
    FT_ATOMIC_STORE_SSIZE_RELEASE(b->mask, t);
1531
1532
    u = a_table;
1533
    if (a_table == a->smalltable)
1534
        u = b->smalltable;
1535
    a_table  = b_table;
1536
    if (b_table == b->smalltable)
1537
        a_table = a->smalltable;
1538
    b_table = u;
1539
1540
    if (a_table == a->smalltable || b_table == b->smalltable) {
1541
        memcpy(tab, a->smalltable, sizeof(tab));
1542
#ifndef Py_GIL_DISABLED
1543
        memcpy(a->smalltable, b->smalltable, sizeof(tab));
1544
        memcpy(b->smalltable, tab, sizeof(tab));
1545
#else
1546
        copy_small_table(a->smalltable, b->smalltable);
1547
        copy_small_table(b->smalltable, tab);
1548
#endif
1549
    }
1550
1551
    if (PyType_IsSubtype(Py_TYPE(a), &PyFrozenSet_Type)  &&
1552
        PyType_IsSubtype(Py_TYPE(b), &PyFrozenSet_Type)) {
1553
        h = FT_ATOMIC_LOAD_SSIZE_RELAXED(a->hash);
1554
        FT_ATOMIC_STORE_SSIZE_RELAXED(a->hash, FT_ATOMIC_LOAD_SSIZE_RELAXED(b->hash));
1555
        FT_ATOMIC_STORE_SSIZE_RELAXED(b->hash, h);
1556
    } else {
1557
        FT_ATOMIC_STORE_SSIZE_RELAXED(a->hash, -1);
1558
        FT_ATOMIC_STORE_SSIZE_RELAXED(b->hash, -1);
1559
    }
1560
    if (!SET_IS_SHARED(b) && SET_IS_SHARED(a)) {
1561
        SET_MARK_SHARED(b);
1562
    }
1563
    if (!SET_IS_SHARED(a) && SET_IS_SHARED(b)) {
1564
        SET_MARK_SHARED(a);
1565
    }
1566
    FT_ATOMIC_STORE_PTR_RELEASE(a->table, a_table);
1567
    FT_ATOMIC_STORE_PTR_RELEASE(b->table, b_table);
1568
}
1569
1570
PyObject *
1571
_PySet_Freeze(PyObject *set)
1572
148
{
1573
148
    assert(set != NULL);
1574
148
    assert(PySet_CheckExact(set));
1575
148
    assert(_PyObject_IsUniquelyReferenced(set));
1576
148
    set->ob_type = &PyFrozenSet_Type;
1577
148
    return Py_NewRef(set);
1578
148
}
1579
1580
static PyObject *
1581
set_copy_untracked_lock_held(PySetObject *so)
1582
942
{
1583
942
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1584
942
    PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1585
942
    if (copy == NULL) {
1586
0
        return NULL;
1587
0
    }
1588
942
    if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
1589
0
        Py_DECREF(copy);
1590
0
        return NULL;
1591
0
    }
1592
942
    return copy;
1593
942
}
1594
1595
/*[clinic input]
1596
@critical_section
1597
set.copy
1598
    so: setobject
1599
1600
Return a shallow copy of a set.
1601
[clinic start generated code]*/
1602
1603
static PyObject *
1604
set_copy_impl(PySetObject *so)
1605
/*[clinic end generated code: output=c9223a1e1cc6b041 input=c169a4fbb8209257]*/
1606
922
{
1607
922
    PyObject *copy = set_copy_untracked_lock_held(so);
1608
922
    if (copy != NULL) {
1609
922
        _PyObject_GC_TRACK(copy);
1610
922
    }
1611
922
    return copy;
1612
922
}
1613
1614
/*[clinic input]
1615
@critical_section
1616
frozenset.copy
1617
    so: setobject
1618
1619
Return a shallow copy of a set.
1620
[clinic start generated code]*/
1621
1622
static PyObject *
1623
frozenset_copy_impl(PySetObject *so)
1624
/*[clinic end generated code: output=b356263526af9e70 input=fbf5bef131268dd7]*/
1625
0
{
1626
0
    if (PyFrozenSet_CheckExact(so)) {
1627
0
        return Py_NewRef(so);
1628
0
    }
1629
0
    return set_copy_impl(so);
1630
0
}
1631
1632
/*[clinic input]
1633
@critical_section
1634
set.clear
1635
    so: setobject
1636
1637
Remove all elements from this set.
1638
[clinic start generated code]*/
1639
1640
static PyObject *
1641
set_clear_impl(PySetObject *so)
1642
/*[clinic end generated code: output=4e71d5a83904161a input=c6f831b366111950]*/
1643
9.13k
{
1644
9.13k
    set_clear_internal((PyObject*)so);
1645
9.13k
    Py_RETURN_NONE;
1646
9.13k
}
1647
1648
/*[clinic input]
1649
set.union
1650
    so: setobject
1651
    *others: array
1652
1653
Return a new set with elements from the set and all others.
1654
[clinic start generated code]*/
1655
1656
static PyObject *
1657
set_union_impl(PySetObject *so, PyObject * const *others,
1658
               Py_ssize_t others_length)
1659
/*[clinic end generated code: output=b1bfa3d74065f27e input=55a2e81db6347a4f]*/
1660
4
{
1661
4
    PySetObject *result;
1662
4
    PyObject *other;
1663
4
    Py_ssize_t i;
1664
1665
4
    result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so),
1666
4
                                                            (PyObject *)so);
1667
4
    if (result == NULL)
1668
0
        return NULL;
1669
1670
8
    for (i = 0; i < others_length; i++) {
1671
4
        other = others[i];
1672
4
        if ((PyObject *)so == other)
1673
0
            continue;
1674
4
        if (set_update_local(result, other)) {
1675
0
            Py_DECREF(result);
1676
0
            return NULL;
1677
0
        }
1678
4
    }
1679
4
    _PyObject_GC_TRACK(result);
1680
4
    return (PyObject *)result;
1681
4
}
1682
1683
static PyObject *
1684
set_or(PyObject *self, PyObject *other)
1685
69
{
1686
69
    PySetObject *result;
1687
1688
69
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1689
0
        Py_RETURN_NOTIMPLEMENTED;
1690
1691
69
    result = (PySetObject *)set_copy(self, NULL);
1692
69
    if (result == NULL) {
1693
0
        return NULL;
1694
0
    }
1695
69
    if (Py_Is(self, other)) {
1696
0
        return (PyObject *)result;
1697
0
    }
1698
69
    if (set_update_local(result, other)) {
1699
0
        Py_DECREF(result);
1700
0
        return NULL;
1701
0
    }
1702
69
    return (PyObject *)result;
1703
69
}
1704
1705
static PyObject *
1706
set_ior(PyObject *self, PyObject *other)
1707
30.7k
{
1708
30.7k
    if (!PyAnySet_Check(other))
1709
0
        Py_RETURN_NOTIMPLEMENTED;
1710
30.7k
    PySetObject *so = _PySet_CAST(self);
1711
1712
30.7k
    if (set_update_internal(so, other)) {
1713
0
        return NULL;
1714
0
    }
1715
30.7k
    return Py_NewRef(so);
1716
30.7k
}
1717
1718
static PyObject *
1719
set_intersection(PySetObject *so, PyObject *other)
1720
260
{
1721
260
    PySetObject *result;
1722
260
    PyObject *key, *it, *tmp;
1723
260
    Py_hash_t hash;
1724
260
    int rv;
1725
1726
260
    if ((PyObject *)so == other)
1727
0
        return set_copy_impl(so);
1728
1729
260
    result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1730
260
    if (result == NULL)
1731
0
        return NULL;
1732
1733
260
    if (PyAnySet_Check(other)) {
1734
248
        Py_ssize_t pos = 0;
1735
248
        setentry *entry;
1736
1737
248
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1738
162
            tmp = (PyObject *)so;
1739
162
            so = (PySetObject *)other;
1740
162
            other = tmp;
1741
162
        }
1742
1743
420
        while (set_next((PySetObject *)other, &pos, &entry)) {
1744
172
            key = entry->key;
1745
172
            hash = entry->hash;
1746
172
            Py_INCREF(key);
1747
172
            rv = set_contains_entry(so, key, hash);
1748
172
            if (rv < 0) {
1749
0
                Py_DECREF(result);
1750
0
                Py_DECREF(key);
1751
0
                return NULL;
1752
0
            }
1753
172
            if (rv) {
1754
0
                if (set_add_entry(result, key, hash)) {
1755
0
                    Py_DECREF(result);
1756
0
                    Py_DECREF(key);
1757
0
                    return NULL;
1758
0
                }
1759
0
            }
1760
172
            Py_DECREF(key);
1761
172
        }
1762
248
        _PyObject_GC_TRACK(result);
1763
248
        return (PyObject *)result;
1764
248
    }
1765
1766
12
    it = PyObject_GetIter(other);
1767
12
    if (it == NULL) {
1768
0
        Py_DECREF(result);
1769
0
        return NULL;
1770
0
    }
1771
1772
124
    while ((key = PyIter_Next(it)) != NULL) {
1773
116
        hash = PyObject_Hash(key);
1774
116
        if (hash == -1)
1775
0
            goto error;
1776
116
        rv = set_contains_entry(so, key, hash);
1777
116
        if (rv < 0)
1778
0
            goto error;
1779
116
        if (rv) {
1780
116
            if (set_add_entry(result, key, hash))
1781
0
                goto error;
1782
116
            if (PySet_GET_SIZE(result) >= PySet_GET_SIZE(so)) {
1783
4
                Py_DECREF(key);
1784
4
                break;
1785
4
            }
1786
116
        }
1787
112
        Py_DECREF(key);
1788
112
    }
1789
12
    Py_DECREF(it);
1790
12
    if (PyErr_Occurred()) {
1791
0
        Py_DECREF(result);
1792
0
        return NULL;
1793
0
    }
1794
12
    _PyObject_GC_TRACK(result);
1795
12
    return (PyObject *)result;
1796
0
  error:
1797
0
    Py_DECREF(it);
1798
0
    Py_DECREF(result);
1799
0
    Py_DECREF(key);
1800
0
    return NULL;
1801
12
}
1802
1803
/*[clinic input]
1804
set.intersection as set_intersection_multi
1805
    so: setobject
1806
    *others: array
1807
1808
Return a new set with elements common to the set and all others.
1809
[clinic start generated code]*/
1810
1811
static PyObject *
1812
set_intersection_multi_impl(PySetObject *so, PyObject * const *others,
1813
                            Py_ssize_t others_length)
1814
/*[clinic end generated code: output=db9ff9f875132b6b input=36c7b615694cadae]*/
1815
8
{
1816
8
    Py_ssize_t i;
1817
1818
8
    if (others_length == 0) {
1819
0
        return set_copy((PyObject *)so, NULL);
1820
0
    }
1821
1822
8
    PyObject *result = Py_NewRef(so);
1823
16
    for (i = 0; i < others_length; i++) {
1824
8
        PyObject *other = others[i];
1825
8
        PyObject *newresult;
1826
8
        Py_BEGIN_CRITICAL_SECTION2(result, other);
1827
8
        newresult = set_intersection((PySetObject *)result, other);
1828
8
        Py_END_CRITICAL_SECTION2();
1829
8
        if (newresult == NULL) {
1830
0
            Py_DECREF(result);
1831
0
            return NULL;
1832
0
        }
1833
8
        Py_SETREF(result, newresult);
1834
8
    }
1835
8
    return result;
1836
8
}
1837
1838
static PyObject *
1839
set_intersection_update(PySetObject *so, PyObject *other)
1840
0
{
1841
0
    PyObject *tmp;
1842
1843
0
    tmp = set_intersection(so, other);
1844
0
    if (tmp == NULL)
1845
0
        return NULL;
1846
0
    set_swap_bodies(so, (PySetObject *)tmp);
1847
0
    Py_DECREF(tmp);
1848
0
    Py_RETURN_NONE;
1849
0
}
1850
1851
/*[clinic input]
1852
set.intersection_update as set_intersection_update_multi
1853
    so: setobject
1854
    *others: array
1855
1856
Update the set, keeping only elements found in it and all others.
1857
[clinic start generated code]*/
1858
1859
static PyObject *
1860
set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others,
1861
                                   Py_ssize_t others_length)
1862
/*[clinic end generated code: output=d768b5584675b48d input=782e422fc370e4fc]*/
1863
0
{
1864
0
    PyObject *tmp;
1865
1866
0
    tmp = set_intersection_multi_impl(so, others, others_length);
1867
0
    if (tmp == NULL)
1868
0
        return NULL;
1869
0
    Py_BEGIN_CRITICAL_SECTION(so);
1870
0
    set_swap_bodies(so, (PySetObject *)tmp);
1871
0
    Py_END_CRITICAL_SECTION();
1872
0
    Py_DECREF(tmp);
1873
0
    Py_RETURN_NONE;
1874
0
}
1875
1876
static PyObject *
1877
set_and(PyObject *self, PyObject *other)
1878
248
{
1879
248
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1880
0
        Py_RETURN_NOTIMPLEMENTED;
1881
248
    PySetObject *so = _PySet_CAST(self);
1882
1883
248
    PyObject *rv;
1884
248
    Py_BEGIN_CRITICAL_SECTION2(so, other);
1885
248
    rv = set_intersection(so, other);
1886
248
    Py_END_CRITICAL_SECTION2();
1887
1888
248
    return rv;
1889
248
}
1890
1891
static PyObject *
1892
set_iand(PyObject *self, PyObject *other)
1893
0
{
1894
0
    PyObject *result;
1895
1896
0
    if (!PyAnySet_Check(other))
1897
0
        Py_RETURN_NOTIMPLEMENTED;
1898
0
    PySetObject *so = _PySet_CAST(self);
1899
1900
0
    Py_BEGIN_CRITICAL_SECTION2(so, other);
1901
0
    result = set_intersection_update(so, other);
1902
0
    Py_END_CRITICAL_SECTION2();
1903
1904
0
    if (result == NULL)
1905
0
        return NULL;
1906
0
    Py_DECREF(result);
1907
0
    return Py_NewRef(so);
1908
0
}
1909
1910
/*[clinic input]
1911
@critical_section so other
1912
set.isdisjoint
1913
    so: setobject
1914
    other: object
1915
    /
1916
1917
Return True if two sets have a null intersection.
1918
[clinic start generated code]*/
1919
1920
static PyObject *
1921
set_isdisjoint_impl(PySetObject *so, PyObject *other)
1922
/*[clinic end generated code: output=273493f2d57c565e input=32f8dcab5e0fc7d6]*/
1923
16.4k
{
1924
16.4k
    PyObject *key, *it, *tmp;
1925
16.4k
    int rv;
1926
1927
16.4k
    if ((PyObject *)so == other) {
1928
0
        if (PySet_GET_SIZE(so) == 0)
1929
0
            Py_RETURN_TRUE;
1930
0
        else
1931
0
            Py_RETURN_FALSE;
1932
0
    }
1933
1934
16.4k
    if (PyAnySet_CheckExact(other)) {
1935
36
        Py_ssize_t pos = 0;
1936
36
        setentry *entry;
1937
1938
36
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1939
4
            tmp = (PyObject *)so;
1940
4
            so = (PySetObject *)other;
1941
4
            other = tmp;
1942
4
        }
1943
36
        while (set_next((PySetObject *)other, &pos, &entry)) {
1944
0
            PyObject *key = entry->key;
1945
0
            Py_INCREF(key);
1946
0
            rv = set_contains_entry(so, key, entry->hash);
1947
0
            Py_DECREF(key);
1948
0
            if (rv < 0) {
1949
0
                return NULL;
1950
0
            }
1951
0
            if (rv) {
1952
0
                Py_RETURN_FALSE;
1953
0
            }
1954
0
        }
1955
36
        Py_RETURN_TRUE;
1956
36
    }
1957
1958
16.3k
    it = PyObject_GetIter(other);
1959
16.3k
    if (it == NULL)
1960
0
        return NULL;
1961
1962
24.6k
    while ((key = PyIter_Next(it)) != NULL) {
1963
24.4k
        rv = set_contains_key(so, key);
1964
24.4k
        Py_DECREF(key);
1965
24.4k
        if (rv < 0) {
1966
0
            Py_DECREF(it);
1967
0
            return NULL;
1968
0
        }
1969
24.4k
        if (rv) {
1970
16.2k
            Py_DECREF(it);
1971
16.2k
            Py_RETURN_FALSE;
1972
16.2k
        }
1973
24.4k
    }
1974
154
    Py_DECREF(it);
1975
154
    if (PyErr_Occurred())
1976
0
        return NULL;
1977
154
    Py_RETURN_TRUE;
1978
154
}
1979
1980
static int
1981
set_difference_update_internal(PySetObject *so, PyObject *other)
1982
76
{
1983
76
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1984
76
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
1985
1986
76
    if ((PyObject *)so == other)
1987
0
        return set_clear_internal((PyObject*)so);
1988
1989
76
    if (PyAnySet_Check(other)) {
1990
76
        setentry *entry;
1991
76
        Py_ssize_t pos = 0;
1992
1993
        /* Optimization:  When the other set is more than 8 times
1994
           larger than the base set, replace the other set with
1995
           intersection of the two sets.
1996
        */
1997
76
        if ((PySet_GET_SIZE(other) >> 3) > PySet_GET_SIZE(so)) {
1998
0
            other = set_intersection(so, other);
1999
0
            if (other == NULL)
2000
0
                return -1;
2001
76
        } else {
2002
76
            Py_INCREF(other);
2003
76
        }
2004
2005
113
        while (set_next((PySetObject *)other, &pos, &entry)) {
2006
37
            PyObject *key = entry->key;
2007
37
            Py_INCREF(key);
2008
37
            if (set_discard_entry(so, key, entry->hash) < 0) {
2009
0
                Py_DECREF(other);
2010
0
                Py_DECREF(key);
2011
0
                return -1;
2012
0
            }
2013
37
            Py_DECREF(key);
2014
37
        }
2015
2016
76
        Py_DECREF(other);
2017
76
    } else {
2018
0
        PyObject *key, *it;
2019
0
        it = PyObject_GetIter(other);
2020
0
        if (it == NULL)
2021
0
            return -1;
2022
2023
0
        while ((key = PyIter_Next(it)) != NULL) {
2024
0
            if (set_discard_key(so, key) < 0) {
2025
0
                Py_DECREF(it);
2026
0
                Py_DECREF(key);
2027
0
                return -1;
2028
0
            }
2029
0
            Py_DECREF(key);
2030
0
        }
2031
0
        Py_DECREF(it);
2032
0
        if (PyErr_Occurred())
2033
0
            return -1;
2034
0
    }
2035
    /* If more than 1/4th are dummies, then resize them away. */
2036
76
    if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4)
2037
76
        return 0;
2038
0
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
2039
76
}
2040
2041
/*[clinic input]
2042
set.difference_update
2043
    so: setobject
2044
    *others: array
2045
2046
Update the set, removing elements found in others.
2047
[clinic start generated code]*/
2048
2049
static PyObject *
2050
set_difference_update_impl(PySetObject *so, PyObject * const *others,
2051
                           Py_ssize_t others_length)
2052
/*[clinic end generated code: output=04a22179b322cfe6 input=93ac28ba5b233696]*/
2053
0
{
2054
0
    Py_ssize_t i;
2055
2056
0
    for (i = 0; i < others_length; i++) {
2057
0
        PyObject *other = others[i];
2058
0
        int rv;
2059
0
        Py_BEGIN_CRITICAL_SECTION2(so, other);
2060
0
        rv = set_difference_update_internal(so, other);
2061
0
        Py_END_CRITICAL_SECTION2();
2062
0
        if (rv) {
2063
0
            return NULL;
2064
0
        }
2065
0
    }
2066
0
    Py_RETURN_NONE;
2067
0
}
2068
2069
static PyObject *
2070
set_copy_and_difference_untracked(PySetObject *so, PyObject *other)
2071
20
{
2072
20
    PyObject *result;
2073
2074
20
    result = set_copy_untracked_lock_held(so);
2075
20
    if (result == NULL)
2076
0
        return NULL;
2077
20
    if (set_difference_update_internal((PySetObject *) result, other) == 0)
2078
20
        return result;
2079
0
    Py_DECREF(result);
2080
0
    return NULL;
2081
20
}
2082
2083
static PyObject *
2084
set_difference_untracked(PySetObject *so, PyObject *other)
2085
22
{
2086
22
    PyObject *result;
2087
22
    PyObject *key;
2088
22
    Py_hash_t hash;
2089
22
    setentry *entry;
2090
22
    Py_ssize_t pos = 0, other_size;
2091
22
    int rv;
2092
2093
22
    if (PyAnySet_Check(other)) {
2094
22
        other_size = PySet_GET_SIZE(other);
2095
22
    }
2096
0
    else if (PyAnyDict_CheckExact(other)) {
2097
0
        other_size = PyDict_GET_SIZE(other);
2098
0
    }
2099
0
    else {
2100
0
        return set_copy_and_difference_untracked(so, other);
2101
0
    }
2102
2103
    /* If len(so) much more than len(other), it's more efficient to simply copy
2104
     * so and then iterate other looking for common elements. */
2105
22
    if ((PySet_GET_SIZE(so) >> 2) > other_size) {
2106
20
        return set_copy_and_difference_untracked(so, other);
2107
20
    }
2108
2109
2
    result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
2110
2
    if (result == NULL)
2111
0
        return NULL;
2112
2113
2
    if (PyAnyDict_CheckExact(other)) {
2114
0
        while (set_next(so, &pos, &entry)) {
2115
0
            key = entry->key;
2116
0
            hash = entry->hash;
2117
0
            Py_INCREF(key);
2118
0
            rv = _PyDict_Contains_KnownHash(other, key, hash);
2119
0
            if (rv < 0) {
2120
0
                Py_DECREF(result);
2121
0
                Py_DECREF(key);
2122
0
                return NULL;
2123
0
            }
2124
0
            if (!rv) {
2125
0
                if (set_add_entry((PySetObject *)result, key, hash)) {
2126
0
                    Py_DECREF(result);
2127
0
                    Py_DECREF(key);
2128
0
                    return NULL;
2129
0
                }
2130
0
            }
2131
0
            Py_DECREF(key);
2132
0
        }
2133
0
        return result;
2134
0
    }
2135
2136
    /* Iterate over so, checking for common elements in other. */
2137
28
    while (set_next(so, &pos, &entry)) {
2138
26
        key = entry->key;
2139
26
        hash = entry->hash;
2140
26
        Py_INCREF(key);
2141
26
        rv = set_contains_entry((PySetObject *)other, key, hash);
2142
26
        if (rv < 0) {
2143
0
            Py_DECREF(result);
2144
0
            Py_DECREF(key);
2145
0
            return NULL;
2146
0
        }
2147
26
        if (!rv) {
2148
20
            if (set_add_entry((PySetObject *)result, key, hash)) {
2149
0
                Py_DECREF(result);
2150
0
                Py_DECREF(key);
2151
0
                return NULL;
2152
0
            }
2153
20
        }
2154
26
        Py_DECREF(key);
2155
26
    }
2156
2
    return result;
2157
2
}
2158
2159
/*[clinic input]
2160
@permit_long_summary
2161
set.difference as set_difference_multi
2162
    so: setobject
2163
    *others: array
2164
2165
Return a new set with elements in the set that are not in the others.
2166
[clinic start generated code]*/
2167
2168
static PyObject *
2169
set_difference_multi_impl(PySetObject *so, PyObject * const *others,
2170
                          Py_ssize_t others_length)
2171
/*[clinic end generated code: output=b0d33fb05d5477a7 input=e0fbedbf79d91d4e]*/
2172
0
{
2173
0
    Py_ssize_t i;
2174
0
    PyObject *result, *other;
2175
2176
0
    if (others_length == 0) {
2177
0
        return set_copy((PyObject *)so, NULL);
2178
0
    }
2179
2180
0
    other = others[0];
2181
0
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2182
0
    result = set_difference_untracked(so, other);
2183
0
    Py_END_CRITICAL_SECTION2();
2184
0
    if (result == NULL)
2185
0
        return NULL;
2186
2187
0
    for (i = 1; i < others_length; i++) {
2188
0
        other = others[i];
2189
0
        int rv;
2190
0
        Py_BEGIN_CRITICAL_SECTION(other);
2191
0
        rv = set_difference_update_internal((PySetObject *)result, other);
2192
0
        Py_END_CRITICAL_SECTION();
2193
0
        if (rv) {
2194
0
            Py_DECREF(result);
2195
0
            return NULL;
2196
0
        }
2197
0
    }
2198
0
    _PyObject_GC_TRACK(result);
2199
0
    return result;
2200
0
}
2201
2202
static PyObject *
2203
set_sub(PyObject *self, PyObject *other)
2204
22
{
2205
22
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
2206
0
        Py_RETURN_NOTIMPLEMENTED;
2207
22
    PySetObject *so = _PySet_CAST(self);
2208
2209
22
    PyObject *rv;
2210
22
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2211
22
    rv = set_difference_untracked(so, other);
2212
22
    Py_END_CRITICAL_SECTION2();
2213
22
    if (rv != NULL) {
2214
22
        _PyObject_GC_TRACK(rv);
2215
22
    }
2216
22
    return rv;
2217
22
}
2218
2219
static PyObject *
2220
set_isub(PyObject *self, PyObject *other)
2221
56
{
2222
56
    if (!PyAnySet_Check(other))
2223
0
        Py_RETURN_NOTIMPLEMENTED;
2224
56
    PySetObject *so = _PySet_CAST(self);
2225
2226
56
    int rv;
2227
56
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2228
56
    rv = set_difference_update_internal(so, other);
2229
56
    Py_END_CRITICAL_SECTION2();
2230
56
    if (rv < 0) {
2231
0
        return NULL;
2232
0
    }
2233
56
    return Py_NewRef(so);
2234
56
}
2235
2236
static int
2237
set_symmetric_difference_update_dict(PySetObject *so, PyObject *other)
2238
0
{
2239
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
2240
#ifdef Py_DEBUG
2241
    if (!PyFrozenDict_CheckExact(other)) {
2242
        _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
2243
    }
2244
#endif
2245
2246
0
    Py_ssize_t pos = 0;
2247
0
    PyObject *key, *value;
2248
0
    Py_hash_t hash;
2249
0
    while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
2250
0
        Py_INCREF(key);
2251
0
        int rv = set_discard_entry(so, key, hash);
2252
0
        if (rv < 0) {
2253
0
            Py_DECREF(key);
2254
0
            return -1;
2255
0
        }
2256
0
        if (rv == DISCARD_NOTFOUND) {
2257
0
            if (set_add_entry(so, key, hash)) {
2258
0
                Py_DECREF(key);
2259
0
                return -1;
2260
0
            }
2261
0
        }
2262
0
        Py_DECREF(key);
2263
0
    }
2264
0
    return 0;
2265
0
}
2266
2267
static int
2268
set_symmetric_difference_update_set(PySetObject *so, PySetObject *other)
2269
0
{
2270
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
2271
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
2272
2273
0
    Py_ssize_t pos = 0;
2274
0
    setentry *entry;
2275
0
    while (set_next(other, &pos, &entry)) {
2276
0
        PyObject *key = Py_NewRef(entry->key);
2277
0
        Py_hash_t hash = entry->hash;
2278
0
        int rv = set_discard_entry(so, key, hash);
2279
0
        if (rv < 0) {
2280
0
            Py_DECREF(key);
2281
0
            return -1;
2282
0
        }
2283
0
        if (rv == DISCARD_NOTFOUND) {
2284
0
            if (set_add_entry(so, key, hash)) {
2285
0
                Py_DECREF(key);
2286
0
                return -1;
2287
0
            }
2288
0
        }
2289
0
        Py_DECREF(key);
2290
0
    }
2291
0
    return 0;
2292
0
}
2293
2294
/*[clinic input]
2295
@permit_long_summary
2296
set.symmetric_difference_update
2297
    so: setobject
2298
    other: object
2299
    /
2300
2301
Update the set, keeping only elements found in either set, but not in both.
2302
[clinic start generated code]*/
2303
2304
static PyObject *
2305
set_symmetric_difference_update_impl(PySetObject *so, PyObject *other)
2306
/*[clinic end generated code: output=79f80b4ee5da66c1 input=86a3dddac9bfb15e]*/
2307
0
{
2308
0
    if (Py_Is((PyObject *)so, other)) {
2309
0
        return set_clear((PyObject *)so, NULL);
2310
0
    }
2311
2312
0
    int rv;
2313
0
    if (PyDict_CheckExact(other)) {
2314
0
        Py_BEGIN_CRITICAL_SECTION2(so, other);
2315
0
        rv = set_symmetric_difference_update_dict(so, other);
2316
0
        Py_END_CRITICAL_SECTION2();
2317
0
    }
2318
0
    else if (PyFrozenDict_CheckExact(other)) {
2319
0
        Py_BEGIN_CRITICAL_SECTION(so);
2320
0
        rv = set_symmetric_difference_update_dict(so, other);
2321
0
        Py_END_CRITICAL_SECTION();
2322
0
    }
2323
0
    else if (PyAnySet_Check(other)) {
2324
0
        Py_BEGIN_CRITICAL_SECTION2(so, other);
2325
0
        rv = set_symmetric_difference_update_set(so, (PySetObject *)other);
2326
0
        Py_END_CRITICAL_SECTION2();
2327
0
    }
2328
0
    else {
2329
0
        PySetObject *otherset = (PySetObject *)make_new_set_basetype(Py_TYPE(so), other);
2330
0
        if (otherset == NULL) {
2331
0
            return NULL;
2332
0
        }
2333
2334
0
        Py_BEGIN_CRITICAL_SECTION(so);
2335
0
        rv = set_symmetric_difference_update_set(so, otherset);
2336
0
        Py_END_CRITICAL_SECTION();
2337
2338
0
        Py_DECREF(otherset);
2339
0
    }
2340
0
    if (rv < 0) {
2341
0
        return NULL;
2342
0
    }
2343
0
    Py_RETURN_NONE;
2344
0
}
2345
2346
/*[clinic input]
2347
@permit_long_summary
2348
@critical_section so other
2349
set.symmetric_difference
2350
    so: setobject
2351
    other: object
2352
    /
2353
2354
Return a new set with elements in either the set or other but not both.
2355
[clinic start generated code]*/
2356
2357
static PyObject *
2358
set_symmetric_difference_impl(PySetObject *so, PyObject *other)
2359
/*[clinic end generated code: output=270ee0b5d42b0797 input=8c29b0be90d47feb]*/
2360
0
{
2361
0
    PySetObject *result =
2362
0
        (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
2363
0
    if (result == NULL) {
2364
0
        return NULL;
2365
0
    }
2366
0
    if (set_update_lock_held(result, other) < 0) {
2367
0
        Py_DECREF(result);
2368
0
        return NULL;
2369
0
    }
2370
0
    if (set_symmetric_difference_update_set(result, so) < 0) {
2371
0
        Py_DECREF(result);
2372
0
        return NULL;
2373
0
    }
2374
0
    _PyObject_GC_TRACK(result);
2375
0
    return (PyObject *)result;
2376
0
}
2377
2378
static PyObject *
2379
set_xor(PyObject *self, PyObject *other)
2380
0
{
2381
0
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
2382
0
        Py_RETURN_NOTIMPLEMENTED;
2383
0
    PySetObject *so = _PySet_CAST(self);
2384
0
    return set_symmetric_difference((PyObject*)so, other);
2385
0
}
2386
2387
static PyObject *
2388
set_ixor(PyObject *self, PyObject *other)
2389
0
{
2390
0
    PyObject *result;
2391
2392
0
    if (!PyAnySet_Check(other))
2393
0
        Py_RETURN_NOTIMPLEMENTED;
2394
0
    PySetObject *so = _PySet_CAST(self);
2395
2396
0
    result = set_symmetric_difference_update((PyObject*)so, other);
2397
0
    if (result == NULL)
2398
0
        return NULL;
2399
0
    Py_DECREF(result);
2400
0
    return Py_NewRef(so);
2401
0
}
2402
2403
/*[clinic input]
2404
@critical_section so other
2405
set.issubset
2406
    so: setobject
2407
    other: object
2408
    /
2409
2410
Report whether another set contains this set.
2411
[clinic start generated code]*/
2412
2413
static PyObject *
2414
set_issubset_impl(PySetObject *so, PyObject *other)
2415
/*[clinic end generated code: output=b2b59d5f314555ce input=f2a4fd0f2537758b]*/
2416
224k
{
2417
224k
    setentry *entry;
2418
224k
    Py_ssize_t pos = 0;
2419
224k
    int rv;
2420
2421
224k
    if (!PyAnySet_Check(other)) {
2422
4
        PyObject *tmp = set_intersection(so, other);
2423
4
        if (tmp == NULL) {
2424
0
            return NULL;
2425
0
        }
2426
4
        int result = (PySet_GET_SIZE(tmp) == PySet_GET_SIZE(so));
2427
4
        Py_DECREF(tmp);
2428
4
        return PyBool_FromLong(result);
2429
4
    }
2430
224k
    if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
2431
0
        Py_RETURN_FALSE;
2432
2433
360k
    while (set_next(so, &pos, &entry)) {
2434
135k
        PyObject *key = entry->key;
2435
135k
        Py_INCREF(key);
2436
135k
        rv = set_contains_entry((PySetObject *)other, key, entry->hash);
2437
135k
        Py_DECREF(key);
2438
135k
        if (rv < 0) {
2439
0
            return NULL;
2440
0
        }
2441
135k
        if (!rv) {
2442
0
            Py_RETURN_FALSE;
2443
0
        }
2444
135k
    }
2445
224k
    Py_RETURN_TRUE;
2446
224k
}
2447
2448
/*[clinic input]
2449
@critical_section so other
2450
set.issuperset
2451
    so: setobject
2452
    other: object
2453
    /
2454
2455
Report whether this set contains another set.
2456
[clinic start generated code]*/
2457
2458
static PyObject *
2459
set_issuperset_impl(PySetObject *so, PyObject *other)
2460
/*[clinic end generated code: output=ecf00ce552c09461 input=5f2e1f262e6e4ccc]*/
2461
376
{
2462
376
    if (PyAnySet_Check(other)) {
2463
0
        return set_issubset(other, (PyObject *)so);
2464
0
    }
2465
2466
376
    PyObject *key, *it = PyObject_GetIter(other);
2467
376
    if (it == NULL) {
2468
0
        return NULL;
2469
0
    }
2470
1.53k
    while ((key = PyIter_Next(it)) != NULL) {
2471
1.16k
        int rv = set_contains_key(so, key);
2472
1.16k
        Py_DECREF(key);
2473
1.16k
        if (rv < 0) {
2474
0
            Py_DECREF(it);
2475
0
            return NULL;
2476
0
        }
2477
1.16k
        if (!rv) {
2478
0
            Py_DECREF(it);
2479
0
            Py_RETURN_FALSE;
2480
0
        }
2481
1.16k
    }
2482
376
    Py_DECREF(it);
2483
376
    if (PyErr_Occurred()) {
2484
0
        return NULL;
2485
0
    }
2486
376
    Py_RETURN_TRUE;
2487
376
}
2488
2489
static PyObject *
2490
set_richcompare(PyObject *self, PyObject *w, int op)
2491
224k
{
2492
224k
    PySetObject *v = _PySet_CAST(self);
2493
224k
    PyObject *r1;
2494
224k
    int r2;
2495
2496
224k
    if(!PyAnySet_Check(w))
2497
0
        Py_RETURN_NOTIMPLEMENTED;
2498
2499
224k
    switch (op) {
2500
224k
    case Py_EQ:
2501
224k
        if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
2502
116
            Py_RETURN_FALSE;
2503
224k
        Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->hash);
2504
224k
        Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(((PySetObject *)w)->hash);
2505
224k
        if (v_hash != -1 && w_hash != -1 && v_hash != w_hash)
2506
0
            Py_RETURN_FALSE;
2507
224k
        return set_issubset((PyObject*)v, w);
2508
0
    case Py_NE:
2509
0
        r1 = set_richcompare((PyObject*)v, w, Py_EQ);
2510
0
        if (r1 == NULL)
2511
0
            return NULL;
2512
0
        r2 = PyObject_IsTrue(r1);
2513
0
        Py_DECREF(r1);
2514
0
        if (r2 < 0)
2515
0
            return NULL;
2516
0
        return PyBool_FromLong(!r2);
2517
136
    case Py_LE:
2518
136
        return set_issubset((PyObject*)v, w);
2519
0
    case Py_GE:
2520
0
        return set_issuperset((PyObject*)v, w);
2521
0
    case Py_LT:
2522
0
        if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w))
2523
0
            Py_RETURN_FALSE;
2524
0
        return set_issubset((PyObject*)v, w);
2525
0
    case Py_GT:
2526
0
        if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w))
2527
0
            Py_RETURN_FALSE;
2528
0
        return set_issuperset((PyObject*)v, w);
2529
224k
    }
2530
224k
    Py_RETURN_NOTIMPLEMENTED;
2531
224k
}
2532
2533
/*[clinic input]
2534
@critical_section
2535
set.add
2536
    so: setobject
2537
    object as key: object
2538
    /
2539
2540
Add an element to a set.
2541
2542
This has no effect if the element is already present.
2543
[clinic start generated code]*/
2544
2545
static PyObject *
2546
set_add_impl(PySetObject *so, PyObject *key)
2547
/*[clinic end generated code: output=4cc4a937f1425c96 input=03baf62cb0e66514]*/
2548
1.44M
{
2549
1.44M
    if (set_add_key(so, key))
2550
0
        return NULL;
2551
1.44M
    Py_RETURN_NONE;
2552
1.44M
}
2553
2554
int
2555
_PySet_Contains(PySetObject *so, PyObject *key)
2556
162M
{
2557
162M
    assert(so);
2558
2559
162M
    Py_hash_t hash = PyObject_Hash(key);
2560
162M
    if (hash == -1) {
2561
0
        if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
2562
0
            set_unhashable_type(key);
2563
0
            return -1;
2564
0
        }
2565
0
        PyErr_Clear();
2566
        // Note that 'key' could be a set() or frozenset() object.  Unlike most
2567
        // container types, set allows membership testing with a set key, even
2568
        // though it is not hashable.
2569
0
        Py_BEGIN_CRITICAL_SECTION(key);
2570
0
        hash = frozenset_hash_impl(key);
2571
0
        Py_END_CRITICAL_SECTION();
2572
0
    }
2573
162M
    return set_contains_entry(so, key, hash);
2574
162M
}
2575
2576
static int
2577
set_contains(PyObject *self, PyObject *key)
2578
919
{
2579
919
    PySetObject *so = _PySet_CAST(self);
2580
919
    return _PySet_Contains(so, key);
2581
919
}
2582
2583
/*[clinic input]
2584
@coexist
2585
set.__contains__
2586
    so: setobject
2587
    object as key: object
2588
    /
2589
2590
x.__contains__(y) <==> y in x.
2591
[clinic start generated code]*/
2592
2593
static PyObject *
2594
set___contains___impl(PySetObject *so, PyObject *key)
2595
/*[clinic end generated code: output=b44863d034b3c70e input=cf4c72db704e4cf0]*/
2596
1.90M
{
2597
1.90M
    long result;
2598
2599
1.90M
    result = _PySet_Contains(so, key);
2600
1.90M
    if (result < 0)
2601
0
        return NULL;
2602
1.90M
    return PyBool_FromLong(result);
2603
1.90M
}
2604
2605
/*[clinic input]
2606
@coexist
2607
frozenset.__contains__
2608
    so: setobject
2609
    object as key: object
2610
    /
2611
2612
x.__contains__(y) <==> y in x.
2613
[clinic start generated code]*/
2614
2615
static PyObject *
2616
frozenset___contains___impl(PySetObject *so, PyObject *key)
2617
/*[clinic end generated code: output=2301ed91bc3a6dd5 input=2f04922a98d8bab7]*/
2618
39.1k
{
2619
39.1k
    Py_hash_t hash = PyObject_Hash(key);
2620
39.1k
    if (hash == -1) {
2621
0
        if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
2622
0
            set_unhashable_type(key);
2623
0
            return NULL;
2624
0
        }
2625
0
        PyErr_Clear();
2626
0
        Py_BEGIN_CRITICAL_SECTION(key);
2627
0
        hash = frozenset_hash_impl(key);
2628
0
        Py_END_CRITICAL_SECTION();
2629
0
    }
2630
39.1k
    setentry *entry; // unused
2631
39.1k
    int status = set_do_lookup(so, so->table, so->mask, key, hash, &entry,
2632
39.1k
                           set_compare_frozenset);
2633
39.1k
    if (status < 0)
2634
0
        return NULL;
2635
39.1k
    return PyBool_FromLong(status);
2636
39.1k
}
2637
2638
/*[clinic input]
2639
@critical_section
2640
set.remove
2641
    so: setobject
2642
    object as key: object
2643
    /
2644
2645
Remove an element from a set; it must be a member.
2646
2647
If the element is not a member, raise a KeyError.
2648
[clinic start generated code]*/
2649
2650
static PyObject *
2651
set_remove_impl(PySetObject *so, PyObject *key)
2652
/*[clinic end generated code: output=0b9134a2a2200363 input=893e1cb1df98227a]*/
2653
0
{
2654
0
    int rv;
2655
2656
0
    rv = set_discard_key(so, key);
2657
0
    if (rv < 0) {
2658
0
        if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))
2659
0
            return NULL;
2660
0
        PyErr_Clear();
2661
0
        Py_hash_t hash;
2662
0
        Py_BEGIN_CRITICAL_SECTION(key);
2663
0
        hash = frozenset_hash_impl(key);
2664
0
        Py_END_CRITICAL_SECTION();
2665
0
        rv = set_discard_entry(so, key, hash);
2666
0
        if (rv < 0)
2667
0
            return NULL;
2668
0
    }
2669
2670
0
    if (rv == DISCARD_NOTFOUND) {
2671
0
        _PyErr_SetKeyError(key);
2672
0
        return NULL;
2673
0
    }
2674
0
    Py_RETURN_NONE;
2675
0
}
2676
2677
/*[clinic input]
2678
@critical_section
2679
set.discard
2680
    so: setobject
2681
    object as key: object
2682
    /
2683
2684
Remove an element from a set if it is a member.
2685
2686
Unlike set.remove(), the discard() method does not raise
2687
an exception when an element is missing from the set.
2688
[clinic start generated code]*/
2689
2690
static PyObject *
2691
set_discard_impl(PySetObject *so, PyObject *key)
2692
/*[clinic end generated code: output=eec3b687bf32759e input=861cb7fb69b4def0]*/
2693
264
{
2694
264
    int rv;
2695
2696
264
    rv = set_discard_key(so, key);
2697
264
    if (rv < 0) {
2698
0
        if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))
2699
0
            return NULL;
2700
0
        PyErr_Clear();
2701
0
        Py_hash_t hash;
2702
0
        Py_BEGIN_CRITICAL_SECTION(key);
2703
0
        hash = frozenset_hash_impl(key);
2704
0
        Py_END_CRITICAL_SECTION();
2705
0
        rv = set_discard_entry(so, key, hash);
2706
0
        if (rv < 0)
2707
0
            return NULL;
2708
0
    }
2709
264
    Py_RETURN_NONE;
2710
264
}
2711
2712
/*[clinic input]
2713
@critical_section
2714
set.__reduce__
2715
    so: setobject
2716
2717
Return state information for pickling.
2718
[clinic start generated code]*/
2719
2720
static PyObject *
2721
set___reduce___impl(PySetObject *so)
2722
/*[clinic end generated code: output=9af7d0e029df87ee input=59405a4249e82f71]*/
2723
0
{
2724
0
    PyObject *keys=NULL, *args=NULL, *result=NULL, *state=NULL;
2725
2726
0
    keys = PySequence_List((PyObject *)so);
2727
0
    if (keys == NULL)
2728
0
        goto done;
2729
0
    args = PyTuple_Pack(1, keys);
2730
0
    if (args == NULL)
2731
0
        goto done;
2732
0
    state = _PyObject_GetState((PyObject *)so);
2733
0
    if (state == NULL)
2734
0
        goto done;
2735
0
    result = PyTuple_Pack(3, Py_TYPE(so), args, state);
2736
0
done:
2737
0
    Py_XDECREF(args);
2738
0
    Py_XDECREF(keys);
2739
0
    Py_XDECREF(state);
2740
0
    return result;
2741
0
}
2742
2743
/*[clinic input]
2744
@critical_section
2745
set.__sizeof__
2746
    so: setobject
2747
2748
S.__sizeof__() -> size of S in memory, in bytes.
2749
[clinic start generated code]*/
2750
2751
static PyObject *
2752
set___sizeof___impl(PySetObject *so)
2753
/*[clinic end generated code: output=4bfa3df7bd38ed88 input=09e1a09f168eaa23]*/
2754
0
{
2755
0
    size_t res = _PyObject_SIZE(Py_TYPE(so));
2756
0
    if (so->table != so->smalltable) {
2757
0
        res += ((size_t)so->mask + 1) * sizeof(setentry);
2758
0
    }
2759
0
    return PyLong_FromSize_t(res);
2760
0
}
2761
2762
static int
2763
set_init(PyObject *so, PyObject *args, PyObject *kwds)
2764
0
{
2765
0
    PySetObject *self = _PySet_CAST(so);
2766
0
    PyObject *iterable = NULL;
2767
2768
0
    if (!_PyArg_NoKeywords("set", kwds))
2769
0
        return -1;
2770
0
    if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable))
2771
0
        return -1;
2772
2773
0
    if (_PyObject_IsUniquelyReferenced((PyObject *)self) && self->fill == 0) {
2774
0
        self->hash = -1;
2775
0
        if (iterable == NULL) {
2776
0
            return 0;
2777
0
        }
2778
0
        return set_update_local(self, iterable);
2779
0
    }
2780
0
    Py_BEGIN_CRITICAL_SECTION(self);
2781
0
    if (self->fill)
2782
0
        set_clear_internal((PyObject*)self);
2783
0
    self->hash = -1;
2784
0
    Py_END_CRITICAL_SECTION();
2785
2786
0
    if (iterable == NULL)
2787
0
        return 0;
2788
0
    return set_update_internal(self, iterable);
2789
0
}
2790
2791
static PyObject*
2792
set_vectorcall(PyObject *type, PyObject * const*args,
2793
               size_t nargsf, PyObject *kwnames)
2794
852k
{
2795
852k
    assert(PyType_Check(type));
2796
2797
852k
    if (!_PyArg_NoKwnames("set", kwnames)) {
2798
0
        return NULL;
2799
0
    }
2800
2801
852k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
2802
852k
    if (!_PyArg_CheckPositional("set", nargs, 0, 1)) {
2803
0
        return NULL;
2804
0
    }
2805
2806
852k
    if (nargs) {
2807
17.6k
        return make_new_set(_PyType_CAST(type), args[0]);
2808
17.6k
    }
2809
2810
834k
    return make_new_set(_PyType_CAST(type), NULL);
2811
852k
}
2812
2813
static PySequenceMethods set_as_sequence = {
2814
    set_len,                            /* sq_length */
2815
    0,                                  /* sq_concat */
2816
    0,                                  /* sq_repeat */
2817
    0,                                  /* sq_item */
2818
    0,                                  /* sq_slice */
2819
    0,                                  /* sq_ass_item */
2820
    0,                                  /* sq_ass_slice */
2821
    set_contains,                       /* sq_contains */
2822
};
2823
2824
/* set object ********************************************************/
2825
2826
static PyMethodDef set_methods[] = {
2827
    SET_ADD_METHODDEF
2828
    SET_CLEAR_METHODDEF
2829
    SET___CONTAINS___METHODDEF
2830
    SET_COPY_METHODDEF
2831
    SET_DISCARD_METHODDEF
2832
    SET_DIFFERENCE_MULTI_METHODDEF
2833
    SET_DIFFERENCE_UPDATE_METHODDEF
2834
    SET_INTERSECTION_MULTI_METHODDEF
2835
    SET_INTERSECTION_UPDATE_MULTI_METHODDEF
2836
    SET_ISDISJOINT_METHODDEF
2837
    SET_ISSUBSET_METHODDEF
2838
    SET_ISSUPERSET_METHODDEF
2839
    SET_POP_METHODDEF
2840
    SET___REDUCE___METHODDEF
2841
    SET_REMOVE_METHODDEF
2842
    SET___SIZEOF___METHODDEF
2843
    SET_SYMMETRIC_DIFFERENCE_METHODDEF
2844
    SET_SYMMETRIC_DIFFERENCE_UPDATE_METHODDEF
2845
    SET_UNION_METHODDEF
2846
    SET_UPDATE_METHODDEF
2847
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS,
2848
     PyDoc_STR("sets are generic over the type of their elements")},
2849
    {NULL,              NULL}   /* sentinel */
2850
};
2851
2852
static PyNumberMethods set_as_number = {
2853
    0,                                  /*nb_add*/
2854
    set_sub,                            /*nb_subtract*/
2855
    0,                                  /*nb_multiply*/
2856
    0,                                  /*nb_remainder*/
2857
    0,                                  /*nb_divmod*/
2858
    0,                                  /*nb_power*/
2859
    0,                                  /*nb_negative*/
2860
    0,                                  /*nb_positive*/
2861
    0,                                  /*nb_absolute*/
2862
    0,                                  /*nb_bool*/
2863
    0,                                  /*nb_invert*/
2864
    0,                                  /*nb_lshift*/
2865
    0,                                  /*nb_rshift*/
2866
    set_and,                            /*nb_and*/
2867
    set_xor,                            /*nb_xor*/
2868
    set_or,                             /*nb_or*/
2869
    0,                                  /*nb_int*/
2870
    0,                                  /*nb_reserved*/
2871
    0,                                  /*nb_float*/
2872
    0,                                  /*nb_inplace_add*/
2873
    set_isub,                           /*nb_inplace_subtract*/
2874
    0,                                  /*nb_inplace_multiply*/
2875
    0,                                  /*nb_inplace_remainder*/
2876
    0,                                  /*nb_inplace_power*/
2877
    0,                                  /*nb_inplace_lshift*/
2878
    0,                                  /*nb_inplace_rshift*/
2879
    set_iand,                           /*nb_inplace_and*/
2880
    set_ixor,                           /*nb_inplace_xor*/
2881
    set_ior,                            /*nb_inplace_or*/
2882
};
2883
2884
PyDoc_STRVAR(set_doc,
2885
"set(iterable=(), /)\n\
2886
--\n\
2887
\n\
2888
Build an unordered collection of unique elements.");
2889
2890
PyTypeObject PySet_Type = {
2891
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
2892
    "set",                              /* tp_name */
2893
    sizeof(PySetObject),                /* tp_basicsize */
2894
    0,                                  /* tp_itemsize */
2895
    /* methods */
2896
    set_dealloc,                        /* tp_dealloc */
2897
    0,                                  /* tp_vectorcall_offset */
2898
    0,                                  /* tp_getattr */
2899
    0,                                  /* tp_setattr */
2900
    0,                                  /* tp_as_async */
2901
    set_repr,                           /* tp_repr */
2902
    &set_as_number,                     /* tp_as_number */
2903
    &set_as_sequence,                   /* tp_as_sequence */
2904
    0,                                  /* tp_as_mapping */
2905
    PyObject_HashNotImplemented,        /* tp_hash */
2906
    0,                                  /* tp_call */
2907
    0,                                  /* tp_str */
2908
    PyObject_GenericGetAttr,            /* tp_getattro */
2909
    0,                                  /* tp_setattro */
2910
    0,                                  /* tp_as_buffer */
2911
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
2912
        Py_TPFLAGS_BASETYPE |
2913
        _Py_TPFLAGS_MATCH_SELF,         /* tp_flags */
2914
    set_doc,                            /* tp_doc */
2915
    set_traverse,                       /* tp_traverse */
2916
    set_clear_internal,                 /* tp_clear */
2917
    set_richcompare,                    /* tp_richcompare */
2918
    offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */
2919
    set_iter,                           /* tp_iter */
2920
    0,                                  /* tp_iternext */
2921
    set_methods,                        /* tp_methods */
2922
    0,                                  /* tp_members */
2923
    0,                                  /* tp_getset */
2924
    0,                                  /* tp_base */
2925
    0,                                  /* tp_dict */
2926
    0,                                  /* tp_descr_get */
2927
    0,                                  /* tp_descr_set */
2928
    0,                                  /* tp_dictoffset */
2929
    set_init,                           /* tp_init */
2930
    _PyType_AllocNoTrack,               /* tp_alloc */
2931
    set_new,                            /* tp_new */
2932
    PyObject_GC_Del,                    /* tp_free */
2933
    .tp_vectorcall = set_vectorcall,
2934
    .tp_version_tag = _Py_TYPE_VERSION_SET,
2935
};
2936
2937
/* frozenset object ********************************************************/
2938
2939
2940
static PyMethodDef frozenset_methods[] = {
2941
    FROZENSET___CONTAINS___METHODDEF
2942
    FROZENSET_COPY_METHODDEF
2943
    SET_DIFFERENCE_MULTI_METHODDEF
2944
    SET_INTERSECTION_MULTI_METHODDEF
2945
    SET_ISDISJOINT_METHODDEF
2946
    SET_ISSUBSET_METHODDEF
2947
    SET_ISSUPERSET_METHODDEF
2948
    SET___REDUCE___METHODDEF
2949
    SET___SIZEOF___METHODDEF
2950
    SET_SYMMETRIC_DIFFERENCE_METHODDEF
2951
    SET_UNION_METHODDEF
2952
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS,
2953
     PyDoc_STR("frozensets are generic over the type of their elements")},
2954
    {NULL,              NULL}   /* sentinel */
2955
};
2956
2957
static PyNumberMethods frozenset_as_number = {
2958
    0,                                  /*nb_add*/
2959
    set_sub,                            /*nb_subtract*/
2960
    0,                                  /*nb_multiply*/
2961
    0,                                  /*nb_remainder*/
2962
    0,                                  /*nb_divmod*/
2963
    0,                                  /*nb_power*/
2964
    0,                                  /*nb_negative*/
2965
    0,                                  /*nb_positive*/
2966
    0,                                  /*nb_absolute*/
2967
    0,                                  /*nb_bool*/
2968
    0,                                  /*nb_invert*/
2969
    0,                                  /*nb_lshift*/
2970
    0,                                  /*nb_rshift*/
2971
    set_and,                            /*nb_and*/
2972
    set_xor,                            /*nb_xor*/
2973
    set_or,                             /*nb_or*/
2974
};
2975
2976
PyDoc_STRVAR(frozenset_doc,
2977
"frozenset(iterable=(), /)\n\
2978
--\n\
2979
\n\
2980
Build an immutable unordered collection of unique elements.");
2981
2982
PyTypeObject PyFrozenSet_Type = {
2983
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
2984
    "frozenset",                        /* tp_name */
2985
    sizeof(PySetObject),                /* tp_basicsize */
2986
    0,                                  /* tp_itemsize */
2987
    /* methods */
2988
    set_dealloc,                        /* tp_dealloc */
2989
    0,                                  /* tp_vectorcall_offset */
2990
    0,                                  /* tp_getattr */
2991
    0,                                  /* tp_setattr */
2992
    0,                                  /* tp_as_async */
2993
    set_repr,                           /* tp_repr */
2994
    &frozenset_as_number,               /* tp_as_number */
2995
    &set_as_sequence,                   /* tp_as_sequence */
2996
    0,                                  /* tp_as_mapping */
2997
    frozenset_hash,                     /* tp_hash */
2998
    0,                                  /* tp_call */
2999
    0,                                  /* tp_str */
3000
    PyObject_GenericGetAttr,            /* tp_getattro */
3001
    0,                                  /* tp_setattro */
3002
    0,                                  /* tp_as_buffer */
3003
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3004
        Py_TPFLAGS_BASETYPE |
3005
        _Py_TPFLAGS_MATCH_SELF,         /* tp_flags */
3006
    frozenset_doc,                      /* tp_doc */
3007
    set_traverse,                       /* tp_traverse */
3008
    set_clear_internal,                 /* tp_clear */
3009
    set_richcompare,                    /* tp_richcompare */
3010
    offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */
3011
    set_iter,                           /* tp_iter */
3012
    0,                                  /* tp_iternext */
3013
    frozenset_methods,                  /* tp_methods */
3014
    0,                                  /* tp_members */
3015
    0,                                  /* tp_getset */
3016
    0,                                  /* tp_base */
3017
    0,                                  /* tp_dict */
3018
    0,                                  /* tp_descr_get */
3019
    0,                                  /* tp_descr_set */
3020
    0,                                  /* tp_dictoffset */
3021
    0,                                  /* tp_init */
3022
    _PyType_AllocNoTrack,               /* tp_alloc */
3023
    frozenset_new,                      /* tp_new */
3024
    PyObject_GC_Del,                    /* tp_free */
3025
    .tp_vectorcall = frozenset_vectorcall,
3026
    .tp_version_tag = _Py_TYPE_VERSION_FROZEN_SET,
3027
};
3028
3029
3030
/***** C API functions *************************************************/
3031
3032
PyObject *
3033
PySet_New(PyObject *iterable)
3034
750k
{
3035
750k
    return make_new_set(&PySet_Type, iterable);
3036
750k
}
3037
3038
PyObject *
3039
PyFrozenSet_New(PyObject *iterable)
3040
4.85k
{
3041
4.85k
    PyObject *result = make_new_set(&PyFrozenSet_Type, iterable);
3042
4.85k
    if (result != NULL) {
3043
4.85k
        _PyFrozenSet_MaybeUntrack(result);
3044
4.85k
    }
3045
4.85k
    return result;
3046
4.85k
}
3047
3048
Py_ssize_t
3049
PySet_Size(PyObject *anyset)
3050
256
{
3051
256
    if (!PyAnySet_Check(anyset)) {
3052
0
        PyErr_BadInternalCall();
3053
0
        return -1;
3054
0
    }
3055
256
    return set_len(anyset);
3056
256
}
3057
3058
int
3059
PySet_Clear(PyObject *set)
3060
539
{
3061
539
    if (!PySet_Check(set)) {
3062
0
        PyErr_BadInternalCall();
3063
0
        return -1;
3064
0
    }
3065
539
    (void)set_clear(set, NULL);
3066
539
    return 0;
3067
539
}
3068
3069
void
3070
_PySet_ClearInternal(PySetObject *so)
3071
0
{
3072
0
    (void)set_clear_internal((PyObject*)so);
3073
0
}
3074
3075
int
3076
PySet_Contains(PyObject *anyset, PyObject *key)
3077
216k
{
3078
216k
    if (!PyAnySet_Check(anyset)) {
3079
0
        PyErr_BadInternalCall();
3080
0
        return -1;
3081
0
    }
3082
3083
216k
    PySetObject *so = (PySetObject *)anyset;
3084
216k
    Py_hash_t hash = PyObject_Hash(key);
3085
216k
    if (hash == -1) {
3086
0
        set_unhashable_type(key);
3087
0
        return -1;
3088
0
    }
3089
216k
    return set_contains_entry(so, key, hash);
3090
216k
}
3091
3092
int
3093
PySet_Discard(PyObject *set, PyObject *key)
3094
38.4k
{
3095
38.4k
    if (!PySet_Check(set)) {
3096
0
        PyErr_BadInternalCall();
3097
0
        return -1;
3098
0
    }
3099
3100
38.4k
    int rv;
3101
38.4k
    Py_BEGIN_CRITICAL_SECTION(set);
3102
38.4k
    rv = set_discard_key((PySetObject *)set, key);
3103
38.4k
    Py_END_CRITICAL_SECTION();
3104
38.4k
    return rv;
3105
38.4k
}
3106
3107
int
3108
PySet_Add(PyObject *anyset, PyObject *key)
3109
32.2k
{
3110
32.2k
    if (PySet_Check(anyset)) {
3111
27.6k
        int rv;
3112
27.6k
        Py_BEGIN_CRITICAL_SECTION(anyset);
3113
27.6k
        rv = set_add_key((PySetObject *)anyset, key);
3114
27.6k
        Py_END_CRITICAL_SECTION();
3115
27.6k
        return rv;
3116
27.6k
    }
3117
3118
4.60k
    if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) {
3119
        // We can only change frozensets if they are uniquely referenced. The
3120
        // API limits the usage of `PySet_Add` to "fill in the values of brand
3121
        // new frozensets before they are exposed to other code". In this case,
3122
        // this can be done without a lock.
3123
        // Since another key is added to the set, we must track the frozenset
3124
        // if needed.
3125
4.60k
        if (PyFrozenSet_CheckExact(anyset) && !PyObject_GC_IsTracked(anyset) && PyObject_GC_IsTracked(key)) {
3126
8
            _PyObject_GC_TRACK(anyset);
3127
8
        }
3128
4.60k
        return set_add_key((PySetObject *)anyset, key);
3129
4.60k
    }
3130
3131
0
    PyErr_BadInternalCall();
3132
0
    return -1;
3133
4.60k
}
3134
3135
int
3136
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3137
3.40k
{
3138
3.40k
    setentry *entry;
3139
3140
3.40k
    if (!PyAnySet_Check(set)) {
3141
0
        PyErr_BadInternalCall();
3142
0
        return -1;
3143
0
    }
3144
3.40k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3145
759
        return 0;
3146
2.64k
    *key = entry->key;
3147
2.64k
    *hash = entry->hash;
3148
2.64k
    return 1;
3149
3.40k
}
3150
3151
int
3152
_PySet_NextEntryRef(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3153
1.32M
{
3154
1.32M
    setentry *entry;
3155
3156
1.32M
    if (!PyAnySet_Check(set)) {
3157
0
        PyErr_BadInternalCall();
3158
0
        return -1;
3159
0
    }
3160
1.32M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(set);
3161
1.32M
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3162
265k
        return 0;
3163
1.05M
    *key = Py_NewRef(entry->key);
3164
1.05M
    *hash = entry->hash;
3165
1.05M
    return 1;
3166
1.32M
}
3167
3168
PyObject *
3169
PySet_Pop(PyObject *set)
3170
6
{
3171
6
    if (!PySet_Check(set)) {
3172
0
        PyErr_BadInternalCall();
3173
0
        return NULL;
3174
0
    }
3175
6
    return set_pop(set, NULL);
3176
6
}
3177
3178
int
3179
_PySet_Update(PyObject *set, PyObject *iterable)
3180
87.8k
{
3181
87.8k
    if (!PySet_Check(set)) {
3182
0
        PyErr_BadInternalCall();
3183
0
        return -1;
3184
0
    }
3185
87.8k
    return set_update_internal((PySetObject *)set, iterable);
3186
87.8k
}
3187
3188
/* Exported for the gdb plugin's benefit. */
3189
PyObject *_PySet_Dummy = dummy;
3190
3191
/***** Dummy Struct  *************************************************/
3192
3193
static PyObject *
3194
dummy_repr(PyObject *op)
3195
0
{
3196
0
    return PyUnicode_FromString("<dummy key>");
3197
0
}
3198
3199
static void _Py_NO_RETURN
3200
dummy_dealloc(PyObject* ignore)
3201
0
{
3202
0
    Py_FatalError("deallocating <dummy key>");
3203
0
}
3204
3205
static PyTypeObject _PySetDummy_Type = {
3206
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
3207
    "<dummy key> type",
3208
    0,
3209
    0,
3210
    dummy_dealloc,      /*tp_dealloc*/ /*never called*/
3211
    0,                  /*tp_vectorcall_offset*/
3212
    0,                  /*tp_getattr*/
3213
    0,                  /*tp_setattr*/
3214
    0,                  /*tp_as_async*/
3215
    dummy_repr,         /*tp_repr*/
3216
    0,                  /*tp_as_number*/
3217
    0,                  /*tp_as_sequence*/
3218
    0,                  /*tp_as_mapping*/
3219
    0,                  /*tp_hash */
3220
    0,                  /*tp_call */
3221
    0,                  /*tp_str */
3222
    0,                  /*tp_getattro */
3223
    0,                  /*tp_setattro */
3224
    0,                  /*tp_as_buffer */
3225
    Py_TPFLAGS_DEFAULT, /*tp_flags */
3226
};
3227
3228
static PyObject _dummy_struct = _PyObject_HEAD_INIT(&_PySetDummy_Type);