Coverage Report

Created: 2026-07-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/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
786k
#define dummy (&_dummy_struct)
65
66
13.2M
#define SET_LOOKKEY_FOUND 1
67
45.1M
#define SET_LOOKKEY_NO_MATCH 0
68
0
#define SET_LOOKKEY_ERROR (-1)
69
7.21M
#define SET_LOOKKEY_CHANGED (-2)
70
40.7M
#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
5.54k
#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
8.39M
{
141
8.39M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
142
8.39M
    if (entry->hash == 0 && entry->key == NULL)
143
3.74M
        return SET_LOOKKEY_EMPTY;
144
4.65M
    if (entry->hash == hash) {
145
3.47M
        PyObject *startkey = entry->key;
146
3.47M
        assert(startkey != dummy);
147
3.47M
        if (startkey == key)
148
3.47M
            return SET_LOOKKEY_FOUND;
149
139
        if (PyUnicode_CheckExact(startkey)
150
139
            && PyUnicode_CheckExact(key)
151
139
            && unicode_eq(startkey, key))
152
139
            return SET_LOOKKEY_FOUND;
153
0
        table = so->table;
154
0
        Py_INCREF(startkey);
155
0
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
156
0
        Py_DECREF(startkey);
157
0
        if (cmp < 0)
158
0
            return SET_LOOKKEY_ERROR;
159
0
        if (table != so->table || entry->key != startkey)
160
0
            return SET_LOOKKEY_CHANGED;
161
0
        if (cmp > 0)
162
0
            return SET_LOOKKEY_FOUND;
163
0
    }
164
1.18M
    return SET_LOOKKEY_NO_MATCH;
165
4.65M
}
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
20.7M
{
175
20.7M
    assert(PyFrozenSet_Check(so));
176
20.7M
    PyObject *startkey = ep->key;
177
20.7M
    if (startkey == NULL) {
178
10.0M
        return SET_LOOKKEY_EMPTY;
179
10.0M
    }
180
10.6M
    if (startkey == key) {
181
9.73M
        return SET_LOOKKEY_FOUND;
182
9.73M
    }
183
933k
    Py_ssize_t ep_hash = ep->hash;
184
933k
    if (ep_hash == hash) {
185
0
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
186
0
        if (cmp < 0) {
187
0
            return SET_LOOKKEY_ERROR;
188
0
        }
189
0
        assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH);
190
0
        return cmp;
191
0
    }
192
933k
    return SET_LOOKKEY_NO_MATCH;
193
933k
}
194
195
static void
196
set_zero_table(setentry *table, size_t size)
197
25.4k
{
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
25.4k
    memset(table, 0, sizeof(setentry)*size);
206
25.4k
#endif
207
25.4k
}
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
36.3M
#define LINEAR_PROBES 9
215
#endif
216
217
/* This must be >= 1 */
218
1.71M
#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
26.9M
{
224
26.9M
    setentry *entry;
225
26.9M
    size_t perturb = hash;
226
26.9M
    size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
227
26.9M
    int probes;
228
26.9M
    int status;
229
230
28.6M
    while (1) {
231
28.6M
        entry = &table[i];
232
28.6M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
233
29.1M
        do {
234
29.1M
            status = compare_entry(so, table, entry, key, hash);
235
29.1M
            if (status != SET_LOOKKEY_NO_MATCH) {
236
26.9M
                if (status == SET_LOOKKEY_EMPTY) {
237
13.7M
                    return SET_LOOKKEY_NO_MATCH;
238
13.7M
                }
239
13.2M
                *epp = entry;
240
13.2M
                return status;
241
26.9M
            }
242
2.11M
            entry++;
243
2.11M
        } while (probes--);
244
1.67M
        perturb >>= PERTURB_SHIFT;
245
1.67M
        i = (i * 5 + 1 + perturb) & mask;
246
1.67M
    }
247
26.9M
    Py_UNREACHABLE();
248
26.9M
}
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
265k
{
255
265k
    setentry *table;
256
265k
    setentry *freeslot;
257
265k
    setentry *entry;
258
265k
    size_t perturb;
259
265k
    size_t mask;
260
265k
    size_t i;                       /* Unsigned for defined overflow behavior */
261
265k
    int probes;
262
265k
    int cmp;
263
264
265k
  restart:
265
266
265k
    mask = so->mask;
267
265k
    i = (size_t)hash & mask;
268
265k
    freeslot = NULL;
269
265k
    perturb = hash;
270
271
303k
    while (1) {
272
303k
        entry = &so->table[i];
273
303k
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
274
312k
        do {
275
312k
            if (entry->hash == 0 && entry->key == NULL)
276
252k
                goto found_unused_or_dummy;
277
60.6k
            if (entry->hash == hash) {
278
13.4k
                PyObject *startkey = entry->key;
279
13.4k
                assert(startkey != dummy);
280
13.4k
                if (startkey == key)
281
144
                    goto found_active;
282
13.3k
                if (PyUnicode_CheckExact(startkey)
283
13.3k
                    && PyUnicode_CheckExact(key)
284
0
                    && unicode_eq(startkey, key))
285
0
                    goto found_active;
286
13.3k
                table = so->table;
287
13.3k
                Py_INCREF(startkey);
288
13.3k
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
289
13.3k
                Py_DECREF(startkey);
290
13.3k
                if (cmp > 0)
291
13.3k
                    goto found_active;
292
0
                if (cmp < 0)
293
0
                    goto comparison_error;
294
0
                if (table != so->table || entry->key != startkey)
295
0
                    goto restart;
296
0
                mask = so->mask;
297
0
            }
298
47.2k
            else if (entry->hash == -1) {
299
20.8k
                assert (entry->key == dummy);
300
20.8k
                freeslot = entry;
301
20.8k
            }
302
47.2k
            entry++;
303
47.2k
        } while (probes--);
304
37.7k
        perturb >>= PERTURB_SHIFT;
305
37.7k
        i = (i * 5 + 1 + perturb) & mask;
306
37.7k
    }
307
308
252k
  found_unused_or_dummy:
309
252k
    if (freeslot == NULL)
310
237k
        goto found_unused;
311
15.0k
    if (freeslot->hash != -1) {
312
0
        goto restart;
313
0
    }
314
15.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
315
15.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash);
316
15.0k
    FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key);
317
15.0k
    return 0;
318
319
237k
  found_unused:
320
237k
    so->fill++;
321
237k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
322
237k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
323
237k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
324
237k
    if ((size_t)so->fill*5 < mask*3)
325
231k
        return 0;
326
5.86k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
327
328
13.4k
  found_active:
329
13.4k
    Py_DECREF(key);
330
13.4k
    return 0;
331
332
0
  comparison_error:
333
0
    Py_DECREF(key);
334
0
    return -1;
335
237k
}
336
337
static int
338
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
339
245k
{
340
245k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
341
342
245k
    return set_add_entry_takeref(so, Py_NewRef(key), hash);
343
245k
}
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
19.9k
{
364
19.9k
    Py_hash_t hash = PyObject_Hash(key);
365
19.9k
    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
19.9k
    return set_add_entry_takeref(so, key, hash);
373
19.9k
}
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
21.5k
{
386
21.5k
    setentry *entry;
387
21.5k
    size_t perturb = hash;
388
21.5k
    size_t i = (size_t)hash & mask;
389
21.5k
    size_t j;
390
391
22.3k
    while (1) {
392
22.3k
        entry = &table[i];
393
22.3k
        if (entry->key == NULL)
394
21.0k
            goto found_null;
395
1.32k
        if (i + LINEAR_PROBES <= mask) {
396
503
            for (j = 0; j < LINEAR_PROBES; j++) {
397
503
                entry++;
398
503
                if (entry->key == NULL)
399
443
                    goto found_null;
400
503
            }
401
443
        }
402
884
        perturb >>= PERTURB_SHIFT;
403
884
        i = (i * 5 + 1 + perturb) & mask;
404
884
    }
405
21.5k
  found_null:
406
21.5k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
407
21.5k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
408
21.5k
}
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
26.9M
{
416
26.9M
    int status;
417
26.9M
    if (PyFrozenSet_CheckExact(so)) {
418
19.7M
        status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
419
19.7M
                               set_compare_frozenset);
420
19.7M
    }
421
7.21M
    else {
422
7.21M
        Py_BEGIN_CRITICAL_SECTION(so);
423
7.21M
        do {
424
7.21M
            status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
425
7.21M
                                   set_compare_entry_lock_held);
426
7.21M
        } while (status == SET_LOOKKEY_CHANGED);
427
7.21M
        Py_END_CRITICAL_SECTION();
428
7.21M
    }
429
26.9M
    assert(status == SET_LOOKKEY_FOUND ||
430
26.9M
           status == SET_LOOKKEY_NO_MATCH ||
431
26.9M
           status == SET_LOOKKEY_ERROR);
432
26.9M
    return status;
433
26.9M
}
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
5.54k
{
469
#ifdef Py_GIL_DISABLED
470
    if (use_qsbr) {
471
        _PyMem_FreeDelayed(entries, size * sizeof(setentry));
472
        return;
473
    }
474
#endif
475
5.54k
    PyMem_Free(entries);
476
5.54k
}
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
25.2k
{
486
25.2k
    setentry *oldtable, *newtable, *entry;
487
25.2k
    Py_ssize_t oldmask = so->mask;
488
25.2k
    Py_ssize_t oldsize = (size_t)oldmask + 1;
489
25.2k
    size_t newmask;
490
25.2k
    int is_oldtable_malloced;
491
25.2k
    setentry small_copy[PySet_MINSIZE];
492
493
25.2k
    assert(minused >= 0);
494
495
    /* Find the smallest table size > minused. */
496
    /* XXX speed-up with intrinsics */
497
25.2k
    size_t newsize = PySet_MINSIZE;
498
31.9k
    while (newsize <= (size_t)minused) {
499
6.72k
        newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
500
6.72k
    }
501
502
    /* Get space for a new table. */
503
25.2k
    oldtable = so->table;
504
25.2k
    assert(oldtable != NULL);
505
25.2k
    is_oldtable_malloced = oldtable != so->smalltable;
506
507
25.2k
    if (newsize == PySet_MINSIZE) {
508
        /* A large table is shrinking, or we can't get any smaller. */
509
19.3k
        newtable = so->smalltable;
510
19.3k
        if (newtable == oldtable) {
511
19.3k
            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
19.3k
            assert(so->fill > so->used);
522
19.3k
            memcpy(small_copy, oldtable, sizeof(small_copy));
523
19.3k
            oldtable = small_copy;
524
19.3k
        }
525
19.3k
    }
526
5.87k
    else {
527
5.87k
        newtable = PyMem_NEW(setentry, newsize);
528
5.87k
        if (newtable == NULL) {
529
0
            PyErr_NoMemory();
530
0
            return -1;
531
0
        }
532
5.87k
    }
533
534
    /* Make the set empty, using the new table. */
535
25.2k
    assert(newtable != oldtable);
536
25.2k
    set_zero_table(newtable, newsize);
537
25.2k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
538
25.2k
    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
25.2k
    newmask = (size_t)so->mask;
543
25.2k
    if (so->fill == so->used) {
544
11.7k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
545
11.2k
            if (entry->key != NULL) {
546
6.79k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
547
6.79k
            }
548
11.2k
        }
549
24.7k
    } else {
550
24.7k
        so->fill = so->used;
551
222k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
552
197k
            if (entry->key != NULL && entry->key != dummy) {
553
14.6k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
554
14.6k
            }
555
197k
        }
556
24.7k
    }
557
558
25.2k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, newtable);
559
560
25.2k
    if (is_oldtable_malloced)
561
139
        free_entries(oldtable, oldsize, SET_IS_SHARED(so));
562
25.2k
    return 0;
563
25.2k
}
564
565
static int
566
set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
567
26.9M
{
568
#ifdef Py_GIL_DISABLED
569
    return set_lookkey_threadsafe(so, key, hash);
570
#else
571
26.9M
    setentry *entry; // unused
572
26.9M
    return set_lookkey(so, key, hash, &entry);
573
26.9M
#endif
574
26.9M
}
575
576
48.4k
#define DISCARD_NOTFOUND 0
577
95.5k
#define DISCARD_FOUND 1
578
579
static int
580
set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
581
96.2k
{
582
96.2k
    setentry *entry;
583
96.2k
    PyObject *old_key;
584
96.2k
    int status = set_lookkey(so, key, hash, &entry);
585
96.2k
    if (status < 0) {
586
0
        return -1;
587
0
    }
588
96.2k
    if (status == SET_LOOKKEY_NO_MATCH) {
589
718
        return DISCARD_NOTFOUND;
590
718
    }
591
96.2k
    assert(status == SET_LOOKKEY_FOUND);
592
95.5k
    old_key = entry->key;
593
95.5k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
594
95.5k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
595
95.5k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
596
95.5k
    Py_DECREF(old_key);
597
95.5k
    return DISCARD_FOUND;
598
95.5k
}
599
600
static int
601
set_add_key(PySetObject *so, PyObject *key)
602
197k
{
603
197k
    Py_hash_t hash = PyObject_Hash(key);
604
197k
    if (hash == -1) {
605
0
        set_unhashable_type(key);
606
0
        return -1;
607
0
    }
608
197k
    return set_add_entry(so, key, hash);
609
197k
}
610
611
static int
612
set_contains_key(PySetObject *so, PyObject *key)
613
0
{
614
0
    Py_hash_t hash = PyObject_Hash(key);
615
0
    if (hash == -1) {
616
0
        set_unhashable_type(key);
617
0
        return -1;
618
0
    }
619
0
    return set_contains_entry(so, key, hash);
620
0
}
621
622
static int
623
set_discard_key(PySetObject *so, PyObject *key)
624
48.4k
{
625
48.4k
    Py_hash_t hash = PyObject_Hash(key);
626
48.4k
    if (hash == -1) {
627
0
        set_unhashable_type(key);
628
0
        return -1;
629
0
    }
630
48.4k
    return set_discard_entry(so, key, hash);
631
48.4k
}
632
633
static void
634
set_empty_to_minsize(PySetObject *so)
635
195
{
636
195
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
637
195
    set_zero_table(so->smalltable, PySet_MINSIZE);
638
195
    so->fill = 0;
639
195
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0);
640
195
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, PySet_MINSIZE - 1);
641
195
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1);
642
195
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, so->smalltable);
643
195
}
644
645
static int
646
set_clear_internal(PyObject *self)
647
195
{
648
195
    PySetObject *so = _PySet_CAST(self);
649
0
    setentry *entry;
650
195
    setentry *table = so->table;
651
195
    Py_ssize_t fill = so->fill;
652
195
    Py_ssize_t used = so->used;
653
195
    Py_ssize_t oldsize = (size_t)so->mask + 1;
654
195
    int table_is_malloced = table != so->smalltable;
655
195
    setentry small_copy[PySet_MINSIZE];
656
657
195
    assert (PyAnySet_Check(so));
658
195
    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
195
    if (table_is_malloced)
667
0
        set_empty_to_minsize(so);
668
669
195
    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
195
        memcpy(small_copy, table, sizeof(small_copy));
675
195
        table = small_copy;
676
195
        set_empty_to_minsize(so);
677
195
    }
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
1.15k
    for (entry = table; used > 0; entry++) {
685
956
        if (entry->key && entry->key != dummy) {
686
195
            used--;
687
195
            Py_DECREF(entry->key);
688
195
        }
689
956
    }
690
691
195
    if (table_is_malloced)
692
0
        free_entries(table, oldsize, SET_IS_SHARED(so));
693
195
    return 0;
694
195
}
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
360k
{
712
360k
    Py_ssize_t i;
713
360k
    Py_ssize_t mask;
714
360k
    setentry *entry;
715
716
360k
    assert (PyAnySet_Check(so));
717
360k
    i = *pos_ptr;
718
360k
    assert(i >= 0);
719
360k
    mask = so->mask;
720
360k
    entry = &so->table[i];
721
1.02M
    while (i <= mask && (entry->key == NULL || entry->key == dummy)) {
722
660k
        i++;
723
660k
        entry++;
724
660k
    }
725
360k
    *pos_ptr = i+1;
726
360k
    if (i > mask)
727
70.1k
        return 0;
728
360k
    assert(entry != NULL);
729
290k
    *entry_ptr = entry;
730
290k
    return 1;
731
290k
}
732
733
static void
734
set_dealloc(PyObject *self)
735
136k
{
736
136k
    PySetObject *so = _PySet_CAST(self);
737
0
    setentry *entry;
738
136k
    Py_ssize_t used = so->used;
739
136k
    Py_ssize_t oldsize = (size_t)so->mask + 1;
740
741
    /* bpo-31095: UnTrack is needed before calling any callbacks */
742
136k
    PyObject_GC_UnTrack(so);
743
136k
    FT_CLEAR_WEAKREFS(self, so->weakreflist);
744
745
502k
    for (entry = so->table; used > 0; entry++) {
746
366k
        if (entry->key && entry->key != dummy) {
747
148k
                used--;
748
148k
                Py_DECREF(entry->key);
749
148k
        }
750
366k
    }
751
136k
    if (so->table != so->smalltable)
752
5.40k
        free_entries(so->table, oldsize, SET_IS_SHARED(so));
753
136k
    Py_TYPE(so)->tp_free(so);
754
136k
}
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
302k
{
824
302k
    PySetObject *so = _PySet_CAST(self);
825
302k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
826
302k
}
827
828
static int
829
set_merge_lock_held(PySetObject *so, PyObject *otherset)
830
58.4k
{
831
58.4k
    PySetObject *other;
832
58.4k
    PyObject *key;
833
58.4k
    Py_ssize_t i;
834
58.4k
    setentry *so_entry;
835
58.4k
    setentry *other_entry;
836
837
58.4k
    assert (PyAnySet_Check(so));
838
58.4k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
839
58.4k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(otherset);
840
841
58.4k
    other = _PySet_CAST(otherset);
842
58.4k
    if (other == so || other->used == 0)
843
        /* a.update(a) or a.update(set()); nothing to do */
844
19.4k
        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
38.9k
    if ((so->fill + other->used)*5 >= so->mask*3) {
850
7
        if (set_table_resize(so, (so->used + other->used)*2) != 0)
851
0
            return -1;
852
7
    }
853
38.9k
    so_entry = so->table;
854
38.9k
    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
38.9k
    if (so->fill == 0 && so->mask == other->mask && other->fill == other->used) {
859
350k
        for (i = 0; i <= other->mask; i++, so_entry++, other_entry++) {
860
311k
            key = other_entry->key;
861
311k
            if (key != NULL) {
862
96.0k
                assert(so_entry->key == NULL);
863
96.0k
                FT_ATOMIC_STORE_SSIZE_RELAXED(so_entry->hash, other_entry->hash);
864
96.0k
                FT_ATOMIC_STORE_PTR_RELEASE(so_entry->key, Py_NewRef(key));
865
96.0k
            }
866
311k
        }
867
38.9k
        so->fill = other->fill;
868
38.9k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
869
38.9k
        return 0;
870
38.9k
    }
871
872
    /* If our table is empty, we can use set_insert_clean() */
873
7
    if (so->fill == 0) {
874
7
        setentry *newtable = so->table;
875
7
        size_t newmask = (size_t)so->mask;
876
7
        so->fill = other->used;
877
7
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
878
231
        for (i = other->mask + 1; i > 0 ; i--, other_entry++) {
879
224
            key = other_entry->key;
880
224
            if (key != NULL && key != dummy) {
881
37
                set_insert_clean(newtable, newmask, Py_NewRef(key),
882
37
                                 other_entry->hash);
883
37
            }
884
224
        }
885
7
        return 0;
886
7
    }
887
888
    /* We can't assure there are no duplicates, so do normal insertions */
889
0
    for (i = 0; i <= other->mask; i++) {
890
0
        other_entry = &other->table[i];
891
0
        key = other_entry->key;
892
0
        if (key != NULL && key != dummy) {
893
0
            if (set_add_entry(so, key, other_entry->hash))
894
0
                return -1;
895
0
        }
896
0
    }
897
0
    return 0;
898
0
}
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
88.0k
{
914
    /* Make sure the search finger is in bounds */
915
88.0k
    setentry *entry = so->table + (so->finger & so->mask);
916
88.0k
    setentry *limit = so->table + so->mask;
917
88.0k
    PyObject *key;
918
919
88.0k
    if (so->used == 0) {
920
0
        PyErr_SetString(PyExc_KeyError, "pop from an empty set");
921
0
        return NULL;
922
0
    }
923
333k
    while (entry->key == NULL || entry->key==dummy) {
924
245k
        entry++;
925
245k
        if (entry > limit)
926
15.4k
            entry = so->table;
927
245k
    }
928
88.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
929
88.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
930
88.0k
    key = entry->key;
931
88.0k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
932
88.0k
    so->finger = entry - so->table + 1;   /* next place to start */
933
88.0k
    return key;
934
88.0k
}
935
936
static int
937
set_traverse(PyObject *self, visitproc visit, void *arg)
938
30.3k
{
939
30.3k
    PySetObject *so = _PySet_CAST(self);
940
0
    Py_ssize_t pos = 0;
941
30.3k
    setentry *entry;
942
943
217k
    while (set_next(so, &pos, &entry))
944
187k
        Py_VISIT(entry->key);
945
30.3k
    return 0;
946
30.3k
}
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
0
{
956
0
    return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL;
957
0
}
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
0
{
975
0
    PySetObject *so = _PySet_CAST(self);
976
0
    Py_uhash_t hash = 0;
977
0
    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
0
    for (entry = so->table; entry <= &so->table[so->mask]; entry++)
990
0
        hash ^= _shuffle_bits(entry->hash);
991
992
    /* Remove the effect of an odd number of NULL entries */
993
0
    if ((so->mask + 1 - so->fill) & 1)
994
0
        hash ^= _shuffle_bits(0);
995
996
    /* Remove the effect of an odd number of dummy entries */
997
0
    if ((so->fill - so->used) & 1)
998
0
        hash ^= _shuffle_bits(-1);
999
1000
    /* Factor in the number of active entries */
1001
0
    hash ^= ((Py_uhash_t)PySet_GET_SIZE(self) + 1) * 1927868237UL;
1002
1003
    /* Disperse patterns arising in nested frozensets */
1004
0
    hash ^= (hash >> 11) ^ (hash >> 25);
1005
0
    hash = hash * 69069U + 907133923UL;
1006
1007
    /* -1 is reserved as an error code */
1008
0
    if (hash == (Py_uhash_t)-1)
1009
0
        hash = 590923713UL;
1010
1011
0
    return (Py_hash_t)hash;
1012
0
}
1013
1014
static Py_hash_t
1015
frozenset_hash(PyObject *self)
1016
0
{
1017
0
    PySetObject *so = _PySet_CAST(self);
1018
0
    Py_uhash_t hash;
1019
1020
0
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) {
1021
0
        return FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->hash);
1022
0
    }
1023
1024
0
    hash = frozenset_hash_impl(self);
1025
0
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->hash, hash);
1026
0
    return hash;
1027
0
}
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
67.8k
{
1042
67.8k
    setiterobject *si = (setiterobject*)self;
1043
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1044
67.8k
    _PyObject_GC_UNTRACK(si);
1045
67.8k
    Py_XDECREF(si->si_set);
1046
67.8k
    PyObject_GC_Del(si);
1047
67.8k
}
1048
1049
static int
1050
setiter_traverse(PyObject *self, visitproc visit, void *arg)
1051
0
{
1052
0
    setiterobject *si = (setiterobject*)self;
1053
0
    Py_VISIT(si->si_set);
1054
0
    return 0;
1055
0
}
1056
1057
static PyObject *
1058
setiter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
1059
0
{
1060
0
    setiterobject *si = (setiterobject*)op;
1061
0
    Py_ssize_t len = 0;
1062
0
    if (si->si_set != NULL && si->si_used == si->si_set->used)
1063
0
        len = si->len;
1064
0
    return PyLong_FromSsize_t(len);
1065
0
}
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
202k
{
1097
202k
    setiterobject *si = (setiterobject*)self;
1098
202k
    PyObject *key = NULL;
1099
202k
    Py_ssize_t i, mask;
1100
202k
    setentry *entry;
1101
202k
    PySetObject *so = si->si_set;
1102
1103
202k
    if (so == NULL)
1104
0
        return NULL;
1105
202k
    assert (PyAnySet_Check(so));
1106
1107
202k
    Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
1108
202k
    Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used);
1109
202k
    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
202k
    Py_BEGIN_CRITICAL_SECTION(so);
1117
202k
    i = si->si_pos;
1118
202k
    assert(i>=0);
1119
202k
    entry = so->table;
1120
202k
    mask = so->mask;
1121
613k
    while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
1122
410k
        i++;
1123
410k
    }
1124
202k
    if (i <= mask) {
1125
134k
        key = Py_NewRef(entry[i].key);
1126
134k
    }
1127
202k
    Py_END_CRITICAL_SECTION();
1128
202k
    si->si_pos = i+1;
1129
202k
    if (key == NULL) {
1130
67.8k
        si->si_set = NULL;
1131
67.8k
        Py_DECREF(so);
1132
67.8k
        return NULL;
1133
67.8k
    }
1134
134k
    si->len--;
1135
134k
    return key;
1136
202k
}
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
67.8k
{
1174
67.8k
    Py_ssize_t size = set_len(so);
1175
67.8k
    setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
1176
67.8k
    if (si == NULL)
1177
0
        return NULL;
1178
67.8k
    si->si_set = (PySetObject*)Py_NewRef(so);
1179
67.8k
    si->si_used = size;
1180
67.8k
    si->si_pos = 0;
1181
67.8k
    si->len = size;
1182
67.8k
    _PyObject_GC_TRACK(si);
1183
67.8k
    return (PyObject *)si;
1184
67.8k
}
1185
1186
static int
1187
set_update_dict_lock_held(PySetObject *so, PyObject *other)
1188
19.3k
{
1189
19.3k
    assert(PyAnyDict_CheckExact(other));
1190
1191
19.3k
    _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
19.3k
    Py_ssize_t dictsize = PyDict_GET_SIZE(other);
1203
19.3k
    if ((so->fill + dictsize)*5 >= so->mask*3) {
1204
0
        if (set_table_resize(so, (so->used + dictsize)*2) != 0) {
1205
0
            return -1;
1206
0
        }
1207
0
    }
1208
1209
19.3k
    Py_ssize_t pos = 0;
1210
19.3k
    PyObject *key;
1211
19.3k
    PyObject *value;
1212
19.3k
    Py_hash_t hash;
1213
67.1k
    while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
1214
47.7k
        if (set_add_entry(so, key, hash)) {
1215
0
            return -1;
1216
0
        }
1217
47.7k
    }
1218
19.3k
    return 0;
1219
19.3k
}
1220
1221
static int
1222
set_update_iterable_lock_held(PySetObject *so, PyObject *other)
1223
125
{
1224
125
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1225
1226
125
    PyObject *it = PyObject_GetIter(other);
1227
125
    if (it == NULL) {
1228
0
        return -1;
1229
0
    }
1230
1231
125
    PyObject *key;
1232
12.3k
    while ((key = PyIter_Next(it)) != NULL) {
1233
12.2k
        if (set_add_key(so, key)) {
1234
0
            Py_DECREF(it);
1235
0
            Py_DECREF(key);
1236
0
            return -1;
1237
0
        }
1238
12.2k
        Py_DECREF(key);
1239
12.2k
    }
1240
125
    Py_DECREF(it);
1241
125
    if (PyErr_Occurred())
1242
0
        return -1;
1243
125
    return 0;
1244
125
}
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
39.1k
{
1262
39.1k
    assert(Py_REFCNT(so) == 1);
1263
39.1k
    if (PyAnySet_Check(other)) {
1264
19.6k
        int rv;
1265
19.6k
        Py_BEGIN_CRITICAL_SECTION(other);
1266
19.6k
        rv = set_merge_lock_held(so, other);
1267
19.6k
        Py_END_CRITICAL_SECTION();
1268
19.6k
        return rv;
1269
19.6k
    }
1270
19.5k
    else if (PyDict_CheckExact(other)) {
1271
19.3k
        int rv;
1272
19.3k
        Py_BEGIN_CRITICAL_SECTION(other);
1273
19.3k
        rv = set_update_dict_lock_held(so, other);
1274
19.3k
        Py_END_CRITICAL_SECTION();
1275
19.3k
        return rv;
1276
19.3k
    }
1277
125
    else if (PyFrozenDict_CheckExact(other)) {
1278
0
        return set_update_dict_lock_held(so, other);
1279
0
    }
1280
125
    return set_update_iterable_lock_held(so, other);
1281
39.1k
}
1282
1283
static int
1284
set_update_internal(PySetObject *so, PyObject *other)
1285
70
{
1286
70
    if (PyAnySet_Check(other)) {
1287
70
        if (Py_Is((PyObject *)so, other)) {
1288
0
            return 0;
1289
0
        }
1290
70
        int rv;
1291
70
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1292
70
        rv = set_merge_lock_held(so, other);
1293
70
        Py_END_CRITICAL_SECTION2();
1294
70
        return rv;
1295
70
    }
1296
0
    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
0
    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
0
    else {
1311
0
        int rv;
1312
0
        Py_BEGIN_CRITICAL_SECTION(so);
1313
0
        rv = set_update_iterable_lock_held(so, other);
1314
0
        Py_END_CRITICAL_SECTION();
1315
0
        return rv;
1316
0
    }
1317
70
}
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
0
{
1332
0
    Py_ssize_t i;
1333
1334
0
    for (i = 0; i < others_length; i++) {
1335
0
        PyObject *other = others[i];
1336
0
        if (set_update_internal(so, other))
1337
0
            return NULL;
1338
0
    }
1339
0
    Py_RETURN_NONE;
1340
0
}
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
138k
{
1353
138k
    assert(PyType_Check(type));
1354
138k
    PySetObject *so;
1355
1356
138k
    so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
1357
138k
    if (so == NULL)
1358
0
        return NULL;
1359
1360
138k
    so->fill = 0;
1361
138k
    so->used = 0;
1362
138k
    so->mask = PySet_MINSIZE - 1;
1363
138k
    so->table = so->smalltable;
1364
138k
    so->hash = -1;
1365
138k
    so->finger = 0;
1366
138k
    so->weakreflist = NULL;
1367
1368
138k
    if (iterable != NULL) {
1369
19.8k
        if (set_update_local(so, iterable)) {
1370
0
            Py_DECREF(so);
1371
0
            return NULL;
1372
0
        }
1373
19.8k
    }
1374
1375
138k
    return (PyObject *)so;
1376
138k
}
1377
1378
static PyObject *
1379
make_new_set(PyTypeObject *type, PyObject *iterable)
1380
99.5k
{
1381
99.5k
    PyObject *so = make_new_set_untracked(type, iterable);
1382
99.5k
    if (so != NULL) {
1383
99.5k
        _PyObject_GC_TRACK(so);
1384
99.5k
    }
1385
99.5k
    return so;
1386
99.5k
}
1387
1388
static PyObject *
1389
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
1390
38.7k
{
1391
38.7k
    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
38.7k
    return make_new_set_untracked(type, iterable);
1398
38.7k
}
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
1.04k
{
1414
1.04k
    assert(op != NULL);
1415
    // subclasses of a frozenset can generate reference cycles, so do not untrack
1416
1.04k
    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
1.04k
    Py_ssize_t pos = 0;
1421
1.04k
    setentry *entry;
1422
7.74k
    while (set_next((PySetObject *)op, &pos, &entry)) {
1423
6.92k
        if (_PyObject_GC_MAY_BE_TRACKED(entry->key)) {
1424
220
            return;
1425
220
        }
1426
6.92k
    }
1427
823
    _PyObject_GC_UNTRACK(op);
1428
823
}
1429
1430
static PyObject *
1431
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
1432
58
{
1433
58
    if (type != &PyFrozenSet_Type) {
1434
0
        return make_new_set(type, iterable);
1435
0
    }
1436
1437
58
    if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
1438
        /* frozenset(f) is idempotent */
1439
0
        return Py_NewRef(iterable);
1440
0
    }
1441
58
    PyObject *obj = make_new_set(type, iterable);
1442
58
    if (obj != NULL) {
1443
58
        _PyFrozenSet_MaybeUntrack(obj);
1444
58
    }
1445
58
    return obj;
1446
58
}
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
58
{
1470
58
    if (!_PyArg_NoKwnames("frozenset", kwnames)) {
1471
0
        return NULL;
1472
0
    }
1473
1474
58
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1475
58
    if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
1476
0
        return NULL;
1477
0
    }
1478
1479
58
    PyObject *iterable = (nargs ? args[0] : NULL);
1480
58
    return make_new_frozenset(_PyType_CAST(type), iterable);
1481
58
}
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
15
{
1573
15
    assert(set != NULL);
1574
15
    assert(PySet_CheckExact(set));
1575
15
    assert(_PyObject_IsUniquelyReferenced(set));
1576
15
    set->ob_type = &PyFrozenSet_Type;
1577
15
    return Py_NewRef(set);
1578
15
}
1579
1580
static PyObject *
1581
set_copy_untracked_lock_held(PySetObject *so)
1582
38.7k
{
1583
38.7k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1584
38.7k
    PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1585
38.7k
    if (copy == NULL) {
1586
0
        return NULL;
1587
0
    }
1588
38.7k
    if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
1589
0
        Py_DECREF(copy);
1590
0
        return NULL;
1591
0
    }
1592
38.7k
    return copy;
1593
38.7k
}
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
38.7k
{
1607
38.7k
    PyObject *copy = set_copy_untracked_lock_held(so);
1608
38.7k
    if (copy != NULL) {
1609
38.7k
        _PyObject_GC_TRACK(copy);
1610
38.7k
    }
1611
38.7k
    return copy;
1612
38.7k
}
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
195
{
1644
195
    set_clear_internal((PyObject*)so);
1645
195
    Py_RETURN_NONE;
1646
195
}
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
0
{
1661
0
    PySetObject *result;
1662
0
    PyObject *other;
1663
0
    Py_ssize_t i;
1664
1665
0
    result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so),
1666
0
                                                            (PyObject *)so);
1667
0
    if (result == NULL)
1668
0
        return NULL;
1669
1670
0
    for (i = 0; i < others_length; i++) {
1671
0
        other = others[i];
1672
0
        if ((PyObject *)so == other)
1673
0
            continue;
1674
0
        if (set_update_local(result, other)) {
1675
0
            Py_DECREF(result);
1676
0
            return NULL;
1677
0
        }
1678
0
    }
1679
0
    _PyObject_GC_TRACK(result);
1680
0
    return (PyObject *)result;
1681
0
}
1682
1683
static PyObject *
1684
set_or(PyObject *self, PyObject *other)
1685
19.3k
{
1686
19.3k
    PySetObject *result;
1687
1688
19.3k
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1689
0
        Py_RETURN_NOTIMPLEMENTED;
1690
1691
19.3k
    result = (PySetObject *)set_copy(self, NULL);
1692
19.3k
    if (result == NULL) {
1693
0
        return NULL;
1694
0
    }
1695
19.3k
    if (Py_Is(self, other)) {
1696
0
        return (PyObject *)result;
1697
0
    }
1698
19.3k
    if (set_update_local(result, other)) {
1699
0
        Py_DECREF(result);
1700
0
        return NULL;
1701
0
    }
1702
19.3k
    return (PyObject *)result;
1703
19.3k
}
1704
1705
static PyObject *
1706
set_ior(PyObject *self, PyObject *other)
1707
70
{
1708
70
    if (!PyAnySet_Check(other))
1709
0
        Py_RETURN_NOTIMPLEMENTED;
1710
70
    PySetObject *so = _PySet_CAST(self);
1711
1712
70
    if (set_update_internal(so, other)) {
1713
0
        return NULL;
1714
0
    }
1715
70
    return Py_NewRef(so);
1716
70
}
1717
1718
static PyObject *
1719
set_intersection(PySetObject *so, PyObject *other)
1720
35
{
1721
35
    PySetObject *result;
1722
35
    PyObject *key, *it, *tmp;
1723
35
    Py_hash_t hash;
1724
35
    int rv;
1725
1726
35
    if ((PyObject *)so == other)
1727
0
        return set_copy_impl(so);
1728
1729
35
    result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1730
35
    if (result == NULL)
1731
0
        return NULL;
1732
1733
35
    if (PyAnySet_Check(other)) {
1734
35
        Py_ssize_t pos = 0;
1735
35
        setentry *entry;
1736
1737
35
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1738
30
            tmp = (PyObject *)so;
1739
30
            so = (PySetObject *)other;
1740
30
            other = tmp;
1741
30
        }
1742
1743
45
        while (set_next((PySetObject *)other, &pos, &entry)) {
1744
10
            key = entry->key;
1745
10
            hash = entry->hash;
1746
10
            Py_INCREF(key);
1747
10
            rv = set_contains_entry(so, key, hash);
1748
10
            if (rv < 0) {
1749
0
                Py_DECREF(result);
1750
0
                Py_DECREF(key);
1751
0
                return NULL;
1752
0
            }
1753
10
            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
10
            Py_DECREF(key);
1761
10
        }
1762
35
        _PyObject_GC_TRACK(result);
1763
35
        return (PyObject *)result;
1764
35
    }
1765
1766
0
    it = PyObject_GetIter(other);
1767
0
    if (it == NULL) {
1768
0
        Py_DECREF(result);
1769
0
        return NULL;
1770
0
    }
1771
1772
0
    while ((key = PyIter_Next(it)) != NULL) {
1773
0
        hash = PyObject_Hash(key);
1774
0
        if (hash == -1)
1775
0
            goto error;
1776
0
        rv = set_contains_entry(so, key, hash);
1777
0
        if (rv < 0)
1778
0
            goto error;
1779
0
        if (rv) {
1780
0
            if (set_add_entry(result, key, hash))
1781
0
                goto error;
1782
0
            if (PySet_GET_SIZE(result) >= PySet_GET_SIZE(so)) {
1783
0
                Py_DECREF(key);
1784
0
                break;
1785
0
            }
1786
0
        }
1787
0
        Py_DECREF(key);
1788
0
    }
1789
0
    Py_DECREF(it);
1790
0
    if (PyErr_Occurred()) {
1791
0
        Py_DECREF(result);
1792
0
        return NULL;
1793
0
    }
1794
0
    _PyObject_GC_TRACK(result);
1795
0
    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
0
}
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
0
{
1816
0
    Py_ssize_t i;
1817
1818
0
    if (others_length == 0) {
1819
0
        return set_copy((PyObject *)so, NULL);
1820
0
    }
1821
1822
0
    PyObject *result = Py_NewRef(so);
1823
0
    for (i = 0; i < others_length; i++) {
1824
0
        PyObject *other = others[i];
1825
0
        PyObject *newresult;
1826
0
        Py_BEGIN_CRITICAL_SECTION2(result, other);
1827
0
        newresult = set_intersection((PySetObject *)result, other);
1828
0
        Py_END_CRITICAL_SECTION2();
1829
0
        if (newresult == NULL) {
1830
0
            Py_DECREF(result);
1831
0
            return NULL;
1832
0
        }
1833
0
        Py_SETREF(result, newresult);
1834
0
    }
1835
0
    return result;
1836
0
}
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
35
{
1879
35
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1880
0
        Py_RETURN_NOTIMPLEMENTED;
1881
35
    PySetObject *so = _PySet_CAST(self);
1882
1883
0
    PyObject *rv;
1884
35
    Py_BEGIN_CRITICAL_SECTION2(so, other);
1885
35
    rv = set_intersection(so, other);
1886
35
    Py_END_CRITICAL_SECTION2();
1887
1888
35
    return rv;
1889
35
}
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
0
{
1924
0
    PyObject *key, *it, *tmp;
1925
0
    int rv;
1926
1927
0
    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
0
    if (PyAnySet_CheckExact(other)) {
1935
0
        Py_ssize_t pos = 0;
1936
0
        setentry *entry;
1937
1938
0
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1939
0
            tmp = (PyObject *)so;
1940
0
            so = (PySetObject *)other;
1941
0
            other = tmp;
1942
0
        }
1943
0
        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
0
        Py_RETURN_TRUE;
1956
0
    }
1957
1958
0
    it = PyObject_GetIter(other);
1959
0
    if (it == NULL)
1960
0
        return NULL;
1961
1962
0
    while ((key = PyIter_Next(it)) != NULL) {
1963
0
        rv = set_contains_key(so, key);
1964
0
        Py_DECREF(key);
1965
0
        if (rv < 0) {
1966
0
            Py_DECREF(it);
1967
0
            return NULL;
1968
0
        }
1969
0
        if (rv) {
1970
0
            Py_DECREF(it);
1971
0
            Py_RETURN_FALSE;
1972
0
        }
1973
0
    }
1974
0
    Py_DECREF(it);
1975
0
    if (PyErr_Occurred())
1976
0
        return NULL;
1977
0
    Py_RETURN_TRUE;
1978
0
}
1979
1980
static int
1981
set_difference_update_internal(PySetObject *so, PyObject *other)
1982
19.3k
{
1983
19.3k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1984
19.3k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
1985
1986
19.3k
    if ((PyObject *)so == other)
1987
0
        return set_clear_internal((PyObject*)so);
1988
1989
19.3k
    if (PyAnySet_Check(other)) {
1990
19.3k
        setentry *entry;
1991
19.3k
        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
19.3k
        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
19.3k
        } else {
2002
19.3k
            Py_INCREF(other);
2003
19.3k
        }
2004
2005
67.1k
        while (set_next((PySetObject *)other, &pos, &entry)) {
2006
47.7k
            PyObject *key = entry->key;
2007
47.7k
            Py_INCREF(key);
2008
47.7k
            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
47.7k
            Py_DECREF(key);
2014
47.7k
        }
2015
2016
19.3k
        Py_DECREF(other);
2017
19.3k
    } 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
19.3k
    if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4)
2037
0
        return 0;
2038
19.3k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
2039
19.3k
}
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
19.3k
{
2054
19.3k
    Py_ssize_t i;
2055
2056
38.7k
    for (i = 0; i < others_length; i++) {
2057
19.3k
        PyObject *other = others[i];
2058
19.3k
        int rv;
2059
19.3k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
2060
19.3k
        rv = set_difference_update_internal(so, other);
2061
19.3k
        Py_END_CRITICAL_SECTION2();
2062
19.3k
        if (rv) {
2063
0
            return NULL;
2064
0
        }
2065
19.3k
    }
2066
19.3k
    Py_RETURN_NONE;
2067
19.3k
}
2068
2069
static PyObject *
2070
set_copy_and_difference_untracked(PySetObject *so, PyObject *other)
2071
0
{
2072
0
    PyObject *result;
2073
2074
0
    result = set_copy_untracked_lock_held(so);
2075
0
    if (result == NULL)
2076
0
        return NULL;
2077
0
    if (set_difference_update_internal((PySetObject *) result, other) == 0)
2078
0
        return result;
2079
0
    Py_DECREF(result);
2080
0
    return NULL;
2081
0
}
2082
2083
static PyObject *
2084
set_difference_untracked(PySetObject *so, PyObject *other)
2085
0
{
2086
0
    PyObject *result;
2087
0
    PyObject *key;
2088
0
    Py_hash_t hash;
2089
0
    setentry *entry;
2090
0
    Py_ssize_t pos = 0, other_size;
2091
0
    int rv;
2092
2093
0
    if (PyAnySet_Check(other)) {
2094
0
        other_size = PySet_GET_SIZE(other);
2095
0
    }
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
0
    if ((PySet_GET_SIZE(so) >> 2) > other_size) {
2106
0
        return set_copy_and_difference_untracked(so, other);
2107
0
    }
2108
2109
0
    result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
2110
0
    if (result == NULL)
2111
0
        return NULL;
2112
2113
0
    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
0
    while (set_next(so, &pos, &entry)) {
2138
0
        key = entry->key;
2139
0
        hash = entry->hash;
2140
0
        Py_INCREF(key);
2141
0
        rv = set_contains_entry((PySetObject *)other, key, hash);
2142
0
        if (rv < 0) {
2143
0
            Py_DECREF(result);
2144
0
            Py_DECREF(key);
2145
0
            return NULL;
2146
0
        }
2147
0
        if (!rv) {
2148
0
            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
0
        }
2154
0
        Py_DECREF(key);
2155
0
    }
2156
0
    return result;
2157
0
}
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
0
{
2205
0
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
2206
0
        Py_RETURN_NOTIMPLEMENTED;
2207
0
    PySetObject *so = _PySet_CAST(self);
2208
2209
0
    PyObject *rv;
2210
0
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2211
0
    rv = set_difference_untracked(so, other);
2212
0
    Py_END_CRITICAL_SECTION2();
2213
0
    if (rv != NULL) {
2214
0
        _PyObject_GC_TRACK(rv);
2215
0
    }
2216
0
    return rv;
2217
0
}
2218
2219
static PyObject *
2220
set_isub(PyObject *self, PyObject *other)
2221
0
{
2222
0
    if (!PyAnySet_Check(other))
2223
0
        Py_RETURN_NOTIMPLEMENTED;
2224
0
    PySetObject *so = _PySet_CAST(self);
2225
2226
0
    int rv;
2227
0
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2228
0
    rv = set_difference_update_internal(so, other);
2229
0
    Py_END_CRITICAL_SECTION2();
2230
0
    if (rv < 0) {
2231
0
        return NULL;
2232
0
    }
2233
0
    return Py_NewRef(so);
2234
0
}
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
40
{
2417
40
    setentry *entry;
2418
40
    Py_ssize_t pos = 0;
2419
40
    int rv;
2420
2421
40
    if (!PyAnySet_Check(other)) {
2422
0
        PyObject *tmp = set_intersection(so, other);
2423
0
        if (tmp == NULL) {
2424
0
            return NULL;
2425
0
        }
2426
0
        int result = (PySet_GET_SIZE(tmp) == PySet_GET_SIZE(so));
2427
0
        Py_DECREF(tmp);
2428
0
        return PyBool_FromLong(result);
2429
0
    }
2430
40
    if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
2431
0
        Py_RETURN_FALSE;
2432
2433
120
    while (set_next(so, &pos, &entry)) {
2434
80
        PyObject *key = entry->key;
2435
80
        Py_INCREF(key);
2436
80
        rv = set_contains_entry((PySetObject *)other, key, entry->hash);
2437
80
        Py_DECREF(key);
2438
80
        if (rv < 0) {
2439
0
            return NULL;
2440
0
        }
2441
80
        if (!rv) {
2442
0
            Py_RETURN_FALSE;
2443
0
        }
2444
80
    }
2445
40
    Py_RETURN_TRUE;
2446
40
}
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
0
{
2462
0
    if (PyAnySet_Check(other)) {
2463
0
        return set_issubset(other, (PyObject *)so);
2464
0
    }
2465
2466
0
    PyObject *key, *it = PyObject_GetIter(other);
2467
0
    if (it == NULL) {
2468
0
        return NULL;
2469
0
    }
2470
0
    while ((key = PyIter_Next(it)) != NULL) {
2471
0
        int rv = set_contains_key(so, key);
2472
0
        Py_DECREF(key);
2473
0
        if (rv < 0) {
2474
0
            Py_DECREF(it);
2475
0
            return NULL;
2476
0
        }
2477
0
        if (!rv) {
2478
0
            Py_DECREF(it);
2479
0
            Py_RETURN_FALSE;
2480
0
        }
2481
0
    }
2482
0
    Py_DECREF(it);
2483
0
    if (PyErr_Occurred()) {
2484
0
        return NULL;
2485
0
    }
2486
0
    Py_RETURN_TRUE;
2487
0
}
2488
2489
static PyObject *
2490
set_richcompare(PyObject *self, PyObject *w, int op)
2491
19.3k
{
2492
19.3k
    PySetObject *v = _PySet_CAST(self);
2493
0
    PyObject *r1;
2494
19.3k
    int r2;
2495
2496
19.3k
    if(!PyAnySet_Check(w))
2497
19.3k
        Py_RETURN_NOTIMPLEMENTED;
2498
2499
40
    switch (op) {
2500
0
    case Py_EQ:
2501
0
        if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
2502
0
            Py_RETURN_FALSE;
2503
0
        Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->hash);
2504
0
        Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(((PySetObject *)w)->hash);
2505
0
        if (v_hash != -1 && w_hash != -1 && v_hash != w_hash)
2506
0
            Py_RETURN_FALSE;
2507
0
        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
40
    case Py_LE:
2518
40
        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
40
    }
2530
40
    Py_RETURN_NOTIMPLEMENTED;
2531
40
}
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
182k
{
2549
182k
    if (set_add_key(so, key))
2550
0
        return NULL;
2551
182k
    Py_RETURN_NONE;
2552
182k
}
2553
2554
int
2555
_PySet_Contains(PySetObject *so, PyObject *key)
2556
26.9M
{
2557
26.9M
    assert(so);
2558
2559
26.9M
    Py_hash_t hash = PyObject_Hash(key);
2560
26.9M
    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
26.9M
    return set_contains_entry(so, key, hash);
2574
26.9M
}
2575
2576
static int
2577
set_contains(PyObject *self, PyObject *key)
2578
248
{
2579
248
    PySetObject *so = _PySet_CAST(self);
2580
0
    return _PySet_Contains(so, key);
2581
248
}
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
0
{
2597
0
    long result;
2598
2599
0
    result = _PySet_Contains(so, key);
2600
0
    if (result < 0)
2601
0
        return NULL;
2602
0
    return PyBool_FromLong(result);
2603
0
}
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
49
{
2619
49
    Py_hash_t hash = PyObject_Hash(key);
2620
49
    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
49
    setentry *entry; // unused
2631
49
    int status = set_do_lookup(so, so->table, so->mask, key, hash, &entry,
2632
49
                           set_compare_frozenset);
2633
49
    if (status < 0)
2634
0
        return NULL;
2635
49
    return PyBool_FromLong(status);
2636
49
}
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
47.7k
{
2654
47.7k
    int rv;
2655
2656
47.7k
    rv = set_discard_key(so, key);
2657
47.7k
    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
47.7k
    if (rv == DISCARD_NOTFOUND) {
2671
0
        _PyErr_SetKeyError(key);
2672
0
        return NULL;
2673
0
    }
2674
47.7k
    Py_RETURN_NONE;
2675
47.7k
}
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
0
{
2694
0
    int rv;
2695
2696
0
    rv = set_discard_key(so, key);
2697
0
    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
0
    Py_RETURN_NONE;
2710
0
}
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
58.6k
{
2795
58.6k
    assert(PyType_Check(type));
2796
2797
58.6k
    if (!_PyArg_NoKwnames("set", kwnames)) {
2798
0
        return NULL;
2799
0
    }
2800
2801
58.6k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
2802
58.6k
    if (!_PyArg_CheckPositional("set", nargs, 0, 1)) {
2803
0
        return NULL;
2804
0
    }
2805
2806
58.6k
    if (nargs) {
2807
102
        return make_new_set(_PyType_CAST(type), args[0]);
2808
102
    }
2809
2810
58.5k
    return make_new_set(_PyType_CAST(type), NULL);
2811
58.5k
}
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
39.8k
{
3035
39.8k
    return make_new_set(&PySet_Type, iterable);
3036
39.8k
}
3037
3038
PyObject *
3039
PyFrozenSet_New(PyObject *iterable)
3040
985
{
3041
985
    PyObject *result = make_new_set(&PyFrozenSet_Type, iterable);
3042
985
    if (result != NULL) {
3043
985
        _PyFrozenSet_MaybeUntrack(result);
3044
985
    }
3045
985
    return result;
3046
985
}
3047
3048
Py_ssize_t
3049
PySet_Size(PyObject *anyset)
3050
0
{
3051
0
    if (!PyAnySet_Check(anyset)) {
3052
0
        PyErr_BadInternalCall();
3053
0
        return -1;
3054
0
    }
3055
0
    return set_len(anyset);
3056
0
}
3057
3058
int
3059
PySet_Clear(PyObject *set)
3060
195
{
3061
195
    if (!PySet_Check(set)) {
3062
0
        PyErr_BadInternalCall();
3063
0
        return -1;
3064
0
    }
3065
195
    (void)set_clear(set, NULL);
3066
195
    return 0;
3067
195
}
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
720
{
3078
720
    if (!PyAnySet_Check(anyset)) {
3079
0
        PyErr_BadInternalCall();
3080
0
        return -1;
3081
0
    }
3082
3083
720
    PySetObject *so = (PySetObject *)anyset;
3084
720
    Py_hash_t hash = PyObject_Hash(key);
3085
720
    if (hash == -1) {
3086
0
        set_unhashable_type(key);
3087
0
        return -1;
3088
0
    }
3089
720
    return set_contains_entry(so, key, hash);
3090
720
}
3091
3092
int
3093
PySet_Discard(PyObject *set, PyObject *key)
3094
723
{
3095
723
    if (!PySet_Check(set)) {
3096
0
        PyErr_BadInternalCall();
3097
0
        return -1;
3098
0
    }
3099
3100
723
    int rv;
3101
723
    Py_BEGIN_CRITICAL_SECTION(set);
3102
723
    rv = set_discard_key((PySetObject *)set, key);
3103
723
    Py_END_CRITICAL_SECTION();
3104
723
    return rv;
3105
723
}
3106
3107
int
3108
PySet_Add(PyObject *anyset, PyObject *key)
3109
3.17k
{
3110
3.17k
    if (PySet_Check(anyset)) {
3111
1.59k
        int rv;
3112
1.59k
        Py_BEGIN_CRITICAL_SECTION(anyset);
3113
1.59k
        rv = set_add_key((PySetObject *)anyset, key);
3114
1.59k
        Py_END_CRITICAL_SECTION();
3115
1.59k
        return rv;
3116
1.59k
    }
3117
3118
1.58k
    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
1.58k
        if (PyFrozenSet_CheckExact(anyset) && !PyObject_GC_IsTracked(anyset) && PyObject_GC_IsTracked(key)) {
3126
0
            _PyObject_GC_TRACK(anyset);
3127
0
        }
3128
1.58k
        return set_add_key((PySetObject *)anyset, key);
3129
1.58k
    }
3130
3131
0
    PyErr_BadInternalCall();
3132
0
    return -1;
3133
1.58k
}
3134
3135
int
3136
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3137
559
{
3138
559
    setentry *entry;
3139
3140
559
    if (!PyAnySet_Check(set)) {
3141
0
        PyErr_BadInternalCall();
3142
0
        return -1;
3143
0
    }
3144
559
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3145
195
        return 0;
3146
364
    *key = entry->key;
3147
364
    *hash = entry->hash;
3148
364
    return 1;
3149
559
}
3150
3151
int
3152
_PySet_NextEntryRef(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3153
67.3k
{
3154
67.3k
    setentry *entry;
3155
3156
67.3k
    if (!PyAnySet_Check(set)) {
3157
0
        PyErr_BadInternalCall();
3158
0
        return -1;
3159
0
    }
3160
67.3k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(set);
3161
67.3k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3162
19.3k
        return 0;
3163
47.9k
    *key = Py_NewRef(entry->key);
3164
47.9k
    *hash = entry->hash;
3165
47.9k
    return 1;
3166
67.3k
}
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
0
{
3181
0
    if (!PySet_Check(set)) {
3182
0
        PyErr_BadInternalCall();
3183
0
        return -1;
3184
0
    }
3185
0
    return set_update_internal((PySetObject *)set, iterable);
3186
0
}
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);