Skip to content

Commit

Permalink
Add API for static strings, primarily good for identifiers.
Browse files Browse the repository at this point in the history
Thanks to Konrad Schöbel and Jasper Schulz for helping with the mass-editing.
  • Loading branch information
loewis committed Oct 9, 2011
1 parent 67df285 commit afe55bb
Show file tree
Hide file tree
Showing 50 changed files with 571 additions and 233 deletions.
12 changes: 12 additions & 0 deletions Include/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern "C" {
#ifdef PY_SSIZE_T_CLEAN
#define PyObject_CallFunction _PyObject_CallFunction_SizeT
#define PyObject_CallMethod _PyObject_CallMethod_SizeT
#define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT
#endif

/* Abstract Object Interface (many thanks to Jim Fulton) */
Expand Down Expand Up @@ -307,11 +308,22 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
Python expression: o.method(args).
*/

PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *o, _Py_Identifier *method,
char *format, ...);

/*
Like PyObject_CallMethod, but expect a _Py_Identifier* as the
method name.
*/

PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable,
char *format, ...);
PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *o,
char *name,
char *format, ...);
PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *o,
_Py_Identifier *name,
char *format, ...);

PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable,
...);
Expand Down
4 changes: 4 additions & 0 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ PyAPI_FUNC(unsigned int) PyType_ClearCache(void);
PyAPI_FUNC(void) PyType_Modified(PyTypeObject *);

/* Generic operations on objects */
struct _Py_Identifier;
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
PyAPI_FUNC(void) _Py_BreakPoint(void);
Expand All @@ -471,6 +472,9 @@ PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *);
PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *);
PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
#endif
Expand Down
34 changes: 34 additions & 0 deletions Include/unicodeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -2024,6 +2024,40 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
int check_content);
#endif

/********************* String Literals ****************************************/
/* This structure helps managing static strings. The basic usage goes like this:
Instead of doing
r = PyObject_CallMethod(o, "foo", "args", ...);
do
_Py_identifier(foo);
...
r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...);
PyId_foo is a static variable, either on block level or file level. On first
usage, the string "foo" is interned, and the structures are linked. On interpreter
shutdown, all strings are released (through _PyUnicode_ClearStaticStrings).
Alternatively, _Py_static_string allows to choose the variable name.
_PyUnicode_FromId returns a new reference to the interned string.
_PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
*/
typedef struct _Py_Identifier {
struct _Py_Identifier *next;
const char* string;
PyObject *object;
} _Py_Identifier;

#define _Py_static_string(varname, value) static _Py_Identifier varname = { 0, value, 0 };
#define _Py_identifier(varname) _Py_static_string(PyId_##varname, #varname)

/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/
PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*);
/* Clear all static strings. */
PyAPI_FUNC(void) _PyUnicode_ClearStaticStrings(void);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins
-----------------

- Add internal API for static strings (_Py_identifier et.al.).

- Issue #13063: the Windows error ERROR_NO_DATA (numbered 232 and described
as "The pipe is being closed") is now mapped to POSIX errno EPIPE
(previously EINVAL).
Expand Down
8 changes: 6 additions & 2 deletions Modules/_bisectmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ insort_right(PyObject *self, PyObject *args, PyObject *kw)
if (PyList_Insert(list, index, item) < 0)
return NULL;
} else {
result = PyObject_CallMethod(list, "insert", "nO", index, item);
_Py_identifier(insert);

result = _PyObject_CallMethodId(list, &PyId_insert, "nO", index, item);
if (result == NULL)
return NULL;
Py_DECREF(result);
Expand Down Expand Up @@ -186,7 +188,9 @@ insort_left(PyObject *self, PyObject *args, PyObject *kw)
if (PyList_Insert(list, index, item) < 0)
return NULL;
} else {
result = PyObject_CallMethod(list, "insert", "iO", index, item);
_Py_identifier(insert);

result = _PyObject_CallMethodId(list, &PyId_insert, "iO", index, item);
if (result == NULL)
return NULL;
Py_DECREF(result);
Expand Down
4 changes: 3 additions & 1 deletion Modules/_collectionsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,13 +1334,15 @@ defdict_reduce(defdictobject *dd)
PyObject *items;
PyObject *iter;
PyObject *result;
_Py_identifier(items);

if (dd->default_factory == NULL || dd->default_factory == Py_None)
args = PyTuple_New(0);
else
args = PyTuple_Pack(1, dd->default_factory);
if (args == NULL)
return NULL;
items = PyObject_CallMethod((PyObject *)dd, "items", "()");
items = _PyObject_CallMethodId((PyObject *)dd, &PyId_items, "()");
if (items == NULL) {
Py_DECREF(args);
return NULL;
Expand Down
4 changes: 3 additions & 1 deletion Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3679,8 +3679,10 @@ _build_result(PyObject *result, PyObject *callargs,
PyTuple_SET_ITEM(tup, index, v);
index++;
} else if (bit & outmask) {
_Py_identifier(__ctypes_from_outparam__);

v = PyTuple_GET_ITEM(callargs, i);
v = PyObject_CallMethod(v, "__ctypes_from_outparam__", NULL);
v = _PyObject_CallMethodId(v, &PyId___ctypes_from_outparam__, NULL);
if (v == NULL || numretvals == 1) {
Py_DECREF(callargs);
return v;
Expand Down
6 changes: 4 additions & 2 deletions Modules/_ctypes/callproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1687,13 +1687,15 @@ unpickle(PyObject *self, PyObject *args)
PyObject *state;
PyObject *result;
PyObject *tmp;
_Py_identifier(__new__);
_Py_identifier(__setstate__);

if (!PyArg_ParseTuple(args, "OO", &typ, &state))
return NULL;
result = PyObject_CallMethod(typ, "__new__", "O", typ);
result = _PyObject_CallMethodId(typ, &PyId___new__, "O", typ);
if (result == NULL)
return NULL;
tmp = PyObject_CallMethod(result, "__setstate__", "O", state);
tmp = _PyObject_CallMethodId(result, &PyId___setstate__, "O", state);
if (tmp == NULL) {
Py_DECREF(result);
return NULL;
Expand Down
7 changes: 5 additions & 2 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1418,10 +1418,12 @@ PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *stream)
while (1) {
char buf[BUFSIZ];
Py_ssize_t n = fread(buf, 1, BUFSIZ, fp);
_Py_identifier(write);

if (n <= 0)
break;
Py_DECREF(res);
res = PyObject_CallMethod(stream, "write", "y#", buf, n);
res = _PyObject_CallMethodId(stream, &PyId_write, "y#", buf, n);
if (res == NULL)
break;
}
Expand Down Expand Up @@ -1911,6 +1913,7 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
WINDOW *win;

PyCursesInitialised;
_Py_identifier(read);

strcpy(fn, "/tmp/py.curses.getwin.XXXXXX");
fd = mkstemp(fn);
Expand All @@ -1922,7 +1925,7 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
remove(fn);
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
}
data = PyObject_CallMethod(stream, "read", "");
data = _PyObject_CallMethodId(stream, &PyId_read, "");
if (data == NULL) {
fclose(fp);
remove(fn);
Expand Down
Loading

0 comments on commit afe55bb

Please sign in to comment.