changeset: 106204:e898d19c991f tag: tip user: Victor Stinner date: Tue Jan 17 16:57:43 2017 +0100 files: Modules/_struct.c Modules/clinic/_struct.c.h description: _struct module now uses FASTCALL and Argument Clinic diff -r 1a97b10cb420 -r e898d19c991f Modules/_struct.c --- a/Modules/_struct.c Tue Jan 17 04:20:26 2017 +0100 +++ b/Modules/_struct.c Tue Jan 17 16:57:43 2017 +0100 @@ -9,6 +9,8 @@ #include "structmember.h" #include +#include "clinic/_struct.c.h" + static PyTypeObject PyStructType; /* The translation function for each format character is table driven */ @@ -1555,10 +1557,10 @@ string S.format. The buffer's size in b least S.size. See help(struct) for more on format strings."); static PyObject * -s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds) +s_unpack_from(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - static char *kwlist[] = {"buffer", "offset", 0}; - + static const char * const kwlist[] = {"buffer", "offset", 0}; + static _PyArg_Parser parser = {"O|n:unpack_from", kwlist, 0}; PyObject *input; Py_ssize_t offset = 0; Py_buffer vbuf; @@ -1568,9 +1570,9 @@ s_unpack_from(PyObject *self, PyObject * assert(PyStruct_Check(self)); assert(soself->s_codes != NULL); - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O|n:unpack_from", kwlist, - &input, &offset)) + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, + &parser, + &input, &offset)) return NULL; if (PyObject_GetBuffer(input, &vbuf, PyBUF_SIMPLE) < 0) return NULL; @@ -1736,7 +1738,7 @@ s_iter_unpack(PyObject *_so, PyObject *i * */ static int -s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf) +s_pack_internal(PyStructObject *soself, PyObject **args, int offset, char* buf) { formatcode *code; /* XXX(nnorwitz): why does i need to be a local? can we use @@ -1750,7 +1752,7 @@ s_pack_internal(PyStructObject *soself, char *res = buf + code->offset; Py_ssize_t j = code->repeat; while (j--) { - PyObject *v = PyTuple_GET_ITEM(args, i++); + PyObject *v = args[i++]; if (e->format == 's') { Py_ssize_t n; int isstring; @@ -1823,7 +1825,7 @@ to the format string S.format. See help strings."); static PyObject * -s_pack(PyObject *self, PyObject *args) +s_pack(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyStructObject *soself; PyObject *result; @@ -1832,10 +1834,13 @@ s_pack(PyObject *self, PyObject *args) soself = (PyStructObject *)self; assert(PyStruct_Check(self)); assert(soself->s_codes != NULL); - if (PyTuple_GET_SIZE(args) != soself->s_len) + if (nargs != soself->s_len) { PyErr_Format(StructError, - "pack expected %zd items for packing (got %zd)", soself->s_len, PyTuple_GET_SIZE(args)); + "pack expected %zd items for packing (got %zd)", soself->s_len, nargs); + return NULL; + } + if (!_PyArg_NoStackKeywords("pack", kwnames)) { return NULL; } @@ -1862,7 +1867,7 @@ offset. Note that the offset is a requi help(struct) for more on format strings."); static PyObject * -s_pack_into(PyObject *self, PyObject *args) +s_pack_into(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyStructObject *soself; Py_buffer buffer; @@ -1872,31 +1877,34 @@ s_pack_into(PyObject *self, PyObject *ar soself = (PyStructObject *)self; assert(PyStruct_Check(self)); assert(soself->s_codes != NULL); - if (PyTuple_GET_SIZE(args) != (soself->s_len + 2)) + if (nargs != (soself->s_len + 2)) { - if (PyTuple_GET_SIZE(args) == 0) { + if (nargs == 0) { PyErr_Format(StructError, "pack_into expected buffer argument"); } - else if (PyTuple_GET_SIZE(args) == 1) { + else if (nargs == 1) { PyErr_Format(StructError, "pack_into expected offset argument"); } else { PyErr_Format(StructError, "pack_into expected %zd items for packing (got %zd)", - soself->s_len, (PyTuple_GET_SIZE(args) - 2)); + soself->s_len, (nargs - 2)); } return NULL; } + if (!_PyArg_NoStackKeywords("pack_into", kwnames)) { + return NULL; + } /* Extract a writable memory buffer from the first argument */ - if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buffer)) + if (!PyArg_Parse(args[0], "w*", &buffer)) return NULL; assert(buffer.len >= 0); /* Extract the offset from the first argument */ - offset = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 1), PyExc_IndexError); + offset = PyNumber_AsSsize_t(args[1], PyExc_IndexError); if (offset == -1 && PyErr_Occurred()) { PyBuffer_Release(&buffer); return NULL; @@ -1957,10 +1965,10 @@ s_sizeof(PyStructObject *self, void *unu static struct PyMethodDef s_methods[] = { {"iter_unpack", s_iter_unpack, METH_O, s_iter_unpack__doc__}, - {"pack", s_pack, METH_VARARGS, s_pack__doc__}, - {"pack_into", s_pack_into, METH_VARARGS, s_pack_into__doc__}, + {"pack", (PyCFunction)s_pack, METH_FASTCALL, s_pack__doc__}, + {"pack_into", (PyCFunction)s_pack_into, METH_FASTCALL, s_pack_into__doc__}, {"unpack", s_unpack, METH_O, s_unpack__doc__}, - {"unpack_from", (PyCFunction)s_unpack_from, METH_VARARGS|METH_KEYWORDS, + {"unpack_from", (PyCFunction)s_unpack_from, METH_FASTCALL, s_unpack_from__doc__}, {"__sizeof__", (PyCFunction)s_sizeof, METH_NOARGS, s_sizeof__doc__}, {NULL, NULL} /* sentinel */ @@ -2091,27 +2099,21 @@ Return a bytes object containing the val to the format string fmt. See help(struct) for more on format strings."); static PyObject * -pack(PyObject *self, PyObject *args) +pack(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *s_object, *fmt, *newargs, *result; - Py_ssize_t n = PyTuple_GET_SIZE(args); + PyObject *s_object, *fmt, *result; - if (n == 0) { + if (nargs == 0) { PyErr_SetString(PyExc_TypeError, "missing format argument"); return NULL; } - fmt = PyTuple_GET_ITEM(args, 0); - newargs = PyTuple_GetSlice(args, 1, n); - if (newargs == NULL) - return NULL; + fmt = args[0]; s_object = cache_struct(fmt); if (s_object == NULL) { - Py_DECREF(newargs); return NULL; } - result = s_pack(s_object, newargs); - Py_DECREF(newargs); + result = s_pack(s_object, args + 1, nargs - 1, kwnames); Py_DECREF(s_object); return result; } @@ -2125,45 +2127,43 @@ that the offset is a required argument. on format strings."); static PyObject * -pack_into(PyObject *self, PyObject *args) +pack_into(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *s_object, *fmt, *newargs, *result; - Py_ssize_t n = PyTuple_GET_SIZE(args); + PyObject *s_object, *fmt, *result; - if (n == 0) { + if (nargs == 0) { PyErr_SetString(PyExc_TypeError, "missing format argument"); return NULL; } - fmt = PyTuple_GET_ITEM(args, 0); - newargs = PyTuple_GetSlice(args, 1, n); - if (newargs == NULL) - return NULL; + fmt = args[0]; s_object = cache_struct(fmt); if (s_object == NULL) { - Py_DECREF(newargs); return NULL; } - result = s_pack_into(s_object, newargs); - Py_DECREF(newargs); + result = s_pack_into(s_object, args + 1, nargs - 1, kwnames); Py_DECREF(s_object); return result; } -PyDoc_STRVAR(unpack_doc, -"unpack(fmt, buffer) -> (v1, v2, ...)\n\ -\n\ -Return a tuple containing values unpacked according to the format string\n\ -fmt. The buffer's size in bytes must be calcsize(fmt). See help(struct)\n\ -for more on format strings."); +/*[clinic input] +unpack + + fmt: object + inputstr: object + / + +Return a tuple containing values unpacked according to the format string fmt. + +The buffer's size in bytes must be calcsize(fmt). See help(struct)\n\ +for more on format strings. +[clinic start generated code]*/ static PyObject * -unpack(PyObject *self, PyObject *args) +unpack_impl(PyObject *module, PyObject *fmt, PyObject *inputstr) +/*[clinic end generated code: output=66ff65ed7e289828 input=b44db1758c478bb7]*/ { - PyObject *s_object, *fmt, *inputstr, *result; - - if (!PyArg_UnpackTuple(args, "unpack", 2, 2, &fmt, &inputstr)) - return NULL; + PyObject *s_object, *result; s_object = cache_struct(fmt); if (s_object == NULL) @@ -2181,51 +2181,51 @@ fmt. The buffer's size, minus offset, m See help(struct) for more on format strings."); static PyObject * -unpack_from(PyObject *self, PyObject *args, PyObject *kwds) +unpack_from(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *s_object, *fmt, *newargs, *result; - Py_ssize_t n = PyTuple_GET_SIZE(args); + PyObject *s_object, *fmt, *result; - if (n == 0) { + if (nargs == 0) { PyErr_SetString(PyExc_TypeError, "missing format argument"); return NULL; } - fmt = PyTuple_GET_ITEM(args, 0); - newargs = PyTuple_GetSlice(args, 1, n); - if (newargs == NULL) - return NULL; + fmt = args[0]; s_object = cache_struct(fmt); if (s_object == NULL) { - Py_DECREF(newargs); return NULL; } - result = s_unpack_from(s_object, newargs, kwds); - Py_DECREF(newargs); + result = s_unpack_from(s_object, args + 1, nargs - 1, kwnames); Py_DECREF(s_object); return result; } -PyDoc_STRVAR(iter_unpack_doc, -"iter_unpack(fmt, buffer) -> iterator(v1, v2, ...)\n\ -\n\ -Return an iterator yielding tuples unpacked from the given bytes\n\ -source according to the format string, like a repeated invocation of\n\ -unpack_from(). Requires that the bytes length be a multiple of the\n\ -format struct size."); +/*[clinic input] +iter_unpack + + fmt: object + buffer: object + / + +Return an iterator yielding tuples unpacked from the given bytes. + +Return an iterator yielding tuples unpacked from the given bytes +source according to the format string, like a repeated invocation of +unpack_from(). Requires that the bytes length be a multiple of the +format struct size. +[clinic start generated code]*/ static PyObject * -iter_unpack(PyObject *self, PyObject *args) +iter_unpack_impl(PyObject *module, PyObject *fmt, PyObject *buffer) +/*[clinic end generated code: output=27470d5a603262d3 input=c1159551bd9856f6]*/ { - PyObject *s_object, *fmt, *input, *result; - - if (!PyArg_ParseTuple(args, "OO:iter_unpack", &fmt, &input)) - return NULL; + PyObject *s_object, *result; s_object = cache_struct(fmt); if (s_object == NULL) return NULL; - result = s_iter_unpack(s_object, input); + + result = s_iter_unpack(s_object, buffer); Py_DECREF(s_object); return result; } @@ -2233,12 +2233,11 @@ iter_unpack(PyObject *self, PyObject *ar static struct PyMethodDef module_functions[] = { {"_clearcache", (PyCFunction)clearcache, METH_NOARGS, clearcache_doc}, {"calcsize", calcsize, METH_O, calcsize_doc}, - {"iter_unpack", iter_unpack, METH_VARARGS, iter_unpack_doc}, - {"pack", pack, METH_VARARGS, pack_doc}, - {"pack_into", pack_into, METH_VARARGS, pack_into_doc}, - {"unpack", unpack, METH_VARARGS, unpack_doc}, - {"unpack_from", (PyCFunction)unpack_from, - METH_VARARGS|METH_KEYWORDS, unpack_from_doc}, + ITER_UNPACK_METHODDEF + {"pack", (PyCFunction)pack, METH_FASTCALL, pack_doc}, + {"pack_into", (PyCFunction)pack_into, METH_FASTCALL, pack_into_doc}, + UNPACK_METHODDEF + {"unpack_from", (PyCFunction)unpack_from, METH_FASTCALL, unpack_from_doc}, {NULL, NULL} /* sentinel */ }; diff -r 1a97b10cb420 -r e898d19c991f Modules/clinic/_struct.c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/clinic/_struct.c.h Tue Jan 17 16:57:43 2017 +0100 @@ -0,0 +1,80 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(unpack__doc__, +"unpack($module, fmt, inputstr, /)\n" +"--\n" +"\n" +"Return a tuple containing values unpacked according to the format string fmt.\n" +"\n" +"The buffer\'s size in bytes must be calcsize(fmt). See help(struct)\\n\\\n" +"for more on format strings."); + +#define UNPACK_METHODDEF \ + {"unpack", (PyCFunction)unpack, METH_FASTCALL, unpack__doc__}, + +static PyObject * +unpack_impl(PyObject *module, PyObject *fmt, PyObject *inputstr); + +static PyObject * +unpack(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *fmt; + PyObject *inputstr; + + if (!_PyArg_UnpackStack(args, nargs, "unpack", + 2, 2, + &fmt, &inputstr)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("unpack", kwnames)) { + goto exit; + } + return_value = unpack_impl(module, fmt, inputstr); + +exit: + return return_value; +} + +PyDoc_STRVAR(iter_unpack__doc__, +"iter_unpack($module, fmt, buffer, /)\n" +"--\n" +"\n" +"Return an iterator yielding tuples unpacked from the given bytes.\n" +"\n" +"Return an iterator yielding tuples unpacked from the given bytes\n" +"source according to the format string, like a repeated invocation of\n" +"unpack_from(). Requires that the bytes length be a multiple of the\n" +"format struct size."); + +#define ITER_UNPACK_METHODDEF \ + {"iter_unpack", (PyCFunction)iter_unpack, METH_FASTCALL, iter_unpack__doc__}, + +static PyObject * +iter_unpack_impl(PyObject *module, PyObject *fmt, PyObject *buffer); + +static PyObject * +iter_unpack(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *fmt; + PyObject *buffer; + + if (!_PyArg_UnpackStack(args, nargs, "iter_unpack", + 2, 2, + &fmt, &buffer)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("iter_unpack", kwnames)) { + goto exit; + } + return_value = iter_unpack_impl(module, fmt, buffer); + +exit: + return return_value; +} +/*[clinic end generated code: output=d474e2de736a8b48 input=a9049054013a1b77]*/