Coverage Report

Created: 2026-01-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/Objects/setobject.c
Line
Count
Source
1
2
/* set object implementation
3
4
   Written and maintained by Raymond D. Hettinger <python@rcn.com>
5
   Derived from Objects/dictobject.c.
6
7
   The basic lookup function used by all operations.
8
   This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
9
10
   The initial probe index is computed as hash mod the table size.
11
   Subsequent probe indices are computed as explained in Objects/dictobject.c.
12
13
   To improve cache locality, each probe inspects a series of consecutive
14
   nearby entries before moving on to probes elsewhere in memory.  This leaves
15
   us with a hybrid of linear probing and randomized probing.  The linear probing
16
   reduces the cost of hash collisions because consecutive memory accesses
17
   tend to be much cheaper than scattered probes.  After LINEAR_PROBES steps,
18
   we then use more of the upper bits from the hash value and apply a simple
19
   linear congruential random number generator.  This helps break-up long
20
   chains of collisions.
21
22
   All arithmetic on hash should ignore overflow.
23
24
   Unlike the dictionary implementation, the lookkey function can return
25
   NULL if the rich comparison returns an error.
26
27
   Use cases for sets differ considerably from dictionaries where looked-up
28
   keys are more likely to be present.  In contrast, sets are primarily
29
   about membership testing where the presence of an element is not known in
30
   advance.  Accordingly, the set implementation needs to optimize for both
31
   the found and not-found case.
32
*/
33
34
#include "Python.h"
35
#include "pycore_ceval.h"               // _PyEval_GetBuiltin()
36
#include "pycore_critical_section.h"    // Py_BEGIN_CRITICAL_SECTION, Py_END_CRITICAL_SECTION
37
#include "pycore_dict.h"                // _PyDict_Contains_KnownHash()
38
#include "pycore_modsupport.h"          // _PyArg_NoKwnames()
39
#include "pycore_object.h"              // _PyObject_GC_UNTRACK()
40
#include "pycore_pyatomic_ft_wrappers.h"  // FT_ATOMIC_LOAD_SSIZE_RELAXED()
41
#include "pycore_pyerrors.h"            // _PyErr_SetKeyError()
42
#include "pycore_setobject.h"           // _PySet_NextEntry() definition
43
#include "pycore_weakref.h"             // FT_CLEAR_WEAKREFS()
44
45
#include "stringlib/eq.h"               // unicode_eq()
46
#include <stddef.h>                     // offsetof()
47
#include "clinic/setobject.c.h"
48
49
/*[clinic input]
50
class set "PySetObject *" "&PySet_Type"
51
class frozenset "PySetObject *" "&PyFrozenSet_Type"
52
[clinic start generated code]*/
53
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=97ad1d3e9f117079]*/
54
55
/*[python input]
56
class setobject_converter(self_converter):
57
    type = "PySetObject *"
58
[python start generated code]*/
59
/*[python end generated code: output=da39a3ee5e6b4b0d input=33a44506d4d57793]*/
60
61
/* Object used as dummy key to fill deleted entries */
62
static PyObject _dummy_struct;
63
64
7.84M
#define dummy (&_dummy_struct)
65
66
14.9M
#define SET_LOOKKEY_FOUND 1
67
54.6M
#define SET_LOOKKEY_NO_MATCH 0
68
0
#define SET_LOOKKEY_ERROR (-1)
69
9.24M
#define SET_LOOKKEY_CHANGED (-2)
70
46.3M
#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
56.3k
#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
12.3M
{
141
12.3M
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
142
12.3M
    if (entry->hash == 0 && entry->key == NULL)
143
5.44M
        return SET_LOOKKEY_EMPTY;
144
6.91M
    if (entry->hash == hash) {
145
3.79M
        PyObject *startkey = entry->key;
146
3.79M
        assert(startkey != dummy);
147
3.79M
        if (startkey == key)
148
3.79M
            return SET_LOOKKEY_FOUND;
149
673
        if (PyUnicode_CheckExact(startkey)
150
673
            && PyUnicode_CheckExact(key)
151
587
            && unicode_eq(startkey, key))
152
587
            return SET_LOOKKEY_FOUND;
153
86
        table = so->table;
154
86
        Py_INCREF(startkey);
155
86
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
156
86
        Py_DECREF(startkey);
157
86
        if (cmp < 0)
158
0
            return SET_LOOKKEY_ERROR;
159
86
        if (table != so->table || entry->key != startkey)
160
0
            return SET_LOOKKEY_CHANGED;
161
86
        if (cmp > 0)
162
86
            return SET_LOOKKEY_FOUND;
163
86
    }
164
3.11M
    return SET_LOOKKEY_NO_MATCH;
165
6.91M
}
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
22.2M
{
175
22.2M
    assert(PyFrozenSet_Check(so));
176
22.2M
    PyObject *startkey = ep->key;
177
22.2M
    if (startkey == NULL) {
178
10.2M
        return SET_LOOKKEY_EMPTY;
179
10.2M
    }
180
11.9M
    if (startkey == key) {
181
11.1M
        return SET_LOOKKEY_FOUND;
182
11.1M
    }
183
854k
    Py_ssize_t ep_hash = ep->hash;
184
854k
    if (ep_hash == hash) {
185
6.30k
        int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
186
6.30k
        if (cmp < 0) {
187
0
            return SET_LOOKKEY_ERROR;
188
0
        }
189
6.30k
        assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH);
190
6.30k
        return cmp;
191
6.30k
    }
192
848k
    return SET_LOOKKEY_NO_MATCH;
193
854k
}
194
195
static void
196
set_zero_table(setentry *table, size_t size)
197
78.1k
{
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
78.1k
    memset(table, 0, sizeof(setentry)*size);
206
78.1k
#endif
207
78.1k
}
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
46.2M
#define LINEAR_PROBES 9
215
#endif
216
217
/* This must be >= 1 */
218
1.95M
#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
30.6M
{
224
30.6M
    setentry *entry;
225
30.6M
    size_t perturb = hash;
226
30.6M
    size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
227
30.6M
    int probes;
228
30.6M
    int status;
229
230
32.4M
    while (1) {
231
32.4M
        entry = &table[i];
232
32.4M
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
233
34.5M
        do {
234
34.5M
            status = compare_entry(so, table, entry, key, hash);
235
34.5M
            if (status != SET_LOOKKEY_NO_MATCH) {
236
30.6M
                if (status == SET_LOOKKEY_EMPTY) {
237
15.7M
                    return SET_LOOKKEY_NO_MATCH;
238
15.7M
                }
239
14.9M
                *epp = entry;
240
14.9M
                return status;
241
30.6M
            }
242
3.95M
            entry++;
243
3.95M
        } while (probes--);
244
1.81M
        perturb >>= PERTURB_SHIFT;
245
1.81M
        i = (i * 5 + 1 + perturb) & mask;
246
1.81M
    }
247
30.6M
    Py_UNREACHABLE();
248
30.6M
}
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
845k
{
255
845k
    setentry *table;
256
845k
    setentry *freeslot;
257
845k
    setentry *entry;
258
845k
    size_t perturb;
259
845k
    size_t mask;
260
845k
    size_t i;                       /* Unsigned for defined overflow behavior */
261
845k
    int probes;
262
845k
    int cmp;
263
264
845k
  restart:
265
266
845k
    mask = so->mask;
267
845k
    i = (size_t)hash & mask;
268
845k
    freeslot = NULL;
269
845k
    perturb = hash;
270
271
982k
    while (1) {
272
982k
        entry = &so->table[i];
273
982k
        probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
274
1.08M
        do {
275
1.08M
            if (entry->hash == 0 && entry->key == NULL)
276
768k
                goto found_unused_or_dummy;
277
320k
            if (entry->hash == hash) {
278
79.6k
                PyObject *startkey = entry->key;
279
79.6k
                assert(startkey != dummy);
280
79.6k
                if (startkey == key)
281
28.9k
                    goto found_active;
282
50.7k
                if (PyUnicode_CheckExact(startkey)
283
50.7k
                    && PyUnicode_CheckExact(key)
284
30.8k
                    && unicode_eq(startkey, key))
285
30.8k
                    goto found_active;
286
19.9k
                table = so->table;
287
19.9k
                Py_INCREF(startkey);
288
19.9k
                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
289
19.9k
                Py_DECREF(startkey);
290
19.9k
                if (cmp > 0)
291
17.0k
                    goto found_active;
292
2.90k
                if (cmp < 0)
293
0
                    goto comparison_error;
294
2.90k
                if (table != so->table || entry->key != startkey)
295
0
                    goto restart;
296
2.90k
                mask = so->mask;
297
2.90k
            }
298
240k
            else if (entry->hash == -1) {
299
23.7k
                assert (entry->key == dummy);
300
23.7k
                freeslot = entry;
301
23.7k
            }
302
243k
            entry++;
303
243k
        } while (probes--);
304
136k
        perturb >>= PERTURB_SHIFT;
305
136k
        i = (i * 5 + 1 + perturb) & mask;
306
136k
    }
307
308
768k
  found_unused_or_dummy:
309
768k
    if (freeslot == NULL)
310
751k
        goto found_unused;
311
17.1k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
312
17.1k
    FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash);
313
17.1k
    FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key);
314
17.1k
    return 0;
315
316
751k
  found_unused:
317
751k
    so->fill++;
318
751k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
319
751k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
320
751k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
321
751k
    if ((size_t)so->fill*5 < mask*3)
322
726k
        return 0;
323
24.7k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
324
325
76.7k
  found_active:
326
76.7k
    Py_DECREF(key);
327
76.7k
    return 0;
328
329
0
  comparison_error:
330
0
    Py_DECREF(key);
331
0
    return -1;
332
751k
}
333
334
static int
335
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
336
823k
{
337
823k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
338
339
823k
    return set_add_entry_takeref(so, Py_NewRef(key), hash);
340
823k
}
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
22.0k
{
361
22.0k
    Py_hash_t hash = _PyObject_HashFast(key);
362
22.0k
    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
22.0k
    return set_add_entry_takeref(so, key, hash);
370
22.0k
}
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
226k
{
383
226k
    setentry *entry;
384
226k
    size_t perturb = hash;
385
226k
    size_t i = (size_t)hash & mask;
386
226k
    size_t j;
387
388
235k
    while (1) {
389
235k
        entry = &table[i];
390
235k
        if (entry->key == NULL)
391
210k
            goto found_null;
392
25.1k
        if (i + LINEAR_PROBES <= mask) {
393
21.2k
            for (j = 0; j < LINEAR_PROBES; j++) {
394
21.1k
                entry++;
395
21.1k
                if (entry->key == NULL)
396
16.4k
                    goto found_null;
397
21.1k
            }
398
16.4k
        }
399
8.74k
        perturb >>= PERTURB_SHIFT;
400
8.74k
        i = (i * 5 + 1 + perturb) & mask;
401
8.74k
    }
402
226k
  found_null:
403
226k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash);
404
226k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key);
405
226k
}
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
30.6M
{
413
30.6M
    int status;
414
30.6M
    if (PyFrozenSet_CheckExact(so)) {
415
21.3M
        status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
416
21.3M
                               set_compare_frozenset);
417
21.3M
    }
418
9.24M
    else {
419
9.24M
        Py_BEGIN_CRITICAL_SECTION(so);
420
9.24M
        do {
421
9.24M
            status = set_do_lookup(so, so->table, so->mask, key, hash, epp,
422
9.24M
                                   set_compare_entry_lock_held);
423
9.24M
        } while (status == SET_LOOKKEY_CHANGED);
424
9.24M
        Py_END_CRITICAL_SECTION();
425
9.24M
    }
426
30.6M
    assert(status == SET_LOOKKEY_FOUND ||
427
30.6M
           status == SET_LOOKKEY_NO_MATCH ||
428
30.6M
           status == SET_LOOKKEY_ERROR);
429
30.6M
    return status;
430
30.6M
}
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
56.3k
{
466
#ifdef Py_GIL_DISABLED
467
    if (use_qsbr) {
468
        _PyMem_FreeDelayed(entries, size * sizeof(setentry));
469
        return;
470
    }
471
#endif
472
56.3k
    PyMem_Free(entries);
473
56.3k
}
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
77.9k
{
483
77.9k
    setentry *oldtable, *newtable, *entry;
484
77.9k
    Py_ssize_t oldmask = so->mask;
485
77.9k
    Py_ssize_t oldsize = (size_t)oldmask + 1;
486
77.9k
    size_t newmask;
487
77.9k
    int is_oldtable_malloced;
488
77.9k
    setentry small_copy[PySet_MINSIZE];
489
490
77.9k
    assert(minused >= 0);
491
492
    /* Find the smallest table size > minused. */
493
    /* XXX speed-up with intrinsics */
494
77.9k
    size_t newsize = PySet_MINSIZE;
495
184k
    while (newsize <= (size_t)minused) {
496
106k
        newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
497
106k
    }
498
499
    /* Get space for a new table. */
500
77.9k
    oldtable = so->table;
501
77.9k
    assert(oldtable != NULL);
502
77.9k
    is_oldtable_malloced = oldtable != so->smalltable;
503
504
77.9k
    if (newsize == PySet_MINSIZE) {
505
        /* A large table is shrinking, or we can't get any smaller. */
506
21.2k
        newtable = so->smalltable;
507
21.2k
        if (newtable == oldtable) {
508
21.2k
            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
21.2k
            assert(so->fill > so->used);
519
21.2k
            memcpy(small_copy, oldtable, sizeof(small_copy));
520
21.2k
            oldtable = small_copy;
521
21.2k
        }
522
21.2k
    }
523
56.7k
    else {
524
56.7k
        newtable = PyMem_NEW(setentry, newsize);
525
56.7k
        if (newtable == NULL) {
526
0
            PyErr_NoMemory();
527
0
            return -1;
528
0
        }
529
56.7k
    }
530
531
    /* Make the set empty, using the new table. */
532
77.9k
    assert(newtable != oldtable);
533
77.9k
    set_zero_table(newtable, newsize);
534
77.9k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
535
77.9k
    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
77.9k
    newmask = (size_t)so->mask;
540
77.9k
    if (so->fill == so->used) {
541
535k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
542
485k
            if (entry->key != NULL) {
543
157k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
544
157k
            }
545
485k
        }
546
50.6k
    } else {
547
27.3k
        so->fill = so->used;
548
245k
        for (entry = oldtable; entry <= oldtable + oldmask; entry++) {
549
218k
            if (entry->key != NULL && entry->key != dummy) {
550
16.5k
                set_insert_clean(newtable, newmask, entry->key, entry->hash);
551
16.5k
            }
552
218k
        }
553
27.3k
    }
554
555
77.9k
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, newtable);
556
557
77.9k
    if (is_oldtable_malloced)
558
3.19k
        free_entries(oldtable, oldsize, SET_IS_SHARED(so));
559
77.9k
    return 0;
560
77.9k
}
561
562
static int
563
set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
564
30.2M
{
565
#ifdef Py_GIL_DISABLED
566
    return set_lookkey_threadsafe(so, key, hash);
567
#else
568
30.2M
    setentry *entry; // unused
569
30.2M
    return set_lookkey(so, key, hash, &entry);
570
30.2M
#endif
571
30.2M
}
572
573
304k
#define DISCARD_NOTFOUND 0
574
115k
#define DISCARD_FOUND 1
575
576
static int
577
set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
578
366k
{
579
366k
    setentry *entry;
580
366k
    PyObject *old_key;
581
366k
    int status = set_lookkey(so, key, hash, &entry);
582
366k
    if (status < 0) {
583
0
        return -1;
584
0
    }
585
366k
    if (status == SET_LOOKKEY_NO_MATCH) {
586
251k
        return DISCARD_NOTFOUND;
587
251k
    }
588
366k
    assert(status == SET_LOOKKEY_FOUND);
589
115k
    old_key = entry->key;
590
115k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
591
115k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
592
115k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
593
115k
    Py_DECREF(old_key);
594
115k
    return DISCARD_FOUND;
595
115k
}
596
597
static int
598
set_add_key(PySetObject *so, PyObject *key)
599
606k
{
600
606k
    Py_hash_t hash = _PyObject_HashFast(key);
601
606k
    if (hash == -1) {
602
0
        set_unhashable_type(key);
603
0
        return -1;
604
0
    }
605
606k
    return set_add_entry(so, key, hash);
606
606k
}
607
608
static int
609
set_contains_key(PySetObject *so, PyObject *key)
610
611k
{
611
611k
    Py_hash_t hash = _PyObject_HashFast(key);
612
611k
    if (hash == -1) {
613
0
        set_unhashable_type(key);
614
0
        return -1;
615
0
    }
616
611k
    return set_contains_entry(so, key, hash);
617
611k
}
618
619
static int
620
set_discard_key(PySetObject *so, PyObject *key)
621
314k
{
622
314k
    Py_hash_t hash = _PyObject_HashFast(key);
623
314k
    if (hash == -1) {
624
0
        set_unhashable_type(key);
625
0
        return -1;
626
0
    }
627
314k
    return set_discard_entry(so, key, hash);
628
314k
}
629
630
static void
631
set_empty_to_minsize(PySetObject *so)
632
207
{
633
207
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL);
634
207
    set_zero_table(so->smalltable, PySet_MINSIZE);
635
207
    so->fill = 0;
636
207
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0);
637
207
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, PySet_MINSIZE - 1);
638
207
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1);
639
207
    FT_ATOMIC_STORE_PTR_RELEASE(so->table, so->smalltable);
640
207
}
641
642
static int
643
set_clear_internal(PyObject *self)
644
207
{
645
207
    PySetObject *so = _PySet_CAST(self);
646
0
    setentry *entry;
647
207
    setentry *table = so->table;
648
207
    Py_ssize_t fill = so->fill;
649
207
    Py_ssize_t used = so->used;
650
207
    Py_ssize_t oldsize = (size_t)so->mask + 1;
651
207
    int table_is_malloced = table != so->smalltable;
652
207
    setentry small_copy[PySet_MINSIZE];
653
654
207
    assert (PyAnySet_Check(so));
655
207
    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
207
    if (table_is_malloced)
664
0
        set_empty_to_minsize(so);
665
666
207
    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
207
        memcpy(small_copy, table, sizeof(small_copy));
672
207
        table = small_copy;
673
207
        set_empty_to_minsize(so);
674
207
    }
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.04k
    for (entry = table; used > 0; entry++) {
682
833
        if (entry->key && entry->key != dummy) {
683
207
            used--;
684
207
            Py_DECREF(entry->key);
685
207
        }
686
833
    }
687
688
207
    if (table_is_malloced)
689
0
        free_entries(table, oldsize, SET_IS_SHARED(so));
690
207
    return 0;
691
207
}
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
6.88M
{
709
6.88M
    Py_ssize_t i;
710
6.88M
    Py_ssize_t mask;
711
6.88M
    setentry *entry;
712
713
6.88M
    assert (PyAnySet_Check(so));
714
6.88M
    i = *pos_ptr;
715
6.88M
    assert(i >= 0);
716
6.88M
    mask = so->mask;
717
6.88M
    entry = &so->table[i];
718
21.7M
    while (i <= mask && (entry->key == NULL || entry->key == dummy)) {
719
14.9M
        i++;
720
14.9M
        entry++;
721
14.9M
    }
722
6.88M
    *pos_ptr = i+1;
723
6.88M
    if (i > mask)
724
675k
        return 0;
725
6.88M
    assert(entry != NULL);
726
6.20M
    *entry_ptr = entry;
727
6.20M
    return 1;
728
6.20M
}
729
730
static void
731
set_dealloc(PyObject *self)
732
708k
{
733
708k
    PySetObject *so = _PySet_CAST(self);
734
0
    setentry *entry;
735
708k
    Py_ssize_t used = so->used;
736
708k
    Py_ssize_t oldsize = (size_t)so->mask + 1;
737
738
    /* bpo-31095: UnTrack is needed before calling any callbacks */
739
708k
    PyObject_GC_UnTrack(so);
740
708k
    FT_CLEAR_WEAKREFS(self, so->weakreflist);
741
742
3.65M
    for (entry = so->table; used > 0; entry++) {
743
2.94M
        if (entry->key && entry->key != dummy) {
744
997k
                used--;
745
997k
                Py_DECREF(entry->key);
746
997k
        }
747
2.94M
    }
748
708k
    if (so->table != so->smalltable)
749
53.1k
        free_entries(so->table, oldsize, SET_IS_SHARED(so));
750
708k
    Py_TYPE(so)->tp_free(so);
751
708k
}
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
401k
{
821
401k
    PySetObject *so = _PySet_CAST(self);
822
401k
    return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
823
401k
}
824
825
static int
826
set_merge_lock_held(PySetObject *so, PyObject *otherset)
827
487k
{
828
487k
    PySetObject *other;
829
487k
    PyObject *key;
830
487k
    Py_ssize_t i;
831
487k
    setentry *so_entry;
832
487k
    setentry *other_entry;
833
834
487k
    assert (PyAnySet_Check(so));
835
487k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
836
487k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(otherset);
837
838
487k
    other = _PySet_CAST(otherset);
839
487k
    if (other == so || other->used == 0)
840
        /* a.update(a) or a.update(set()); nothing to do */
841
327k
        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
159k
    if ((so->fill + other->used)*5 >= so->mask*3) {
847
31.9k
        if (set_table_resize(so, (so->used + other->used)*2) != 0)
848
0
            return -1;
849
31.9k
    }
850
159k
    so_entry = so->table;
851
159k
    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
159k
    if (so->fill == 0 && so->mask == other->mask && other->fill == other->used) {
856
1.60M
        for (i = 0; i <= other->mask; i++, so_entry++, other_entry++) {
857
1.47M
            key = other_entry->key;
858
1.47M
            if (key != NULL) {
859
416k
                assert(so_entry->key == NULL);
860
416k
                FT_ATOMIC_STORE_SSIZE_RELAXED(so_entry->hash, other_entry->hash);
861
416k
                FT_ATOMIC_STORE_PTR_RELEASE(so_entry->key, Py_NewRef(key));
862
416k
            }
863
1.47M
        }
864
127k
        so->fill = other->fill;
865
127k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
866
127k
        return 0;
867
127k
    }
868
869
    /* If our table is empty, we can use set_insert_clean() */
870
31.6k
    if (so->fill == 0) {
871
6.27k
        setentry *newtable = so->table;
872
6.27k
        size_t newmask = (size_t)so->mask;
873
6.27k
        so->fill = other->used;
874
6.27k
        FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, other->used);
875
221k
        for (i = other->mask + 1; i > 0 ; i--, other_entry++) {
876
215k
            key = other_entry->key;
877
215k
            if (key != NULL && key != dummy) {
878
52.2k
                set_insert_clean(newtable, newmask, Py_NewRef(key),
879
52.2k
                                 other_entry->hash);
880
52.2k
            }
881
215k
        }
882
6.27k
        return 0;
883
6.27k
    }
884
885
    /* We can't assure there are no duplicates, so do normal insertions */
886
546k
    for (i = 0; i <= other->mask; i++) {
887
521k
        other_entry = &other->table[i];
888
521k
        key = other_entry->key;
889
521k
        if (key != NULL && key != dummy) {
890
164k
            if (set_add_entry(so, key, other_entry->hash))
891
0
                return -1;
892
164k
        }
893
521k
    }
894
25.4k
    return 0;
895
25.4k
}
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
103k
{
911
    /* Make sure the search finger is in bounds */
912
103k
    setentry *entry = so->table + (so->finger & so->mask);
913
103k
    setentry *limit = so->table + so->mask;
914
103k
    PyObject *key;
915
916
103k
    if (so->used == 0) {
917
0
        PyErr_SetString(PyExc_KeyError, "pop from an empty set");
918
0
        return NULL;
919
0
    }
920
389k
    while (entry->key == NULL || entry->key==dummy) {
921
285k
        entry++;
922
285k
        if (entry > limit)
923
16.2k
            entry = so->table;
924
285k
    }
925
103k
    FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1);
926
103k
    FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1);
927
103k
    key = entry->key;
928
103k
    FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy);
929
103k
    so->finger = entry - so->table + 1;   /* next place to start */
930
103k
    return key;
931
103k
}
932
933
static int
934
set_traverse(PyObject *self, visitproc visit, void *arg)
935
601k
{
936
601k
    PySetObject *so = _PySet_CAST(self);
937
0
    Py_ssize_t pos = 0;
938
601k
    setentry *entry;
939
940
6.53M
    while (set_next(so, &pos, &entry))
941
5.93M
        Py_VISIT(entry->key);
942
601k
    return 0;
943
601k
}
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
309k
{
953
309k
    return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL;
954
309k
}
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
11.7k
{
969
11.7k
    PySetObject *so = _PySet_CAST(self);
970
0
    Py_uhash_t hash = 0;
971
11.7k
    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
315k
    for (entry = so->table; entry <= &so->table[so->mask]; entry++)
984
303k
        hash ^= _shuffle_bits(entry->hash);
985
986
    /* Remove the effect of an odd number of NULL entries */
987
11.7k
    if ((so->mask + 1 - so->fill) & 1)
988
6.42k
        hash ^= _shuffle_bits(0);
989
990
    /* Remove the effect of an odd number of dummy entries */
991
11.7k
    if ((so->fill - so->used) & 1)
992
0
        hash ^= _shuffle_bits(-1);
993
994
    /* Factor in the number of active entries */
995
11.7k
    hash ^= ((Py_uhash_t)PySet_GET_SIZE(self) + 1) * 1927868237UL;
996
997
    /* Disperse patterns arising in nested frozensets */
998
11.7k
    hash ^= (hash >> 11) ^ (hash >> 25);
999
11.7k
    hash = hash * 69069U + 907133923UL;
1000
1001
    /* -1 is reserved as an error code */
1002
11.7k
    if (hash == (Py_uhash_t)-1)
1003
0
        hash = 590923713UL;
1004
1005
11.7k
    return (Py_hash_t)hash;
1006
11.7k
}
1007
1008
static Py_hash_t
1009
frozenset_hash(PyObject *self)
1010
15.4k
{
1011
15.4k
    PySetObject *so = _PySet_CAST(self);
1012
0
    Py_uhash_t hash;
1013
1014
15.4k
    if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) {
1015
3.77k
        return FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->hash);
1016
3.77k
    }
1017
1018
11.7k
    hash = frozenset_hash_impl(self);
1019
11.7k
    FT_ATOMIC_STORE_SSIZE_RELEASE(so->hash, hash);
1020
11.7k
    return hash;
1021
15.4k
}
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
134k
{
1036
134k
    setiterobject *si = (setiterobject*)self;
1037
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1038
134k
    _PyObject_GC_UNTRACK(si);
1039
134k
    Py_XDECREF(si->si_set);
1040
134k
    PyObject_GC_Del(si);
1041
134k
}
1042
1043
static int
1044
setiter_traverse(PyObject *self, visitproc visit, void *arg)
1045
0
{
1046
0
    setiterobject *si = (setiterobject*)self;
1047
0
    Py_VISIT(si->si_set);
1048
0
    return 0;
1049
0
}
1050
1051
static PyObject *
1052
setiter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
1053
0
{
1054
0
    setiterobject *si = (setiterobject*)op;
1055
0
    Py_ssize_t len = 0;
1056
0
    if (si->si_set != NULL && si->si_used == si->si_set->used)
1057
0
        len = si->len;
1058
0
    return PyLong_FromSsize_t(len);
1059
0
}
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
305k
{
1091
305k
    setiterobject *si = (setiterobject*)self;
1092
305k
    PyObject *key = NULL;
1093
305k
    Py_ssize_t i, mask;
1094
305k
    setentry *entry;
1095
305k
    PySetObject *so = si->si_set;
1096
1097
305k
    if (so == NULL)
1098
0
        return NULL;
1099
305k
    assert (PyAnySet_Check(so));
1100
1101
305k
    Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
1102
305k
    Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used);
1103
305k
    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
305k
    Py_BEGIN_CRITICAL_SECTION(so);
1111
305k
    i = si->si_pos;
1112
305k
    assert(i>=0);
1113
305k
    entry = so->table;
1114
305k
    mask = so->mask;
1115
1.25M
    while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
1116
950k
        i++;
1117
950k
    }
1118
305k
    if (i <= mask) {
1119
170k
        key = Py_NewRef(entry[i].key);
1120
170k
    }
1121
305k
    Py_END_CRITICAL_SECTION();
1122
305k
    si->si_pos = i+1;
1123
305k
    if (key == NULL) {
1124
134k
        si->si_set = NULL;
1125
134k
        Py_DECREF(so);
1126
134k
        return NULL;
1127
134k
    }
1128
170k
    si->len--;
1129
170k
    return key;
1130
305k
}
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
134k
{
1168
134k
    Py_ssize_t size = set_len(so);
1169
134k
    setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
1170
134k
    if (si == NULL)
1171
0
        return NULL;
1172
134k
    si->si_set = (PySetObject*)Py_NewRef(so);
1173
134k
    si->si_used = size;
1174
134k
    si->si_pos = 0;
1175
134k
    si->len = size;
1176
134k
    _PyObject_GC_TRACK(si);
1177
134k
    return (PyObject *)si;
1178
134k
}
1179
1180
static int
1181
set_update_dict_lock_held(PySetObject *so, PyObject *other)
1182
21.2k
{
1183
21.2k
    assert(PyDict_CheckExact(other));
1184
1185
21.2k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1186
21.2k
    _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
21.2k
    Py_ssize_t dictsize = PyDict_GET_SIZE(other);
1193
21.2k
    if ((so->fill + dictsize)*5 >= so->mask*3) {
1194
0
        if (set_table_resize(so, (so->used + dictsize)*2) != 0) {
1195
0
            return -1;
1196
0
        }
1197
0
    }
1198
1199
21.2k
    Py_ssize_t pos = 0;
1200
21.2k
    PyObject *key;
1201
21.2k
    PyObject *value;
1202
21.2k
    Py_hash_t hash;
1203
73.9k
    while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
1204
52.6k
        if (set_add_entry(so, key, hash)) {
1205
0
            return -1;
1206
0
        }
1207
52.6k
    }
1208
21.2k
    return 0;
1209
21.2k
}
1210
1211
static int
1212
set_update_iterable_lock_held(PySetObject *so, PyObject *other)
1213
11.8k
{
1214
11.8k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1215
1216
11.8k
    PyObject *it = PyObject_GetIter(other);
1217
11.8k
    if (it == NULL) {
1218
0
        return -1;
1219
0
    }
1220
1221
11.8k
    PyObject *key;
1222
120k
    while ((key = PyIter_Next(it)) != NULL) {
1223
108k
        if (set_add_key(so, key)) {
1224
0
            Py_DECREF(it);
1225
0
            Py_DECREF(key);
1226
0
            return -1;
1227
0
        }
1228
108k
        Py_DECREF(key);
1229
108k
    }
1230
11.8k
    Py_DECREF(it);
1231
11.8k
    if (PyErr_Occurred())
1232
0
        return -1;
1233
11.8k
    return 0;
1234
11.8k
}
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
235k
{
1252
235k
    assert(Py_REFCNT(so) == 1);
1253
235k
    if (PyAnySet_Check(other)) {
1254
202k
        int rv;
1255
202k
        Py_BEGIN_CRITICAL_SECTION(other);
1256
202k
        rv = set_merge_lock_held(so, other);
1257
202k
        Py_END_CRITICAL_SECTION();
1258
202k
        return rv;
1259
202k
    }
1260
33.1k
    else if (PyDict_CheckExact(other)) {
1261
21.2k
        int rv;
1262
21.2k
        Py_BEGIN_CRITICAL_SECTION(other);
1263
21.2k
        rv = set_update_dict_lock_held(so, other);
1264
21.2k
        Py_END_CRITICAL_SECTION();
1265
21.2k
        return rv;
1266
21.2k
    }
1267
11.8k
    return set_update_iterable_lock_held(so, other);
1268
235k
}
1269
1270
static int
1271
set_update_internal(PySetObject *so, PyObject *other)
1272
242k
{
1273
242k
    if (PyAnySet_Check(other)) {
1274
242k
        if (Py_Is((PyObject *)so, other)) {
1275
0
            return 0;
1276
0
        }
1277
242k
        int rv;
1278
242k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1279
242k
        rv = set_merge_lock_held(so, other);
1280
242k
        Py_END_CRITICAL_SECTION2();
1281
242k
        return rv;
1282
242k
    }
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
242k
}
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
710k
{
1331
710k
    assert(PyType_Check(type));
1332
710k
    PySetObject *so;
1333
1334
710k
    so = (PySetObject *)type->tp_alloc(type, 0);
1335
710k
    if (so == NULL)
1336
0
        return NULL;
1337
1338
710k
    so->fill = 0;
1339
710k
    so->used = 0;
1340
710k
    so->mask = PySet_MINSIZE - 1;
1341
710k
    so->table = so->smalltable;
1342
710k
    so->hash = -1;
1343
710k
    so->finger = 0;
1344
710k
    so->weakreflist = NULL;
1345
1346
710k
    if (iterable != NULL) {
1347
214k
        if (set_update_local(so, iterable)) {
1348
0
            Py_DECREF(so);
1349
0
            return NULL;
1350
0
        }
1351
214k
    }
1352
1353
710k
    return (PyObject *)so;
1354
710k
}
1355
1356
static PyObject *
1357
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1358
42.5k
{
1359
42.5k
    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
42.5k
    return make_new_set(type, iterable);
1366
42.5k
}
1367
1368
static PyObject *
1369
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
1370
92
{
1371
92
    if (type != &PyFrozenSet_Type) {
1372
0
        return make_new_set(type, iterable);
1373
0
    }
1374
1375
92
    if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
1376
        /* frozenset(f) is idempotent */
1377
0
        return Py_NewRef(iterable);
1378
0
    }
1379
92
    return make_new_set(type, iterable);
1380
92
}
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
92
{
1404
92
    if (!_PyArg_NoKwnames("frozenset", kwnames)) {
1405
0
        return NULL;
1406
0
    }
1407
1408
92
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1409
92
    if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
1410
0
        return NULL;
1411
0
    }
1412
1413
92
    PyObject *iterable = (nargs ? args[0] : NULL);
1414
92
    return make_new_frozenset(_PyType_CAST(type), iterable);
1415
92
}
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
42.4k
{
1516
42.4k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1517
42.4k
    PyObject *copy = make_new_set_basetype(Py_TYPE(so), NULL);
1518
42.4k
    if (copy == NULL) {
1519
0
        return NULL;
1520
0
    }
1521
42.4k
    if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
1522
0
        Py_DECREF(copy);
1523
0
        return NULL;
1524
0
    }
1525
42.4k
    return copy;
1526
42.4k
}
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
207
{
1558
207
    set_clear_internal((PyObject*)so);
1559
207
    Py_RETURN_NONE;
1560
207
}
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
0
{
1575
0
    PySetObject *result;
1576
0
    PyObject *other;
1577
0
    Py_ssize_t i;
1578
1579
0
    result = (PySetObject *)set_copy((PyObject *)so, NULL);
1580
0
    if (result == NULL)
1581
0
        return NULL;
1582
1583
0
    for (i = 0; i < others_length; i++) {
1584
0
        other = others[i];
1585
0
        if ((PyObject *)so == other)
1586
0
            continue;
1587
0
        if (set_update_local(result, other)) {
1588
0
            Py_DECREF(result);
1589
0
            return NULL;
1590
0
        }
1591
0
    }
1592
0
    return (PyObject *)result;
1593
0
}
1594
1595
static PyObject *
1596
set_or(PyObject *self, PyObject *other)
1597
21.2k
{
1598
21.2k
    PySetObject *result;
1599
1600
21.2k
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1601
0
        Py_RETURN_NOTIMPLEMENTED;
1602
1603
21.2k
    result = (PySetObject *)set_copy(self, NULL);
1604
21.2k
    if (result == NULL) {
1605
0
        return NULL;
1606
0
    }
1607
21.2k
    if (Py_Is(self, other)) {
1608
0
        return (PyObject *)result;
1609
0
    }
1610
21.2k
    if (set_update_local(result, other)) {
1611
0
        Py_DECREF(result);
1612
0
        return NULL;
1613
0
    }
1614
21.2k
    return (PyObject *)result;
1615
21.2k
}
1616
1617
static PyObject *
1618
set_ior(PyObject *self, PyObject *other)
1619
242k
{
1620
242k
    if (!PyAnySet_Check(other))
1621
0
        Py_RETURN_NOTIMPLEMENTED;
1622
242k
    PySetObject *so = _PySet_CAST(self);
1623
1624
242k
    if (set_update_internal(so, other)) {
1625
0
        return NULL;
1626
0
    }
1627
242k
    return Py_NewRef(so);
1628
242k
}
1629
1630
static PyObject *
1631
set_intersection(PySetObject *so, PyObject *other)
1632
49
{
1633
49
    PySetObject *result;
1634
49
    PyObject *key, *it, *tmp;
1635
49
    Py_hash_t hash;
1636
49
    int rv;
1637
1638
49
    if ((PyObject *)so == other)
1639
0
        return set_copy_impl(so);
1640
1641
49
    result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
1642
49
    if (result == NULL)
1643
0
        return NULL;
1644
1645
49
    if (PyAnySet_Check(other)) {
1646
49
        Py_ssize_t pos = 0;
1647
49
        setentry *entry;
1648
1649
49
        if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
1650
42
            tmp = (PyObject *)so;
1651
42
            so = (PySetObject *)other;
1652
42
            other = tmp;
1653
42
        }
1654
1655
63
        while (set_next((PySetObject *)other, &pos, &entry)) {
1656
14
            key = entry->key;
1657
14
            hash = entry->hash;
1658
14
            Py_INCREF(key);
1659
14
            rv = set_contains_entry(so, key, hash);
1660
14
            if (rv < 0) {
1661
0
                Py_DECREF(result);
1662
0
                Py_DECREF(key);
1663
0
                return NULL;
1664
0
            }
1665
14
            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
14
            Py_DECREF(key);
1673
14
        }
1674
49
        return (PyObject *)result;
1675
49
    }
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
49
{
1789
49
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
1790
0
        Py_RETURN_NOTIMPLEMENTED;
1791
49
    PySetObject *so = _PySet_CAST(self);
1792
1793
0
    PyObject *rv;
1794
49
    Py_BEGIN_CRITICAL_SECTION2(so, other);
1795
49
    rv = set_intersection(so, other);
1796
49
    Py_END_CRITICAL_SECTION2();
1797
1798
49
    return rv;
1799
49
}
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
0
{
1834
0
    PyObject *key, *it, *tmp;
1835
0
    int rv;
1836
1837
0
    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
0
    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
0
    it = PyObject_GetIter(other);
1869
0
    if (it == NULL)
1870
0
        return NULL;
1871
1872
0
    while ((key = PyIter_Next(it)) != NULL) {
1873
0
        rv = set_contains_key(so, key);
1874
0
        Py_DECREF(key);
1875
0
        if (rv < 0) {
1876
0
            Py_DECREF(it);
1877
0
            return NULL;
1878
0
        }
1879
0
        if (rv) {
1880
0
            Py_DECREF(it);
1881
0
            Py_RETURN_FALSE;
1882
0
        }
1883
0
    }
1884
0
    Py_DECREF(it);
1885
0
    if (PyErr_Occurred())
1886
0
        return NULL;
1887
0
    Py_RETURN_TRUE;
1888
0
}
1889
1890
static int
1891
set_difference_update_internal(PySetObject *so, PyObject *other)
1892
21.2k
{
1893
21.2k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
1894
21.2k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
1895
1896
21.2k
    if ((PyObject *)so == other)
1897
0
        return set_clear_internal((PyObject*)so);
1898
1899
21.2k
    if (PyAnySet_Check(other)) {
1900
21.2k
        setentry *entry;
1901
21.2k
        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
21.2k
        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
21.2k
        } else {
1912
21.2k
            Py_INCREF(other);
1913
21.2k
        }
1914
1915
73.8k
        while (set_next((PySetObject *)other, &pos, &entry)) {
1916
52.6k
            PyObject *key = entry->key;
1917
52.6k
            Py_INCREF(key);
1918
52.6k
            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
52.6k
            Py_DECREF(key);
1924
52.6k
        }
1925
1926
21.2k
        Py_DECREF(other);
1927
21.2k
    } 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
21.2k
    if ((size_t)(so->fill - so->used) <= (size_t)so->mask / 4)
1947
0
        return 0;
1948
21.2k
    return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4);
1949
21.2k
}
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
21.2k
{
1964
21.2k
    Py_ssize_t i;
1965
1966
42.4k
    for (i = 0; i < others_length; i++) {
1967
21.2k
        PyObject *other = others[i];
1968
21.2k
        int rv;
1969
21.2k
        Py_BEGIN_CRITICAL_SECTION2(so, other);
1970
21.2k
        rv = set_difference_update_internal(so, other);
1971
21.2k
        Py_END_CRITICAL_SECTION2();
1972
21.2k
        if (rv) {
1973
0
            return NULL;
1974
0
        }
1975
21.2k
    }
1976
21.2k
    Py_RETURN_NONE;
1977
21.2k
}
1978
1979
static PyObject *
1980
set_copy_and_difference(PySetObject *so, PyObject *other)
1981
0
{
1982
0
    PyObject *result;
1983
1984
0
    result = set_copy_impl(so);
1985
0
    if (result == NULL)
1986
0
        return NULL;
1987
0
    if (set_difference_update_internal((PySetObject *) result, other) == 0)
1988
0
        return result;
1989
0
    Py_DECREF(result);
1990
0
    return NULL;
1991
0
}
1992
1993
static PyObject *
1994
set_difference(PySetObject *so, PyObject *other)
1995
0
{
1996
0
    PyObject *result;
1997
0
    PyObject *key;
1998
0
    Py_hash_t hash;
1999
0
    setentry *entry;
2000
0
    Py_ssize_t pos = 0, other_size;
2001
0
    int rv;
2002
2003
0
    if (PyAnySet_Check(other)) {
2004
0
        other_size = PySet_GET_SIZE(other);
2005
0
    }
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
0
    if ((PySet_GET_SIZE(so) >> 2) > other_size) {
2016
0
        return set_copy_and_difference(so, other);
2017
0
    }
2018
2019
0
    result = make_new_set_basetype(Py_TYPE(so), NULL);
2020
0
    if (result == NULL)
2021
0
        return NULL;
2022
2023
0
    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
0
    while (set_next(so, &pos, &entry)) {
2048
0
        key = entry->key;
2049
0
        hash = entry->hash;
2050
0
        Py_INCREF(key);
2051
0
        rv = set_contains_entry((PySetObject *)other, key, hash);
2052
0
        if (rv < 0) {
2053
0
            Py_DECREF(result);
2054
0
            Py_DECREF(key);
2055
0
            return NULL;
2056
0
        }
2057
0
        if (!rv) {
2058
0
            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
0
        }
2064
0
        Py_DECREF(key);
2065
0
    }
2066
0
    return result;
2067
0
}
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
0
{
2113
0
    if (!PyAnySet_Check(self) || !PyAnySet_Check(other))
2114
0
        Py_RETURN_NOTIMPLEMENTED;
2115
0
    PySetObject *so = _PySet_CAST(self);
2116
2117
0
    PyObject *rv;
2118
0
    Py_BEGIN_CRITICAL_SECTION2(so, other);
2119
0
    rv = set_difference(so, other);
2120
0
    Py_END_CRITICAL_SECTION2();
2121
0
    return rv;
2122
0
}
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
6.20k
{
2310
6.20k
    setentry *entry;
2311
6.20k
    Py_ssize_t pos = 0;
2312
6.20k
    int rv;
2313
2314
6.20k
    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
6.20k
    if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
2324
0
        Py_RETURN_FALSE;
2325
2326
47.7k
    while (set_next(so, &pos, &entry)) {
2327
41.6k
        PyObject *key = entry->key;
2328
41.6k
        Py_INCREF(key);
2329
41.6k
        rv = set_contains_entry((PySetObject *)other, key, entry->hash);
2330
41.6k
        Py_DECREF(key);
2331
41.6k
        if (rv < 0) {
2332
0
            return NULL;
2333
0
        }
2334
41.6k
        if (!rv) {
2335
112
            Py_RETURN_FALSE;
2336
112
        }
2337
41.6k
    }
2338
6.20k
    Py_RETURN_TRUE;
2339
6.20k
}
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
0
{
2355
0
    if (PyAnySet_Check(other)) {
2356
0
        return set_issubset(other, (PyObject *)so);
2357
0
    }
2358
2359
0
    PyObject *key, *it = PyObject_GetIter(other);
2360
0
    if (it == NULL) {
2361
0
        return NULL;
2362
0
    }
2363
0
    while ((key = PyIter_Next(it)) != NULL) {
2364
0
        int rv = set_contains_key(so, key);
2365
0
        Py_DECREF(key);
2366
0
        if (rv < 0) {
2367
0
            Py_DECREF(it);
2368
0
            return NULL;
2369
0
        }
2370
0
        if (!rv) {
2371
0
            Py_DECREF(it);
2372
0
            Py_RETURN_FALSE;
2373
0
        }
2374
0
    }
2375
0
    Py_DECREF(it);
2376
0
    if (PyErr_Occurred()) {
2377
0
        return NULL;
2378
0
    }
2379
0
    Py_RETURN_TRUE;
2380
0
}
2381
2382
static PyObject *
2383
set_richcompare(PyObject *self, PyObject *w, int op)
2384
27.4k
{
2385
27.4k
    PySetObject *v = _PySet_CAST(self);
2386
0
    PyObject *r1;
2387
27.4k
    int r2;
2388
2389
27.4k
    if(!PyAnySet_Check(w))
2390
21.2k
        Py_RETURN_NOTIMPLEMENTED;
2391
2392
6.20k
    switch (op) {
2393
6.15k
    case Py_EQ:
2394
6.15k
        if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
2395
0
            Py_RETURN_FALSE;
2396
6.15k
        Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->hash);
2397
6.15k
        Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(((PySetObject *)w)->hash);
2398
6.15k
        if (v_hash != -1 && w_hash != -1 && v_hash != w_hash)
2399
0
            Py_RETURN_FALSE;
2400
6.15k
        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
44
    case Py_LE:
2411
44
        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
6.20k
    }
2423
6.20k
    Py_RETURN_NOTIMPLEMENTED;
2424
6.20k
}
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
308k
{
2442
308k
    if (set_add_key(so, key))
2443
0
        return NULL;
2444
308k
    Py_RETURN_NONE;
2445
308k
}
2446
2447
int
2448
_PySet_Contains(PySetObject *so, PyObject *key)
2449
29.6M
{
2450
29.6M
    assert(so);
2451
2452
29.6M
    Py_hash_t hash = _PyObject_HashFast(key);
2453
29.6M
    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
29.6M
    return set_contains_entry(so, key, hash);
2467
29.6M
}
2468
2469
static int
2470
set_contains(PyObject *self, PyObject *key)
2471
263
{
2472
263
    PySetObject *so = _PySet_CAST(self);
2473
0
    return _PySet_Contains(so, key);
2474
263
}
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
0
{
2490
0
    long result;
2491
2492
0
    result = _PySet_Contains(so, key);
2493
0
    if (result < 0)
2494
0
        return NULL;
2495
0
    return PyBool_FromLong(result);
2496
0
}
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
69
{
2512
69
    Py_hash_t hash = _PyObject_HashFast(key);
2513
69
    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
69
    setentry *entry; // unused
2524
69
    int status = set_do_lookup(so, so->table, so->mask, key, hash, &entry,
2525
69
                           set_compare_frozenset);
2526
69
    if (status < 0)
2527
0
        return NULL;
2528
69
    return PyBool_FromLong(status);
2529
69
}
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
52.6k
{
2547
52.6k
    int rv;
2548
2549
52.6k
    rv = set_discard_key(so, key);
2550
52.6k
    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
52.6k
    if (rv == DISCARD_NOTFOUND) {
2564
0
        _PyErr_SetKeyError(key);
2565
0
        return NULL;
2566
0
    }
2567
52.6k
    Py_RETURN_NONE;
2568
52.6k
}
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
82.4k
{
2688
82.4k
    assert(PyType_Check(type));
2689
2690
82.4k
    if (!_PyArg_NoKwnames("set", kwnames)) {
2691
0
        return NULL;
2692
0
    }
2693
2694
82.4k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
2695
82.4k
    if (!_PyArg_CheckPositional("set", nargs, 0, 1)) {
2696
0
        return NULL;
2697
0
    }
2698
2699
82.4k
    if (nargs) {
2700
153
        return make_new_set(_PyType_CAST(type), args[0]);
2701
153
    }
2702
2703
82.3k
    return make_new_set(_PyType_CAST(type), NULL);
2704
82.3k
}
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
572k
{
2926
572k
    return make_new_set(&PySet_Type, iterable);
2927
572k
}
2928
2929
PyObject *
2930
PyFrozenSet_New(PyObject *iterable)
2931
12.8k
{
2932
12.8k
    return make_new_set(&PyFrozenSet_Type, iterable);
2933
12.8k
}
2934
2935
Py_ssize_t
2936
PySet_Size(PyObject *anyset)
2937
7.67k
{
2938
7.67k
    if (!PyAnySet_Check(anyset)) {
2939
0
        PyErr_BadInternalCall();
2940
0
        return -1;
2941
0
    }
2942
7.67k
    return set_len(anyset);
2943
7.67k
}
2944
2945
int
2946
PySet_Clear(PyObject *set)
2947
207
{
2948
207
    if (!PySet_Check(set)) {
2949
0
        PyErr_BadInternalCall();
2950
0
        return -1;
2951
0
    }
2952
207
    (void)set_clear(set, NULL);
2953
207
    return 0;
2954
207
}
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
611k
{
2965
611k
    if (!PyAnySet_Check(anyset)) {
2966
0
        PyErr_BadInternalCall();
2967
0
        return -1;
2968
0
    }
2969
611k
    if (PyFrozenSet_CheckExact(anyset)) {
2970
0
        return set_contains_key((PySetObject *)anyset, key);
2971
0
    }
2972
611k
    int rv;
2973
611k
    Py_BEGIN_CRITICAL_SECTION(anyset);
2974
611k
    rv = set_contains_key((PySetObject *)anyset, key);
2975
611k
    Py_END_CRITICAL_SECTION();
2976
611k
    return rv;
2977
611k
}
2978
2979
int
2980
PySet_Discard(PyObject *set, PyObject *key)
2981
261k
{
2982
261k
    if (!PySet_Check(set)) {
2983
0
        PyErr_BadInternalCall();
2984
0
        return -1;
2985
0
    }
2986
2987
261k
    int rv;
2988
261k
    Py_BEGIN_CRITICAL_SECTION(set);
2989
261k
    rv = set_discard_key((PySetObject *)set, key);
2990
261k
    Py_END_CRITICAL_SECTION();
2991
261k
    return rv;
2992
261k
}
2993
2994
int
2995
PySet_Add(PyObject *anyset, PyObject *key)
2996
189k
{
2997
189k
    if (PySet_Check(anyset)) {
2998
187k
        int rv;
2999
187k
        Py_BEGIN_CRITICAL_SECTION(anyset);
3000
187k
        rv = set_add_key((PySetObject *)anyset, key);
3001
187k
        Py_END_CRITICAL_SECTION();
3002
187k
        return rv;
3003
187k
    }
3004
3005
1.83k
    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
1.83k
        return set_add_key((PySetObject *)anyset, key);
3011
1.83k
    }
3012
3013
0
    PyErr_BadInternalCall();
3014
0
    return -1;
3015
1.83k
}
3016
3017
int
3018
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3019
57.1k
{
3020
57.1k
    setentry *entry;
3021
3022
57.1k
    if (!PyAnySet_Check(set)) {
3023
0
        PyErr_BadInternalCall();
3024
0
        return -1;
3025
0
    }
3026
57.1k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3027
7.00k
        return 0;
3028
50.0k
    *key = entry->key;
3029
50.0k
    *hash = entry->hash;
3030
50.0k
    return 1;
3031
57.1k
}
3032
3033
int
3034
_PySet_NextEntryRef(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
3035
167k
{
3036
167k
    setentry *entry;
3037
3038
167k
    if (!PyAnySet_Check(set)) {
3039
0
        PyErr_BadInternalCall();
3040
0
        return -1;
3041
0
    }
3042
167k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(set);
3043
167k
    if (set_next((PySetObject *)set, pos, &entry) == 0)
3044
39.4k
        return 0;
3045
128k
    *key = Py_NewRef(entry->key);
3046
128k
    *hash = entry->hash;
3047
128k
    return 1;
3048
167k
}
3049
3050
PyObject *
3051
PySet_Pop(PyObject *set)
3052
6.20k
{
3053
6.20k
    if (!PySet_Check(set)) {
3054
0
        PyErr_BadInternalCall();
3055
0
        return NULL;
3056
0
    }
3057
6.20k
    return set_pop(set, NULL);
3058
6.20k
}
3059
3060
int
3061
_PySet_Update(PyObject *set, PyObject *iterable)
3062
0
{
3063
0
    if (!PySet_Check(set)) {
3064
0
        PyErr_BadInternalCall();
3065
0
        return -1;
3066
0
    }
3067
0
    return set_update_internal((PySetObject *)set, iterable);
3068
0
}
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);