Coverage Report

Created: 2026-02-09 07:07

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