Skip to content

Commit 5f147c6

Browse files
committed
Implement FOR_ITER_SET
1 parent f805d37 commit 5f147c6

File tree

10 files changed

+144
-87
lines changed

10 files changed

+144
-87
lines changed

Include/internal/pycore_opcode.h

Lines changed: 14 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_set.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef Py_INTERNAL_SET_H
2+
#define Py_INTERNAL_SET_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
typedef struct {
12+
PyObject_HEAD
13+
PySetObject *si_set; /* Set to NULL when iterator is exhausted */
14+
Py_ssize_t si_used;
15+
Py_ssize_t si_pos;
16+
Py_ssize_t len;
17+
} _PySetIterObject;
18+
19+
int _PySetIter_GetNext(_PySetIterObject *si, PyObject**);
20+
21+
#ifdef __cplusplus
22+
}
23+
#endif
24+
#endif /* !Py_INTERNAL_SET_H */

Include/opcode.h

Lines changed: 33 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def jabs_op(name, op):
282282
"FOR_ITER_ADAPTIVE",
283283
"FOR_ITER_LIST",
284284
"FOR_ITER_RANGE",
285+
"FOR_ITER_SET",
285286
],
286287
"JUMP_BACKWARD": [
287288
"JUMP_BACKWARD_QUICK",

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,7 @@ PYTHON_HEADERS= \
16311631
$(srcdir)/Include/internal/pycore_range.h \
16321632
$(srcdir)/Include/internal/pycore_runtime.h \
16331633
$(srcdir)/Include/internal/pycore_runtime_init.h \
1634+
$(srcdir)/Include/internal/pycore_set.h \
16341635
$(srcdir)/Include/internal/pycore_signal.h \
16351636
$(srcdir)/Include/internal/pycore_sliceobject.h \
16361637
$(srcdir)/Include/internal/pycore_strhex.h \

Objects/setobject.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
*/
3333

3434
#include "Python.h"
35+
#include "pycore_set.h" // struct _PySetIterObject
3536
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
3637
#include <stddef.h> // offsetof()
3738

3839
/* Object used as dummy key to fill deleted entries */
3940
static PyObject _dummy_struct;
40-
4141
#define dummy (&_dummy_struct)
4242

4343

@@ -730,16 +730,8 @@ frozenset_hash(PyObject *self)
730730

731731
/***** Set iterator type ***********************************************/
732732

733-
typedef struct {
734-
PyObject_HEAD
735-
PySetObject *si_set; /* Set to NULL when iterator is exhausted */
736-
Py_ssize_t si_used;
737-
Py_ssize_t si_pos;
738-
Py_ssize_t len;
739-
} setiterobject;
740-
741733
static void
742-
setiter_dealloc(setiterobject *si)
734+
setiter_dealloc(_PySetIterObject *si)
743735
{
744736
/* bpo-31095: UnTrack is needed before calling any callbacks */
745737
_PyObject_GC_UNTRACK(si);
@@ -748,30 +740,30 @@ setiter_dealloc(setiterobject *si)
748740
}
749741

750742
static int
751-
setiter_traverse(setiterobject *si, visitproc visit, void *arg)
743+
setiter_traverse(_PySetIterObject *si, visitproc visit, void *arg)
752744
{
753745
Py_VISIT(si->si_set);
754746
return 0;
755747
}
756748

757749
static PyObject *
758-
setiter_len(setiterobject *si, PyObject *Py_UNUSED(ignored))
750+
setiter_len(_PySetIterObject *si, PyObject *Py_UNUSED(ignored))
759751
{
760752
Py_ssize_t len = 0;
761753
if (si->si_set != NULL && si->si_used == si->si_set->used)
762754
len = si->len;
763755
return PyLong_FromSsize_t(len);
764756
}
765757

766-
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
758+
static PyObject *setiter_iternext(_PySetIterObject *si);
767759

768-
static PyObject *setiter_iternext(setiterobject *si);
760+
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
769761

770762
static PyObject *
771-
setiter_reduce(setiterobject *si, PyObject *Py_UNUSED(ignored))
763+
setiter_reduce(_PySetIterObject *si, PyObject *Py_UNUSED(ignored))
772764
{
773765
/* copy the iterator state */
774-
setiterobject tmp = *si;
766+
_PySetIterObject tmp = *si;
775767
Py_XINCREF(tmp.si_set);
776768

777769
/* iterate the temporary into a list */
@@ -791,48 +783,60 @@ static PyMethodDef setiter_methods[] = {
791783
{NULL, NULL} /* sentinel */
792784
};
793785

794-
static PyObject *setiter_iternext(setiterobject *si)
786+
int _PySetIter_GetNext(_PySetIterObject *si, PyObject **stack)
795787
{
796-
PyObject *key;
788+
assert(Py_IS_TYPE((PyObject *)si, &PySetIter_Type));
797789
Py_ssize_t i, mask;
798790
setentry *entry;
799791
PySetObject *so = si->si_set;
800792

801-
if (so == NULL)
802-
return NULL;
793+
if (so == NULL) {
794+
return 0;
795+
}
803796
assert (PyAnySet_Check(so));
804797

805798
if (si->si_used != so->used) {
806799
PyErr_SetString(PyExc_RuntimeError,
807800
"Set changed size during iteration");
808801
si->si_used = -1; /* Make this state sticky */
809-
return NULL;
802+
return -1;
810803
}
811804

812805
i = si->si_pos;
813806
assert(i>=0);
814807
entry = so->table;
815808
mask = so->mask;
816-
while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy))
809+
while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
817810
i++;
811+
}
818812
si->si_pos = i+1;
819-
if (i > mask)
813+
if (i > mask) {
820814
goto fail;
815+
}
821816
si->len--;
822-
key = entry[i].key;
823-
Py_INCREF(key);
824-
return key;
825-
817+
stack[0] = entry[i].key;
818+
Py_INCREF(stack[0]);
819+
return 1;
826820
fail:
827821
si->si_set = NULL;
828822
Py_DECREF(so);
829-
return NULL;
823+
return 0;
824+
}
825+
826+
static PyObject *setiter_iternext(_PySetIterObject *si) {
827+
PyObject *key = NULL;
828+
PyObject *stack[1];
829+
int err = _PySetIter_GetNext(si, stack);
830+
if (err <= 0) {
831+
return NULL;
832+
}
833+
return stack[0];
830834
}
831835

832836
PyTypeObject PySetIter_Type = {
833837
PyVarObject_HEAD_INIT(&PyType_Type, 0)
834838
"set_iterator", /* tp_name */
835-
sizeof(setiterobject), /* tp_basicsize */
839+
sizeof(_PySetIterObject), /* tp_basicsize */
836840
0, /* tp_itemsize */
837841
/* methods */
838842
(destructor)setiter_dealloc, /* tp_dealloc */
@@ -865,7 +869,7 @@ PyTypeObject PySetIter_Type = {
865869
static PyObject *
866870
set_iter(PySetObject *so)
867871
{
868-
setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
872+
_PySetIterObject *si = PyObject_GC_New(_PySetIterObject, &PySetIter_Type);
869873
if (si == NULL)
870874
return NULL;
871875
Py_INCREF(so);

0 commit comments

Comments
 (0)