Kaydet (Commit) d4ff1b90 authored tarafından Barry Warsaw's avatar Barry Warsaw

New strop_joinfields implementation, highly optimized for Lists. All

other sequences use the Sequence protocol from the abstract API.  The
algorithm has changed so that only one pass through the sequences are
made.
üst 95f92dfa
...@@ -168,11 +168,13 @@ strop_joinfields(self, args) ...@@ -168,11 +168,13 @@ strop_joinfields(self, args)
PyObject *self; /* Not used */ PyObject *self; /* Not used */
PyObject *args; PyObject *args;
{ {
PyObject *seq, *item, *res; PyObject *seq;
char *p, *sep = NULL; char *sep = NULL;
int seqlen, reslen, itemlen, i, seplen = 0; int seqlen, seplen = 0;
int ownrefs = 0; int i, reslen = 0, slen = 0, sz = 100;
PyObject* (*getitemfunc) Py_PROTO((PyObject*, int)); PyObject *res = NULL;
char* p = NULL;
intargfunc getitemfunc;
if (!PyArg_ParseTuple(args, "O|s#", &seq, &sep, &seplen)) if (!PyArg_ParseTuple(args, "O|s#", &seq, &sep, &seplen))
return NULL; return NULL;
...@@ -180,84 +182,104 @@ strop_joinfields(self, args) ...@@ -180,84 +182,104 @@ strop_joinfields(self, args)
sep = " "; sep = " ";
seplen = 1; seplen = 1;
} }
/* do it this way to optimize for the common cases, but also
* support the more general sequence protocol
*/
if (PyList_Check(seq)) {
getitemfunc = PyList_GetItem;
seqlen = PyList_Size(seq);
}
else if (PyTuple_Check(seq)) {
getitemfunc = PyTuple_GetItem;
seqlen = PyTuple_Size(seq);
}
else if (PySequence_Check(seq)) {
getitemfunc = PySequence_GetItem;
seqlen = PySequence_Length(seq); seqlen = PySequence_Length(seq);
ownrefs = 1;
}
else {
PyErr_SetString(PyExc_TypeError,
"first argument must be a sequence");
return NULL;
}
if (seqlen < 0 && PyErr_Occurred()) if (seqlen < 0 && PyErr_Occurred())
return NULL; return NULL;
reslen = 0; if (seqlen == 1) {
for (i = 0; i < seqlen; i++) { /* Optimization if there's only one item */
if (!(item = getitemfunc(seq, i))) PyObject *item = PySequence_GetItem(seq, 0);
if (item && !PyString_Check(item))
PyErr_SetString(PyExc_TypeError,
"first argument must be sequence of strings");
return item;
}
if (!(res = PyString_FromStringAndSize((char*)NULL, sz)))
return NULL; return NULL;
p = PyString_AsString(res);
/* optimize for lists, since it's the most common case. all others
* (tuples and arbitrary sequences) just use the sequence abstract
* interface.
*/
if (PyList_Check(seq)) {
for (i = 0; i < seqlen; i++) {
PyObject *item = PyList_GET_ITEM(seq, i);
if (!PyString_Check(item)) { if (!PyString_Check(item)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"first argument must be sequence of strings"); "first argument must be sequence of strings");
if (ownrefs) Py_DECREF(res);
Py_DECREF(item);
return NULL; return NULL;
} }
if (i > 0) slen = PyString_GET_SIZE(item);
while (reslen + slen + seplen >= sz) {
if (_PyString_Resize(&res, sz * 2)) {
Py_DECREF(res);
return NULL;
}
sz *= 2;
p = PyString_AsString(res) + reslen;
}
if (i > 0) {
memcpy(p, sep, seplen);
p += seplen;
reslen += seplen; reslen += seplen;
reslen += PyString_Size(item);
if (ownrefs)
Py_DECREF(item);
} }
if (seqlen == 1) { memcpy(p, PyString_AS_STRING(item), slen);
/* Optimization if there's only one item */ p += slen;
item = getitemfunc(seq, 0); reslen += slen;
if (!ownrefs)
Py_XINCREF(item);
return item;
} }
if (_PyString_Resize(&res, reslen)) {
res = PyString_FromStringAndSize((char *)NULL, reslen); Py_DECREF(res);
if (res == NULL) res = NULL;
}
return res;
}
else if (!PySequence_Check(seq)) {
PyErr_SetString(PyExc_TypeError,
"first argument must be a sequence");
return NULL; return NULL;
p = PyString_AsString(res); }
/* type safe */
getitemfunc = seq->ob_type->tp_as_sequence->sq_item;
for (i = 0; i < seqlen; i++) { for (i = 0; i < seqlen; i++) {
if (!(item = getitemfunc(seq, i))) { PyObject *item = getitemfunc(seq, i);
if (!item || !PyString_Check(item)) {
PyErr_SetString(PyExc_TypeError,
"first argument must be sequence of strings");
Py_DECREF(res); Py_DECREF(res);
Py_XDECREF(item);
return NULL; return NULL;
} }
slen = PyString_GET_SIZE(item);
while (reslen + slen + seplen >= sz) {
if (_PyString_Resize(&res, sz * 2)) {
Py_DECREF(res);
Py_DECREF(item);
return NULL;
}
sz *= 2;
p = PyString_AsString(res) + reslen;
}
if (i > 0) { if (i > 0) {
memcpy(p, sep, seplen); memcpy(p, sep, seplen);
p += seplen; p += seplen;
reslen += seplen;
} }
itemlen = PyString_Size(item); memcpy(p, PyString_AS_STRING(item), slen);
memcpy(p, PyString_AsString(item), itemlen); p += slen;
p += itemlen; reslen += slen;
if (ownrefs)
Py_DECREF(item); Py_DECREF(item);
} }
if (p != PyString_AsString(res) + reslen) { if (_PyString_Resize(&res, reslen)) {
PyErr_SetString(PyExc_SystemError, Py_DECREF(res);
"strop.joinfields: assertion failed"); res = NULL;
return NULL;
} }
return res; return res;
} }
static PyObject * static PyObject *
strop_find(self, args) strop_find(self, args)
PyObject *self; /* Not used */ PyObject *self; /* Not used */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment