Coverage Report

Created: 2026-10-31 06:21

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