diff options
author | Martin v. Löwis <martin@v.loewis.de> | 2004-06-01 15:22:42 (GMT) |
---|---|---|
committer | Martin v. Löwis <martin@v.loewis.de> | 2004-06-01 15:22:42 (GMT) |
commit | e440e47e91a93ae57870da8753f9c141c4a37885 (patch) | |
tree | b51a0c792d63b9357dccbd781000d2c4ea8274b0 /Objects | |
parent | 09e2cb0ba70aeb52bf6562120103573d7f65cbd6 (diff) | |
download | cpython-e440e47e91a93ae57870da8753f9c141c4a37885.zip cpython-e440e47e91a93ae57870da8753f9c141c4a37885.tar.gz cpython-e440e47e91a93ae57870da8753f9c141c4a37885.tar.bz2 |
Patch #957398: Add public API for Generator Object/Type.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/genobject.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c new file mode 100644 index 0000000..0f7373a --- /dev/null +++ b/Objects/genobject.c @@ -0,0 +1,129 @@ +/* Generator object implementation */ + +#include "Python.h" +#include "frameobject.h" +#include "genobject.h" +#include "ceval.h" +#include "structmember.h" + +static int +gen_traverse(PyGenObject *gen, visitproc visit, void *arg) +{ + return visit((PyObject *)gen->gi_frame, arg); +} + +static void +gen_dealloc(PyGenObject *gen) +{ + _PyObject_GC_UNTRACK(gen); + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) gen); + Py_DECREF(gen->gi_frame); + PyObject_GC_Del(gen); +} + +static PyObject * +gen_iternext(PyGenObject *gen) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyFrameObject *f = gen->gi_frame; + PyObject *result; + + if (gen->gi_running) { + PyErr_SetString(PyExc_ValueError, + "generator already executing"); + return NULL; + } + if (f->f_stacktop == NULL) + return NULL; + + /* Generators always return to their most recent caller, not + * necessarily their creator. */ + Py_XINCREF(tstate->frame); + assert(f->f_back == NULL); + f->f_back = tstate->frame; + + gen->gi_running = 1; + result = PyEval_EvaluateFrame((PyObject *)f); + gen->gi_running = 0; + + /* Don't keep the reference to f_back any longer than necessary. It + * may keep a chain of frames alive or it could create a reference + * cycle. */ + Py_XDECREF(f->f_back); + f->f_back = NULL; + + /* If the generator just returned (as opposed to yielding), signal + * that the generator is exhausted. */ + if (result == Py_None && f->f_stacktop == NULL) { + Py_DECREF(result); + result = NULL; + } + + return result; +} + +static PyObject * +gen_getiter(PyObject *gen) +{ + Py_INCREF(gen); + return gen; +} + +static PyMemberDef gen_memberlist[] = { + {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), RO}, + {"gi_running", T_INT, offsetof(PyGenObject, gi_running), RO}, + {NULL} /* Sentinel */ +}; + +PyTypeObject PyGen_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "generator", /* tp_name */ + sizeof(PyGenObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)gen_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)gen_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ + (getiterfunc)gen_getiter, /* tp_iter */ + (iternextfunc)gen_iternext, /* tp_iternext */ + 0, /* tp_methods */ + gen_memberlist, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ +}; + +PyObject * +PyGen_New(PyFrameObject *f) +{ + PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type); + if (gen == NULL) { + Py_DECREF(f); + return NULL; + } + gen->gi_frame = f; + gen->gi_running = 0; + gen->gi_weakreflist = NULL; + _PyObject_GC_TRACK(gen); + return (PyObject *)gen; +} |