Coverage Report

Created: 2026-08-13 06:33

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
1.94M
#define dummy (&_dummy_struct)
65
66
14.7M
#define SET_LOOKKEY_FOUND 1
67
58.7M
#define SET_LOOKKEY_NO_MATCH 0
68
0
#define SET_LOOKKEY_ERROR (-1)
69
10.0M
#define SET_LOOKKEY_CHANGED (-2)
70
47.5M
#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
42.7k
#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
14.6M
{
141
14.6M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
142
14.6M
    if (entry->hash == 0 && entry->key == NULL)
143
6.18M
        return SET_LOOKKEY_EMPTY;
144
8.42M
    if (entry->hash == hash) {
145
3.85M
        PyObject *startkey = entry->key;
146
3.85M
        assert(startkey != dummy);
147
3.85M
        if (startkey == key)
148
3.85M
            return SET_LOOKKEY_FOUND;
149
291
        if (PyUnicode_CheckExact(startkey)
150
291
            && PyUnicode_CheckExact(key)
151
235
            && unicode_eq(startkey, key))
152
235
            return SET_LOOKKEY_FOUND;
153
56
        table = so->table;
154
56
        Py_INCREF(startkey);
155
56
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
156
56
        Py_DECREF(startkey);
157
56
        if (cmp < 0)
158
0
            return SET_LOOKKEY_ERROR;
159
56
        if (table != so->table || entry->key != startkey)
160
0
            return SET_LOOKKEY_CHANGED;
161
56
        if (cmp > 0)
162
56
            return SET_LOOKKEY_FOUND;
163
56
    }
164
4.56M
    return SET_LOOKKEY_NO_MATCH;
165
8.42M
}
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
21.9M
{
175
21.9M
    assert(PyFrozenSet_Check(so));
176
21.9M
    PyObject *startkey = ep->key;
177
21.9M
    if (startkey == NULL) {
178
10.2M
        return SET_LOOKKEY_EMPTY;
179
10.2M
    }
180
11.7M
    if (startkey == key) {
181
10.9M
        return SET_LOOKKEY_FOUND;
182
10.9M
    }
183
868k
    Py_ssize_t ep_hash = ep->hash;
184
868k
    if (ep_hash == hash) {
185
78.4k
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
186
78.4k
        if (cmp < 0) {
187
0
            return SET_LOOKKEY_ERROR;
188
0
        }
189
78.4k
        assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH);
190
78.4k
        return cmp;
191
78.4k
    }
192
790k
    return SET_LOOKKEY_NO_MATCH;
193
868k
}
194
195
static void
196
set_zero_table(setentry *table, size_t size)
197
62.9k
{
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
62.9k
    memset(table, 0, sizeof(setentry)*size);
206
62.9k
#endif
207
62.9k
}
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
47.0M
#define LINEAR_PROBES 9
215
#endif
216
217
/* This must be >= 1 */
218
2.58M
#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
31.1M
{
224
31.1M
    setentry *entry;
225
31.1M
    size_t perturb = hash;
226
31.1M
    size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
227
31.1M
    int probes;
228
31.1M
    int status;
229
230
33.4M
    while (1) {
231
33.4M
        entry = &table[i];
232
33.4M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
233
36.6M
        do {
234
36.6M
            status = compare_entry(so, table, entry, key, hash);
235
36.6M
            if (status != SET_LOOKKEY_NO_MATCH) {
236
31.1M
                if (status == SET_LOOKKEY_EMPTY) {
237
16.4M
                    return SET_LOOKKEY_NO_MATCH;
238
16.4M
                }
239
14.7M
                *epp = entry;
240
14.7M
                return status;
241
31.1M
            }
242
5.43M
            entry++;
243
5.43M
        } while (probes--);
244
2.29M
        perturb >>= PERTURB_SHIFT;
245
2.29M
        i = (i * 5 + 1 + perturb) & mask;
246
2.29M
    }
247
31.1M
    Py_UNREACHABLE();
248
31.1M
}
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
807k
{
255
807k
    setentry *table;
256
807k
    setentry *freeslot;
257
807k
    setentry *entry;
258
807k
    size_t perturb;
259
807k
    size_t mask;
260
807k
    size_t i;                       /* Unsigned for defined overflow behavior */
261
807k
    int probes;
262
807k
    int cmp;
263
264
807k
  restart:
265
266
807k
    mask = so->mask;
267
807k
    i = (size_t)hash & mask;
268
807k
    freeslot = NULL;
269
807k
    perturb = hash;
270
271
1.04M
    while (1) {
272
1.04M
        entry = &so->table[i];
273
1.04M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
274
1.14M
        do {
275
1.14M
            if (entry->hash == 0 && entry->key == NULL)
276
720k
                goto found_unused_or_dummy;
277
424k
            if (entry->hash == hash) {
278
194k
                PyObject *startkey = entry->key;
279
194k
                assert(startkey != dummy);
280
194k
                if (startkey == key)
281
16.1k
                    goto found_active;
282
178k
                if (PyUnicode_CheckExact(startkey)
283
178k
                    && PyUnicode_CheckExact(key)
284
57.6k
                    && unicode_eq(startkey, key))
285
57.6k
                    goto found_active;
286
120k
                table = so->table;
287
120k
                Py_INCREF(startkey);
288
120k
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
289
120k
                Py_DECREF(startkey);
290
120k
                if (cmp > 0)
291
13.4k
                    goto found_active;
292
107k
                if (cmp < 0)
293
0
                    goto comparison_error;
294
107k
                if (table != so->table || entry->key != startkey)
295
0
                    goto restart;
296
107k
                mask = so->mask;
297
107k
            }
298
229k
            else if (entry->hash == -1) {
299
21.1k
                assert (entry->key == dummy);
300
21.1k
                freeslot = entry;
301
21.1k
            }
302
337k
            entry++;
303
337k
        } while (probes--);
304
242k
        perturb >>= PERTURB_SHIFT;
305
242k
        i = (i * 5 + 1 + perturb) & mask;
306
242k
    }
307
308
720k
  found_unused_or_dummy:
309
720k
    if (freeslot == NULL)
310
705k
        goto found_unused;
311
15.3k
    if (freeslot->hash != -1) {
312
0
        goto restart;
313
0
    }
314
15.3k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
315
15.3k
    FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash);
316
15.3k
    FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key);
317
15.3k
    return 0;
318
319
705k
  found_unused:
320
705k
    so->fill++;
321
705k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
322
705k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
323
705k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
324
705k
    if ((size_t)so->fill*5 < mask*3)
325
678k
        return 0;
326
27.1k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
327
328
87.2k
  found_active:
329
87.2k
    Py_DECREF(key);
330
87.2k
    return 0;
331
332
0
  comparison_error:
333
0
    Py_DECREF(key);
334
0
    return -1;
335
705k
}
336
337
static int
338
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
339
787k
{
340
787k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
341
342
787k
    return set_add_entry_takeref(so, Py_NewRef(key), hash);
343
787k
}
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
20.3k
{
364
20.3k
    Py_hash_t hash = PyObject_Hash(key);
365
20.3k
    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
20.3k
    return set_add_entry_takeref(so, key, hash);
373
20.3k
}
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
239k
{
386
239k
    setentry *entry;
387
239k
    size_t perturb = hash;
388
239k
    size_t i = (size_t)hash & mask;
389
239k
    size_t j;
390
391
288k
    while (1) {
392
288k
        entry = &table[i];
393
288k
        if (entry->key == NULL)
394
221k
            goto found_null;
395
66.6k
        if (i + LINEAR_PROBES <= mask) {
396
28.3k
            for (j = 0; j < LINEAR_PROBES; j++) {
397
28.3k
                entry++;
398
28.3k
                if (entry->key == NULL)
399
17.9k
                    goto found_null;
400
28.3k
            }
401
17.9k
        }
402
48.6k
        perturb >>= PERTURB_SHIFT;
403
48.6k
        i = (i * 5 + 1 + perturb) & mask;
404
48.6k
    }
405
239k
  found_null:
406
239k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
407
239k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
408
239k
}
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
31.1M
{
416
31.1M
    int status;
417
31.1M
    if (PyFrozenSet_CheckExact(so)) {
418
21.1M
        status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
419
21.1M
                               set_compare_frozenset);
420
21.1M
    }
421
10.0M
    else {
422
10.0M
        Py_BEGIN_CRITICAL_SECTION(so);
423
10.0M
        do {
424
10.0M
            status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
425
10.0M
                                   set_compare_entry_lock_held);
426
10.0M
        } while (status == SET_LOOKKEY_CHANGED);
427
10.0M
        Py_END_CRITICAL_SECTION();
428
10.0M
    }
429
31.1M
    assert(status == SET_LOOKKEY_FOUND ||
430
31.1M
           status == SET_LOOKKEY_NO_MATCH ||
431
31.1M
           status == SET_LOOKKEY_ERROR);
432
31.1M
    return status;
433
31.1M
}
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
42.7k
{
469
#ifdef Py_GIL_DISABLED
470
    if (use_qsbr) {
471
        _PyMem_FreeDelayed(entries, size * sizeof(setentry));
472
        return;
473
    }
474
#endif
475
42.7k
    PyMem_Free(entries);
476
42.7k
}
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
62.7k
{
486
62.7k
    setentry *oldtable, *newtable, *entry;
487
62.7k
    Py_ssize_t oldmask = so->mask;
488
62.7k
    Py_ssize_t oldsize = (size_t)oldmask + 1;
489
62.7k
    size_t newmask;
490
62.7k
    int is_oldtable_malloced;
491
62.7k
    setentry small_copy[PySet_MINSIZE];
492
493
62.7k
    assert(minused >= 0);
494
495
    /* Find the smallest table size > minused. */
496
    /* XXX speed-up with intrinsics */
497
62.7k
    size_t newsize = PySet_MINSIZE;
498
150k
    while (newsize <= (size_t)minused) {
499
87.9k
        newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
500
87.9k
    }
501
502
    /* Get space for a new table. */
503
62.7k
    oldtable = so->table;
504
62.7k
    assert(oldtable != NULL);
505
62.7k
    is_oldtable_malloced = oldtable != so->smalltable;
506
507
62.7k
    if (newsize == PySet_MINSIZE) {
508
        /* A large table is shrinking, or we can't get any smaller. */
509
19.5k
        newtable = so->smalltable;
510
19.5k
        if (newtable == oldtable) {
511
19.5k
            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.5k
            assert(so->fill > so->used);
522
19.5k
            memcpy(small_copy, oldtable, sizeof(small_copy));
523
19.5k
            oldtable = small_copy;
524
19.5k
        }
525
19.5k
    }
526
43.1k
    else {
527
43.1k
        newtable = PyMem_NEW(setentry, newsize);
528
43.1k
        if (newtable == NULL) {
529
0
            PyErr_NoMemory();
530
0
            return -1;
531
0
        }
532
43.1k
    }
533
534
    /* Make the set empty, using the new table. */
535
62.7k
    assert(newtable != oldtable);
536
62.7k
    set_zero_table(newtable, newsize);
537
62.7k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
538
62.7k
    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
62.7k
    newmask = (size_t)so->mask;
543
62.7k
    if (so->fill == so->used) {
544
433k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
545
396k
            if (entry->key != NULL) {
546
173k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
547
173k
            }
548
396k
        }
549
37.6k
    } else {
550
25.1k
        so->fill = so->used;
551
226k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
552
200k
            if (entry->key != NULL && entry->key != dummy) {
553
15.1k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
554
15.1k
            }
555
200k
        }
556
25.1k
    }
557
558
62.7k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, newtable);
559
560
62.7k
    if (is_oldtable_malloced)
561
3.50k
        free_entries(oldtable, oldsize, SET_IS_SHARED(so));
562
62.7k
    return 0;
563
62.7k
}
564
565
static int
566
set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
567
30.7M
{
568
#ifdef Py_GIL_DISABLED
569
    return set_lookkey_threadsafe(so, key, hash);
570
#else
571
30.7M
    setentry *entry; // unused
572
30.7M
    return set_lookkey(so, key, hash, &entry);
573
30.7M
#endif
574
30.7M
}
575
576
331k
#define DISCARD_NOTFOUND 0
577
105k
#define DISCARD_FOUND 1
578
579
static int
580
set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
581
388k
{
582
388k
    setentry *entry;
583
388k
    PyObject *old_key;
584
388k
    int status = set_lookkey(so, key, hash, &entry);
585
388k
    if (status < 0) {
586
0
        return -1;
587
0
    }
588
388k
    if (status == SET_LOOKKEY_NO_MATCH) {
589
283k
        return DISCARD_NOTFOUND;
590
283k
    }
591
388k
    assert(status == SET_LOOKKEY_FOUND);
592
105k
    old_key = entry->key;
593
105k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
594
105k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
595
105k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
596
105k
    Py_DECREF(old_key);
597
105k
    return DISCARD_FOUND;
598
105k
}
599
600
static int
601
set_add_key(PySetObject *so, PyObject *key)
602
640k
{
603
640k
    Py_hash_t hash = PyObject_Hash(key);
604
640k
    if (hash == -1) {
605
0
        set_unhashable_type(key);
606
0
        return -1;
607
0
    }
608
640k
    return set_add_entry(so, key, hash);
609
640k
}
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
340k
{
625
340k
    Py_hash_t hash = PyObject_Hash(key);
626
340k
    if (hash == -1) {
627
0
        set_unhashable_type(key);
628
0
        return -1;
629
0
    }
630
340k
    return set_discard_entry(so, key, hash);
631
340k
}
632
633
static void
634
set_empty_to_minsize(PySetObject *so)
635
214
{
636
214
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
637
214
    set_zero_table(so->smalltable, PySet_MINSIZE);
638
214
    so->fill = 0;
639
214
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0);
640
214
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, PySet_MINSIZE - 1);
641
214
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1);
642
214
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, so->smalltable);
643
214
}
644
645
static int
646
set_clear_internal(PyObject *self)
647
214
{
648
214
    PySetObject *so = _PySet_CAST(self);
649
0
    setentry *entry;
650
214
    setentry *table = so->table;
651
214
    Py_ssize_t fill = so->fill;
652
214
    Py_ssize_t used = so->used;
653
214
    Py_ssize_t oldsize = (size_t)so->mask + 1;
654
214
    int table_is_malloced = table != so->smalltable;
655
214
    setentry small_copy[PySet_MINSIZE];
656
657
214
    assert (PyAnySet_Check(so));
658
214
    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
214
    if (table_is_malloced)
667
0
        set_empty_to_minsize(so);
668
669
214
    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
214
        memcpy(small_copy, table, sizeof(small_copy));
675
214
        table = small_copy;
676
214
        set_empty_to_minsize(so);
677
214
    }
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.08k
    for (entry = table; used > 0; entry++) {
685
867
        if (entry->key && entry->key != dummy) {
686
214
            used--;
687
214
            Py_DECREF(entry->key);
688
214
        }
689
867
    }
690
691
214
    if (table_is_malloced)
692
0
        free_entries(table, oldsize, SET_IS_SHARED(so));
693
214
    return 0;
694
214
}
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
660k
{
712
660k
    Py_ssize_t i;
713
660k
    Py_ssize_t mask;
714
660k
    setentry *entry;
715
716
660k
    assert (PyAnySet_Check(so));
717
660k
    i = *pos_ptr;
718
660k
    assert(i >= 0);
719
660k
    mask = so->mask;
720
660k
    entry = &so->table[i];
721
2.05M
    while (i <= mask && (entry->key == NULL || entry->key == dummy)) {
722
1.39M
        i++;
723
1.39M
        entry++;
724
1.39M
    }
725
660k
    *pos_ptr = i+1;
726
660k
    if (i > mask)
727
109k
        return 0;
728
660k
    assert(entry != NULL);
729
551k
    *entry_ptr = entry;
730
551k
    return 1;
731
551k
}
732
733
static void
734
set_dealloc(PyObject *self)
735
663k
{
736
663k
    PySetObject *so = _PySet_CAST(self);
737
0
    setentry *entry;
738
663k
    Py_ssize_t used = so->used;
739
663k
    Py_ssize_t oldsize = (size_t)so->mask + 1;
740
741
    /* bpo-31095: UnTrack is needed before calling any callbacks */
742
663k
    PyObject_GC_UnTrack(so);
743
663k
    FT_CLEAR_WEAKREFS(self, so->weakreflist);
744
745
3.17M
    for (entry = so->table; used > 0; entry++) {
746
2.50M
        if (entry->key && entry->key != dummy) {
747
866k
                used--;
748
866k
                Py_DECREF(entry->key);
749
866k
        }
750
2.50M
    }
751
663k
    if (so->table != so->smalltable)
752
39.2k
        free_entries(so->table, oldsize, SET_IS_SHARED(so));
753
663k
    Py_TYPE(so)->tp_free(so);
754
663k
}
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
367k
{
824
367k
    PySetObject *so = _PySet_CAST(self);
825
367k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
826
367k
}
827
828
static int
829
set_merge_lock_held(PySetObject *so, PyObject *otherset)
830
465k
{
831
465k
    PySetObject *other;
832
465k
    PyObject *key;
833
465k
    Py_ssize_t i;
834
465k
    setentry *so_entry;
835
465k
    setentry *other_entry;
836
837
465k
    assert (PyAnySet_Check(so));
838
465k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
839
465k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(otherset);
840
841
465k
    other = _PySet_CAST(otherset);
842
465k
    if (other == so || other->used == 0)
843
        /* a.update(a) or a.update(set()); nothing to do */
844
333k
        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
132k
    if ((so->fill + other->used)*5 >= so->mask*3) {
850
16.0k
        if (set_table_resize(so, (so->used + other->used)*2) != 0)
851
0
            return -1;
852
16.0k
    }
853
132k
    so_entry = so->table;
854
132k
    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
132k
    if (so->fill == 0 && so->mask == other->mask && other->fill == other->used) {
859
1.24M
        for (i = 0; i <= other->mask; i++, so_entry++, other_entry++) {
860
1.13M
            key = other_entry->key;
861
1.13M
            if (key != NULL) {
862
313k
                assert(so_entry->key == NULL);
863
313k
                FT_ATOMIC_STORE_SSIZE_RELAXED(so_entry->hash, other_entry->hash);
864
313k
                FT_ATOMIC_STORE_PTR_RELEASE(so_entry->key, Py_NewRef(key));
865
313k
            }
866
1.13M
        }
867
111k
        so->fill = other->fill;
868
111k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
869
111k
        return 0;
870
111k
    }
871
872
    /* If our table is empty, we can use set_insert_clean() */
873
21.5k
    if (so->fill == 0) {
874
3.96k
        setentry *newtable = so->table;
875
3.96k
        size_t newmask = (size_t)so->mask;
876
3.96k
        so->fill = other->used;
877
3.96k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
878
215k
        for (i = other->mask + 1; i > 0 ; i--, other_entry++) {
879
211k
            key = other_entry->key;
880
211k
            if (key != NULL && key != dummy) {
881
50.5k
                set_insert_clean(newtable, newmask, Py_NewRef(key),
882
50.5k
                                 other_entry->hash);
883
50.5k
            }
884
211k
        }
885
3.96k
        return 0;
886
3.96k
    }
887
888
    /* We can't assure there are no duplicates, so do normal insertions */
889
307k
    for (i = 0; i <= other->mask; i++) {
890
290k
        other_entry = &other->table[i];
891
290k
        key = other_entry->key;
892
290k
        if (key != NULL && key != dummy) {
893
98.6k
            if (set_add_entry(so, key, other_entry->hash))
894
0
                return -1;
895
98.6k
        }
896
290k
    }
897
17.5k
    return 0;
898
17.5k
}
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
94.0k
{
914
    /* Make sure the search finger is in bounds */
915
94.0k
    setentry *entry = so->table + (so->finger & so->mask);
916
94.0k
    setentry *limit = so->table + so->mask;
917
94.0k
    PyObject *key;
918
919
94.0k
    if (so->used == 0) {
920
0
        PyErr_SetString(PyExc_KeyError, "pop from an empty set");
921
0
        return NULL;
922
0
    }
923
352k
    while (entry->key == NULL || entry->key==dummy) {
924
258k
        entry++;
925
258k
        if (entry > limit)
926
15.2k
            entry = so->table;
927
258k
    }
928
94.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
929
94.0k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
930
94.0k
    key = entry->key;
931
94.0k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
932
94.0k
    so->finger = entry - so->table + 1;   /* next place to start */
933
94.0k
    return key;
934
94.0k
}
935
936
static int
937
set_traverse(PyObject *self, visitproc visit, void *arg)
938
34.6k
{
939
34.6k
    PySetObject *so = _PySet_CAST(self);
940
0
    Py_ssize_t pos = 0;
941
34.6k
    setentry *entry;
942
943
256k
    while (set_next(so, &pos, &entry))
944
221k
        Py_VISIT(entry->key);
945
34.6k
    return 0;
946
34.6k
}
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
183k
{
956
183k
    return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL;
957
183k
}
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
9.73k
{
975
9.73k
    PySetObject *so = _PySet_CAST(self);
976
0
    Py_uhash_t hash = 0;
977
9.73k
    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
189k
    for (entry = so->table; entry <= &so->table[so->mask]; entry++)
990
179k
        hash ^= _shuffle_bits(entry->hash);
991
992
    /* Remove the effect of an odd number of NULL entries */
993
9.73k
    if ((so->mask + 1 - so->fill) & 1)
994
4.21k
        hash ^= _shuffle_bits(0);
995
996
    /* Remove the effect of an odd number of dummy entries */
997
9.73k
    if ((so->fill - so->used) & 1)
998
0
        hash ^= _shuffle_bits(-1);
999
1000
    /* Factor in the number of active entries */
1001
9.73k
    hash ^= ((Py_uhash_t)PySet_GET_SIZE(self) + 1) * 1927868237UL;
1002
1003
    /* Disperse patterns arising in nested frozensets */
1004
9.73k
    hash ^= (hash >> 11) ^ (hash >> 25);
1005
9.73k
    hash = hash * 69069U + 907133923UL;
1006
1007
    /* -1 is reserved as an error code */
1008
9.73k
    if (hash == (Py_uhash_t)-1)
1009
0
        hash = 590923713UL;
1010
1011
9.73k
    return (Py_hash_t)hash;
1012
9.73k
}
1013
1014
static Py_hash_t
1015
frozenset_hash(PyObject *self)
1016
12.0k
{
1017
12.0k
    PySetObject *so = _PySet_CAST(self);
1018
0
    Py_uhash_t hash;
1019
1020
12.0k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) {
1021
2.28k
        return FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->hash);
1022
2.28k
    }
1023
1024
9.73k
    hash = frozenset_hash_impl(self);
1025
9.73k
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->hash, hash);
1026
9.73k
    return hash;
1027
12.0k
}
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
124k
{
1042
124k
    setiterobject *si = (setiterobject*)self;
1043
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1044
124k
    _PyObject_GC_UNTRACK(si);
1045
124k
    Py_XDECREF(si->si_set);
1046
124k
    PyObject_GC_Del(si);
1047
124k
}
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
269k
{
1097
269k
    setiterobject *si = (setiterobject*)self;
1098
269k
    PyObject *key = NULL;
1099
269k
    Py_ssize_t i, mask;
1100
269k
    setentry *entry;
1101
269k
    PySetObject *so = si->si_set;
1102
1103
269k
    if (so == NULL)
1104
0
        return NULL;
1105
269k
    assert (PyAnySet_Check(so));
1106
1107
269k
    Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
1108
269k
    Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used);
1109
269k
    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
269k
    Py_BEGIN_CRITICAL_SECTION(so);
1117
269k
    i = si->si_pos;
1118
269k
    assert(i>=0);
1119
269k
    entry = so->table;
1120
269k
    mask = so->mask;
1121
1.14M
    while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
1122
870k
        i++;
1123
870k
    }
1124
269k
    if (i <= mask) {
1125
145k
        key = Py_NewRef(entry[i].key);
1126
145k
    }
1127
269k
    Py_END_CRITICAL_SECTION();
1128
269k
    si->si_pos = i+1;
1129
269k
    if (key == NULL) {
1130
124k
        si->si_set = NULL;
1131
124k
        Py_DECREF(so);
1132
124k
        return NULL;
1133
124k
    }
1134
145k
    si->len--;
1135
145k
    return key;
1136
269k
}
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
124k
{
1174
124k
    Py_ssize_t size = set_len(so);
1175
124k
    setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
1176
124k
    if (si == NULL)
1177
0
        return NULL;
1178
124k
    si->si_set = (PySetObject*)Py_NewRef(so);
1179
124k
    si->si_used = size;
1180
124k
    si->si_pos = 0;
1181
124k
    si->len = size;
1182
124k
    _PyObject_GC_TRACK(si);
1183
124k
    return (PyObject *)si;
1184
124k
}
1185
1186
static int
1187
set_update_dict_lock_held(PySetObject *so, PyObject *other)
1188
19.6k
{
1189
19.6k
    assert(PyAnyDict_CheckExact(other));
1190
1191
19.6k
    _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.6k
    Py_ssize_t dictsize = PyDict_GET_SIZE(other);
1203
19.6k
    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.6k
    Py_ssize_t pos = 0;
1210
19.6k
    PyObject *key;
1211
19.6k
    PyObject *value;
1212
19.6k
    Py_hash_t hash;
1213
68.1k
    while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
1214
48.4k
        if (set_add_entry(so, key, hash)) {
1215
0
            return -1;
1216
0
        }
1217
48.4k
    }
1218
19.6k
    return 0;
1219
19.6k
}
1220
1221
static int
1222
set_update_iterable_lock_held(PySetObject *so, PyObject *other)
1223
9.87k
{
1224
9.87k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1225
1226
9.87k
    PyObject *it = PyObject_GetIter(other);
1227
9.87k
    if (it == NULL) {
1228
0
        return -1;
1229
0
    }
1230
1231
9.87k
    PyObject *key;
1232
67.1k
    while ((key = PyIter_Next(it)) != NULL) {
1233
57.2k
        if (set_add_key(so, key)) {
1234
0
            Py_DECREF(it);
1235
0
            Py_DECREF(key);
1236
0
            return -1;
1237
0
        }
1238
57.2k
        Py_DECREF(key);
1239
57.2k
    }
1240
9.87k
    Py_DECREF(it);
1241
9.87k
    if (PyErr_Occurred())
1242
0
        return -1;
1243
9.87k
    return 0;
1244
9.87k
}
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
226k
{
1262
226k
    assert(Py_REFCNT(so) == 1);
1263
226k
    if (PyAnySet_Check(other)) {
1264
196k
        int rv;
1265
196k
        Py_BEGIN_CRITICAL_SECTION(other);
1266
196k
        rv = set_merge_lock_held(so, other);
1267
196k
        Py_END_CRITICAL_SECTION();
1268
196k
        return rv;
1269
196k
    }
1270
29.5k
    else if (PyDict_CheckExact(other)) {
1271
19.6k
        int rv;
1272
19.6k
        Py_BEGIN_CRITICAL_SECTION(other);
1273
19.6k
        rv = set_update_dict_lock_held(so, other);
1274
19.6k
        Py_END_CRITICAL_SECTION();
1275
19.6k
        return rv;
1276
19.6k
    }
1277
9.87k
    else if (PyFrozenDict_CheckExact(other)) {
1278
0
        return set_update_dict_lock_held(so, other);
1279
0
    }
1280
9.87k
    return set_update_iterable_lock_held(so, other);
1281
226k
}
1282
1283
static int
1284
set_update_internal(PySetObject *so, PyObject *other)
1285
229k
{
1286
229k
    if (PyAnySet_Check(other)) {
1287
229k
        if (Py_Is((PyObject *)so, other)) {
1288
0
            return 0;
1289
0
        }
1290
229k
        int rv;
1291
229k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1292
229k
        rv = set_merge_lock_held(so, other);
1293
229k
        Py_END_CRITICAL_SECTION2();
1294
229k
        return rv;
1295
229k
    }
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
229k
}
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
665k
{
1353
665k
    assert(PyType_Check(type));
1354
665k
    PySetObject *so;
1355
1356
665k
    so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
1357
665k
    if (so == NULL)
1358
0
        return NULL;
1359
1360
665k
    so->fill = 0;
1361
665k
    so->used = 0;
1362
665k
    so->mask = PySet_MINSIZE - 1;
1363
665k
    so->table = so->smalltable;
1364
665k
    so->hash = -1;
1365
665k
    so->finger = 0;
1366
665k
    so->weakreflist = NULL;
1367
1368
665k
    if (iterable != NULL) {
1369
206k
        if (set_update_local(so, iterable)) {
1370
0
            Py_DECREF(so);
1371
0
            return NULL;
1372
0
        }
1373
206k
    }
1374
1375
665k
    return (PyObject *)so;
1376
665k
}
1377
1378
static PyObject *
1379
make_new_set(PyTypeObject *type, PyObject *iterable)
1380
626k
{
1381
626k
    PyObject *so = make_new_set_untracked(type, iterable);
1382
626k
    if (so != NULL) {
1383
626k
        _PyObject_GC_TRACK(so);
1384
626k
    }
1385
626k
    return so;
1386
626k
}
1387
1388
static PyObject *
1389
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
1390
39.2k
{
1391
39.2k
    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
39.2k
    return make_new_set_untracked(type, iterable);
1398
39.2k
}
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
10.9k
{
1414
10.9k
    assert(op != NULL);
1415
    // subclasses of a frozenset can generate reference cycles, so do not untrack
1416
10.9k
    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
10.9k
    Py_ssize_t pos = 0;
1421
10.9k
    setentry *entry;
1422
45.6k
    while (set_next((PySetObject *)op, &pos, &entry)) {
1423
40.2k
        if (_PyObject_GC_MAY_BE_TRACKED(entry->key)) {
1424
5.46k
            return;
1425
5.46k
        }
1426
40.2k
    }
1427
5.44k
    _PyObject_GC_UNTRACK(op);
1428
5.44k
}
1429
1430
static PyObject *
1431
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
1432
67
{
1433
67
    if (type != &PyFrozenSet_Type) {
1434
0
        return make_new_set(type, iterable);
1435
0
    }
1436
1437
67
    if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
1438
        /* frozenset(f) is idempotent */
1439
0
        return Py_NewRef(iterable);
1440
0
    }
1441
67
    PyObject *obj = make_new_set(type, iterable);
1442
67
    if (obj != NULL) {
1443
67
        _PyFrozenSet_MaybeUntrack(obj);
1444
67
    }
1445
67
    return obj;
1446
67
}
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
67
{
1470
67
    if (!_PyArg_NoKwnames("frozenset", kwnames)) {
1471
0
        return NULL;
1472
0
    }
1473
1474
67
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1475
67
    if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
1476
0
        return NULL;
1477
0
    }
1478
1479
67
    PyObject *iterable = (nargs ? args[0] : NULL);
1480
67
    return make_new_frozenset(_PyType_CAST(type), iterable);
1481
67
}
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
18
{
1573
18
    assert(set != NULL);
1574
18
    assert(PySet_CheckExact(set));
1575
18
    assert(_PyObject_IsUniquelyReferenced(set));
1576
18
    set->ob_type = &PyFrozenSet_Type;
1577
18
    return Py_NewRef(set);
1578
18
}
1579
1580
static PyObject *
1581
set_copy_untracked_lock_held(PySetObject *so)
1582
39.1k
{
1583
39.1k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1584
39.1k
    PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1585
39.1k
    if (copy == NULL) {
1586
0
        return NULL;
1587
0
    }
1588
39.1k
    if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
1589
0
        Py_DECREF(copy);
1590
0
        return NULL;
1591
0
    }
1592
39.1k
    return copy;
1593
39.1k
}
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
39.1k
{
1607
39.1k
    PyObject *copy = set_copy_untracked_lock_held(so);
1608
39.1k
    if (copy != NULL) {
1609
39.1k
        _PyObject_GC_TRACK(copy);
1610
39.1k
    }
1611
39.1k
    return copy;
1612
39.1k
}
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
214
{
1644
214
    set_clear_internal((PyObject*)so);
1645
214
    Py_RETURN_NONE;
1646
214
}
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.5k
{
1686
19.5k
    PySetObject *result;
1687
1688
19.5k
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1689
0
        Py_RETURN_NOTIMPLEMENTED;
1690
1691
19.5k
    result = (PySetObject *)set_copy(self, NULL);
1692
19.5k
    if (result == NULL) {
1693
0
        return NULL;
1694
0
    }
1695
19.5k
    if (Py_Is(self, other)) {
1696
0
        return (PyObject *)result;
1697
0
    }
1698
19.5k
    if (set_update_local(result, other)) {
1699
0
        Py_DECREF(result);
1700
0
        return NULL;
1701
0
    }
1702
19.5k
    return (PyObject *)result;
1703
19.5k
}
1704
1705
static PyObject *
1706
set_ior(PyObject *self, PyObject *other)
1707
229k
{
1708
229k
    if (!PyAnySet_Check(other))
1709
0
        Py_RETURN_NOTIMPLEMENTED;
1710
229k
    PySetObject *so = _PySet_CAST(self);
1711
1712
229k
    if (set_update_internal(so, other)) {
1713
0
        return NULL;
1714
0
    }
1715
229k
    return Py_NewRef(so);
1716
229k
}
1717
1718
static PyObject *
1719
set_intersection(PySetObject *so, PyObject *other)
1720
42
{
1721
42
    PySetObject *result;
1722
42
    PyObject *key, *it, *tmp;
1723
42
    Py_hash_t hash;
1724
42
    int rv;
1725
1726
42
    if ((PyObject *)so == other)
1727
0
        return set_copy_impl(so);
1728
1729
42
    result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
1730
42
    if (result == NULL)
1731
0
        return NULL;
1732
1733
42
    if (PyAnySet_Check(other)) {
1734
42
        Py_ssize_t pos = 0;
1735
42
        setentry *entry;
1736
1737
42
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1738
36
            tmp = (PyObject *)so;
1739
36
            so = (PySetObject *)other;
1740
36
            other = tmp;
1741
36
        }
1742
1743
54
        while (set_next((PySetObject *)other, &pos, &entry)) {
1744
12
            key = entry->key;
1745
12
            hash = entry->hash;
1746
12
            Py_INCREF(key);
1747
12
            rv = set_contains_entry(so, key, hash);
1748
12
            if (rv < 0) {
1749
0
                Py_DECREF(result);
1750
0
                Py_DECREF(key);
1751
0
                return NULL;
1752
0
            }
1753
12
            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
12
            Py_DECREF(key);
1761
12
        }
1762
42
        _PyObject_GC_TRACK(result);
1763
42
        return (PyObject *)result;
1764
42
    }
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
42
{
1879
42
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1880
0
        Py_RETURN_NOTIMPLEMENTED;
1881
42
    PySetObject *so = _PySet_CAST(self);
1882
1883
0
    PyObject *rv;
1884
42
    Py_BEGIN_CRITICAL_SECTION2(so, other);
1885
42
    rv = set_intersection(so, other);
1886
42
    Py_END_CRITICAL_SECTION2();
1887
1888
42
    return rv;
1889
42
}
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.5k
{
1983
19.5k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1984
19.5k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
1985
1986
19.5k
    if ((PyObject *)so == other)
1987
0
        return set_clear_internal((PyObject*)so);
1988
1989
19.5k
    if (PyAnySet_Check(other)) {
1990
19.5k
        setentry *entry;
1991
19.5k
        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.5k
        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.5k
        } else {
2002
19.5k
            Py_INCREF(other);
2003
19.5k
        }
2004
2005
68.0k
        while (set_next((PySetObject *)other, &pos, &entry)) {
2006
48.4k
            PyObject *key = entry->key;
2007
48.4k
            Py_INCREF(key);
2008
48.4k
            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
48.4k
            Py_DECREF(key);
2014
48.4k
        }
2015
2016
19.5k
        Py_DECREF(other);
2017
19.5k
    } 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.5k
    if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4)
2037
0
        return 0;
2038
19.5k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
2039
19.5k
}
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.5k
{
2054
19.5k
    Py_ssize_t i;
2055
2056
39.1k
    for (i = 0; i < others_length; i++) {
2057
19.5k
        PyObject *other = others[i];
2058
19.5k
        int rv;
2059
19.5k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
2060
19.5k
        rv = set_difference_update_internal(so, other);
2061
19.5k
        Py_END_CRITICAL_SECTION2();
2062
19.5k
        if (rv) {
2063
0
            return NULL;
2064
0
        }
2065
19.5k
    }
2066
19.5k
    Py_RETURN_NONE;
2067
19.5k
}
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
6.45k
{
2417
6.45k
    setentry *entry;
2418
6.45k
    Py_ssize_t pos = 0;
2419
6.45k
    int rv;
2420
2421
6.45k
    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
6.45k
    if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
2431
0
        Py_RETURN_FALSE;
2432
2433
34.1k
    while (set_next(so, &pos, &entry)) {
2434
27.7k
        PyObject *key = entry->key;
2435
27.7k
        Py_INCREF(key);
2436
27.7k
        rv = set_contains_entry((PySetObject *)other, key, entry->hash);
2437
27.7k
        Py_DECREF(key);
2438
27.7k
        if (rv < 0) {
2439
0
            return NULL;
2440
0
        }
2441
27.7k
        if (!rv) {
2442
85
            Py_RETURN_FALSE;
2443
85
        }
2444
27.7k
    }
2445
6.45k
    Py_RETURN_TRUE;
2446
6.45k
}
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
26.0k
{
2492
26.0k
    PySetObject *v = _PySet_CAST(self);
2493
0
    PyObject *r1;
2494
26.0k
    int r2;
2495
2496
26.0k
    if(!PyAnySet_Check(w))
2497
19.5k
        Py_RETURN_NOTIMPLEMENTED;
2498
2499
6.45k
    switch (op) {
2500
6.40k
    case Py_EQ:
2501
6.40k
        if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
2502
0
            Py_RETURN_FALSE;
2503
6.40k
        Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->hash);
2504
6.40k
        Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(((PySetObject *)w)->hash);
2505
6.40k
        if (v_hash != -1 && w_hash != -1 && v_hash != w_hash)
2506
0
            Py_RETURN_FALSE;
2507
6.40k
        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
42
    case Py_LE:
2518
42
        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
6.45k
    }
2530
6.45k
    Py_RETURN_NOTIMPLEMENTED;
2531
6.45k
}
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
388k
{
2549
388k
    if (set_add_key(so, key))
2550
0
        return NULL;
2551
388k
    Py_RETURN_NONE;
2552
388k
}
2553
2554
int
2555
_PySet_Contains(PySetObject *so, PyObject *key)
2556
30.1M
{
2557
30.1M
    assert(so);
2558
2559
30.1M
    Py_hash_t hash = PyObject_Hash(key);
2560
30.1M
    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
30.1M
    return set_contains_entry(so, key, hash);
2574
30.1M
}
2575
2576
static int
2577
set_contains(PyObject *self, PyObject *key)
2578
277
{
2579
277
    PySetObject *so = _PySet_CAST(self);
2580
0
    return _PySet_Contains(so, key);
2581
277
}
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
64
{
2619
64
    Py_hash_t hash = PyObject_Hash(key);
2620
64
    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
64
    setentry *entry; // unused
2631
64
    int status = set_do_lookup(so, so->table, so->mask, key, hash, &entry,
2632
64
                           set_compare_frozenset);
2633
64
    if (status < 0)
2634
0
        return NULL;
2635
64
    return PyBool_FromLong(status);
2636
64
}
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
48.4k
{
2654
48.4k
    int rv;
2655
2656
48.4k
    rv = set_discard_key(so, key);
2657
48.4k
    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
48.4k
    if (rv == DISCARD_NOTFOUND) {
2671
0
        _PyErr_SetKeyError(key);
2672
0
        return NULL;
2673
0
    }
2674
48.4k
    Py_RETURN_NONE;
2675
48.4k
}
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
77.1k
{
2795
77.1k
    assert(PyType_Check(type));
2796
2797
77.1k
    if (!_PyArg_NoKwnames("set", kwnames)) {
2798
0
        return NULL;
2799
0
    }
2800
2801
77.1k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
2802
77.1k
    if (!_PyArg_CheckPositional("set", nargs, 0, 1)) {
2803
0
        return NULL;
2804
0
    }
2805
2806
77.1k
    if (nargs) {
2807
120
        return make_new_set(_PyType_CAST(type), args[0]);
2808
120
    }
2809
2810
76.9k
    return make_new_set(_PyType_CAST(type), NULL);
2811
76.9k
}
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
538k
{
3035
538k
    return make_new_set(&PySet_Type, iterable);
3036
538k
}
3037
3038
PyObject *
3039
PyFrozenSet_New(PyObject *iterable)
3040
10.8k
{
3041
10.8k
    PyObject *result = make_new_set(&PyFrozenSet_Type, iterable);
3042
10.8k
    if (result != NULL) {
3043
10.8k
        _PyFrozenSet_MaybeUntrack(result);
3044
10.8k
    }
3045
10.8k
    return result;
3046
10.8k
}
3047
3048
Py_ssize_t
3049
PySet_Size(PyObject *anyset)
3050
5.49k
{
3051
5.49k
    if (!PyAnySet_Check(anyset)) {
3052
0
        PyErr_BadInternalCall();
3053
0
        return -1;
3054
0
    }
3055
5.49k
    return set_len(anyset);
3056
5.49k
}
3057
3058
int
3059
PySet_Clear(PyObject *set)
3060
214
{
3061
214
    if (!PySet_Check(set)) {
3062
0
        PyErr_BadInternalCall();
3063
0
        return -1;
3064
0
    }
3065
214
    (void)set_clear(set, NULL);
3066
214
    return 0;
3067
214
}
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
640k
{
3078
640k
    if (!PyAnySet_Check(anyset)) {
3079
0
        PyErr_BadInternalCall();
3080
0
        return -1;
3081
0
    }
3082
3083
640k
    PySetObject *so = (PySetObject *)anyset;
3084
640k
    Py_hash_t hash = PyObject_Hash(key);
3085
640k
    if (hash == -1) {
3086
0
        set_unhashable_type(key);
3087
0
        return -1;
3088
0
    }
3089
640k
    return set_contains_entry(so, key, hash);
3090
640k
}
3091
3092
int
3093
PySet_Discard(PyObject *set, PyObject *key)
3094
291k
{
3095
291k
    if (!PySet_Check(set)) {
3096
0
        PyErr_BadInternalCall();
3097
0
        return -1;
3098
0
    }
3099
3100
291k
    int rv;
3101
291k
    Py_BEGIN_CRITICAL_SECTION(set);
3102
291k
    rv = set_discard_key((PySetObject *)set, key);
3103
291k
    Py_END_CRITICAL_SECTION();
3104
291k
    return rv;
3105
291k
}
3106
3107
int
3108
PySet_Add(PyObject *anyset, PyObject *key)
3109
194k
{
3110
194k
    if (PySet_Check(anyset)) {
3111
193k
        int rv;
3112
193k
        Py_BEGIN_CRITICAL_SECTION(anyset);
3113
193k
        rv = set_add_key((PySetObject *)anyset, key);
3114
193k
        Py_END_CRITICAL_SECTION();
3115
193k
        return rv;
3116
193k
    }
3117
3118
1.76k
    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.76k
        if (PyFrozenSet_CheckExact(anyset) && !PyObject_GC_IsTracked(anyset) && PyObject_GC_IsTracked(key)) {
3126
0
            _PyObject_GC_TRACK(anyset);
3127
0
        }
3128
1.76k
        return set_add_key((PySetObject *)anyset, key);
3129
1.76k
    }
3130
3131
0
    PyErr_BadInternalCall();
3132
0
    return -1;
3133
1.76k
}
3134
3135
int
3136
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3137
30.1k
{
3138
30.1k
    setentry *entry;
3139
3140
30.1k
    if (!PyAnySet_Check(set)) {
3141
0
        PyErr_BadInternalCall();
3142
0
        return -1;
3143
0
    }
3144
30.1k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3145
5.65k
        return 0;
3146
24.5k
    *key = entry->key;
3147
24.5k
    *hash = entry->hash;
3148
24.5k
    return 1;
3149
30.1k
}
3150
3151
int
3152
_PySet_NextEntryRef(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3153
225k
{
3154
225k
    setentry *entry;
3155
3156
225k
    if (!PyAnySet_Check(set)) {
3157
0
        PyErr_BadInternalCall();
3158
0
        return -1;
3159
0
    }
3160
225k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(set);
3161
225k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3162
37.2k
        return 0;
3163
188k
    *key = Py_NewRef(entry->key);
3164
188k
    *hash = entry->hash;
3165
188k
    return 1;
3166
225k
}
3167
3168
PyObject *
3169
PySet_Pop(PyObject *set)
3170
4.82k
{
3171
4.82k
    if (!PySet_Check(set)) {
3172
0
        PyErr_BadInternalCall();
3173
0
        return NULL;
3174
0
    }
3175
4.82k
    return set_pop(set, NULL);
3176
4.82k
}
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);