Coverage Report

Created: 2026-10-17 06:15

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