Coverage Report

Created: 2026-01-10 06:41

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