Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
e440e47e
Commit
e440e47e
authored
Jun 01, 2004
by
Martin v. Löwis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Patch #957398: Add public API for Generator Object/Type.
parent
09e2cb0b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
207 additions
and
138 deletions
+207
-138
Doc/api/concrete.tex
Doc/api/concrete.tex
+31
-0
Include/ceval.h
Include/ceval.h
+1
-0
Include/genobject.h
Include/genobject.h
+33
-0
Makefile.pre.in
Makefile.pre.in
+2
-0
Misc/NEWS
Misc/NEWS
+3
-0
Objects/genobject.c
Objects/genobject.c
+129
-0
Python/ceval.c
Python/ceval.c
+8
-138
No files found.
Doc/api/concrete.tex
View file @
e440e47e
...
...
@@ -2603,3 +2603,34 @@ when accessed. Cell objects are not likely to be useful elsewhere.
reference counts are adjusted, and no checks are made for safety;
\var
{
cell
}
must be non-
\NULL
{}
and must be a cell object.
\end{cfuncdesc}
\subsection
{
Generator Objects
\label
{
gen-objects
}}
Generator objects are what Python uses to implement generator iterators.
They are normally created by iterating over a function that yields values,
rather than explicitly calling
\cfunction
{
PyGen
_
New
}
.
\begin{ctypedesc}
{
PyGenObject
}
The C structure used for generator objects.
\end{ctypedesc}
\begin{cvardesc}
{
PyTypeObject
}{
PyGen
_
Type
}
The type object corresponding to generator objects
\end{cvardesc}
\begin{cfuncdesc}
{
int
}{
PyGen
_
Check
}{
ob
}
Return true if
\var
{
ob
}
is a generator object;
\var
{
ob
}
must not be
\NULL
.
\end{cfuncdesc}
\begin{cfuncdesc}
{
int
}{
PyGen
_
CheckExact
}{
ob
}
Return true if
\var
{
ob
}
's type is
\var
{
PyGen
_
Type
}
is a generator object;
\var
{
ob
}
must not be
\NULL
.
\end{cfuncdesc}
\begin{cfuncdesc}
{
PyObject*
}{
PyGen
_
New
}{
PyFrameObject *frame
}
Create and return a new generator object based on the
\var
{
frame
}
object.
The parameter must not be
\NULL
.
\end{cfuncdesc}
Include/ceval.h
View file @
e440e47e
...
...
@@ -64,6 +64,7 @@ PyAPI_FUNC(char *) PyEval_GetFuncName(PyObject *);
PyAPI_FUNC
(
char
*
)
PyEval_GetFuncDesc
(
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
PyEval_GetCallStats
(
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
PyEval_EvaluateFrame
(
PyObject
*
);
/* this used to be handled on a per-thread basis - now just two globals */
PyAPI_DATA
(
volatile
int
)
_Py_Ticker
;
...
...
Include/genobject.h
0 → 100644
View file @
e440e47e
/* Generator object interface */
#ifndef Py_GENOBJECT_H
#define Py_GENOBJECT_H
#ifdef __cplusplus
extern
"C"
{
#endif
typedef
struct
{
PyObject_HEAD
/* The gi_ prefix is intended to remind of generator-iterator. */
PyFrameObject
*
gi_frame
;
/* True if generator is being executed. */
int
gi_running
;
/* List of weak reference. */
PyObject
*
gi_weakreflist
;
}
PyGenObject
;
PyAPI_DATA
(
PyTypeObject
)
PyGen_Type
;
#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type)
#define PyGen_CheckExact(op) ((op)->ob_type == &PyGen_Type)
PyAPI_FUNC
(
PyObject
*
)
PyGen_New
(
PyFrameObject
*
);
#ifdef __cplusplus
}
#endif
#endif
/* !Py_GENOBJECT_H */
Makefile.pre.in
View file @
e440e47e
...
...
@@ -261,6 +261,7 @@ OBJECT_OBJS= \
Objects/complexobject.o
\
Objects/descrobject.o
\
Objects/enumobject.o
\
Objects/genobject.o
\
Objects/fileobject.o
\
Objects/floatobject.o
\
Objects/frameobject.o
\
...
...
@@ -478,6 +479,7 @@ PYTHON_HEADERS= \
Include/descrobject.h
\
Include/dictobject.h
\
Include/enumobject.h
\
Include/genobject.h
\
Include/fileobject.h
\
Include/floatobject.h
\
Include/funcobject.h
\
...
...
Misc/NEWS
View file @
e440e47e
...
...
@@ -497,6 +497,9 @@ Build
C
API
-----
-
New
public
functions
PyEval_EvaluateFrame
and
PyGen_New
to
expose
generator
objects
.
-
New
public
functions
Py_IncRef
()
and
Py_DecRef
(),
exposing
the
functionality
of
the
Py_XINCREF
()
and
Py_XDECREF
macros
.
Useful
for
runtime
dynamic
embedding
of
Python
.
See
patch
#
938302
,
by
Bob
...
...
Objects/genobject.c
0 → 100644
View file @
e440e47e
/* 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
;
}
Python/ceval.c
View file @
e440e47e
...
...
@@ -10,6 +10,7 @@
#include "compile.h"
#include "frameobject.h"
#include "genobject.h"
#include "eval.h"
#include "opcode.h"
#include "structmember.h"
...
...
@@ -139,143 +140,6 @@ PyEval_GetCallStats(PyObject *self)
}
#endif
static
PyTypeObject
gentype
;
typedef
struct
{
PyObject_HEAD
/* The gi_ prefix is intended to remind of generator-iterator. */
PyFrameObject
*
gi_frame
;
/* True if generator is being executed. */
int
gi_running
;
/* List of weak reference. */
PyObject
*
gi_weakreflist
;
}
genobject
;
static
PyObject
*
gen_new
(
PyFrameObject
*
f
)
{
genobject
*
gen
=
PyObject_GC_New
(
genobject
,
&
gentype
);
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
;
}
static
int
gen_traverse
(
genobject
*
gen
,
visitproc
visit
,
void
*
arg
)
{
return
visit
((
PyObject
*
)
gen
->
gi_frame
,
arg
);
}
static
void
gen_dealloc
(
genobject
*
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
(
genobject
*
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
=
eval_frame
(
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
(
genobject
,
gi_frame
),
RO
},
{
"gi_running"
,
T_INT
,
offsetof
(
genobject
,
gi_running
),
RO
},
{
NULL
}
/* Sentinel */
};
static
PyTypeObject
gentype
=
{
PyObject_HEAD_INIT
(
&
PyType_Type
)
0
,
/* ob_size */
"generator"
,
/* tp_name */
sizeof
(
genobject
),
/* 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
(
genobject
,
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 */
};
#ifdef WITH_THREAD
...
...
@@ -2673,7 +2537,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
/* Create a new generator that owns the ready to run frame
* and return that as the value. */
return
gen_n
ew
(
f
);
return
PyGen_N
ew
(
f
);
}
retval
=
eval_frame
(
f
);
...
...
@@ -3407,6 +3271,12 @@ PyEval_GetFuncDesc(PyObject *func)
}
}
PyObject
*
PyEval_EvaluateFrame
(
PyObject
*
fo
)
{
return
eval_frame
((
PyFrameObject
*
)
fo
);
}
#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
static
void
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment