two changes to string_join:

implementation -- use PySequence_Fast interface to iterate over elements
interface -- if instance object reports wrong length, ignore it;
   previous version raised an IndexError if reported length was too high
This commit is contained in:
Jeremy Hylton 2000-07-10 21:30:28 +00:00
parent 663809ed83
commit 194e43e953
1 changed files with 45 additions and 85 deletions

View File

@ -744,91 +744,52 @@ string_join(PyStringObject *self, PyObject *args)
int seqlen = 0; int seqlen = 0;
int sz = 100; int sz = 100;
int i, slen; int i, slen;
PyObject *seq; PyObject *orig, *seq, *item;
if (!PyArg_ParseTuple(args, "O:join", &seq)) if (!PyArg_ParseTuple(args, "O:join", &orig))
return NULL; return NULL;
seq = PySequence_Fast(orig, "");
if (seq == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_Format(PyExc_TypeError,
"sequence expected, %.80s found",
orig->ob_type->tp_name);
return NULL;
}
seqlen = PySequence_Length(seq); seqlen = PySequence_Length(seq);
if (seqlen < 0 && PyErr_Occurred())
return NULL;
if (seqlen == 1) { if (seqlen == 1) {
/* Optimization if there's only one item */ item = PySequence_Fast_GET_ITEM(seq, 0);
PyObject *item = PySequence_GetItem(seq, 0); Py_INCREF(item);
if (item == NULL)
return NULL;
if (!PyString_Check(item) &&
!PyUnicode_Check(item)) {
PyErr_SetString(PyExc_TypeError,
"first argument must be sequence of strings");
Py_DECREF(item);
return NULL;
}
return item; return item;
} }
if (!(res = PyString_FromStringAndSize((char*)NULL, sz))) if (!(res = PyString_FromStringAndSize((char*)NULL, sz)))
return NULL; return NULL;
p = PyString_AsString(res); p = PyString_AsString(res);
/* optimize for lists. all others (tuples and arbitrary sequences)
* just use the abstract interface.
*/
if (PyList_Check(seq)) {
for (i = 0; i < seqlen; i++) { for (i = 0; i < seqlen; i++) {
PyObject *item = PyList_GET_ITEM(seq, i); item = PySequence_Fast_GET_ITEM(seq, i);
if (!PyString_Check(item)){
if (PyUnicode_Check(item)) {
Py_DECREF(res);
return PyUnicode_Join(
(PyObject *)self,
seq);
}
PyErr_Format(PyExc_TypeError,
"sequence item %i not a string",
i);
goto finally;
}
slen = PyString_GET_SIZE(item);
while (reslen + slen + seplen >= sz) {
if (_PyString_Resize(&res, sz*2))
goto finally;
sz *= 2;
p = PyString_AsString(res) + reslen;
}
if (i > 0) {
memcpy(p, sep, seplen);
p += seplen;
reslen += seplen;
}
memcpy(p, PyString_AS_STRING(item), slen);
p += slen;
reslen += slen;
}
}
else {
for (i = 0; i < seqlen; i++) {
PyObject *item = PySequence_GetItem(seq, i);
if (!item)
goto finally;
if (!PyString_Check(item)){ if (!PyString_Check(item)){
if (PyUnicode_Check(item)) { if (PyUnicode_Check(item)) {
Py_DECREF(res); Py_DECREF(res);
Py_DECREF(item); Py_DECREF(item);
return PyUnicode_Join( return PyUnicode_Join((PyObject *)self,
(PyObject *)self,
seq); seq);
} }
Py_DECREF(item);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"sequence item %i not a string", "sequence item %i: expected string, %.80s found",
i); i, item->ob_type->tp_name);
Py_DECREF(item);
Py_DECREF(seq);
goto finally; goto finally;
} }
slen = PyString_GET_SIZE(item); slen = PyString_GET_SIZE(item);
while (reslen + slen + seplen >= sz) { while (reslen + slen + seplen >= sz) {
if (_PyString_Resize(&res, sz*2)) { if (_PyString_Resize(&res, sz*2)) {
Py_DECREF(item); Py_DECREF(item);
Py_DECREF(seq);
goto finally; goto finally;
} }
sz *= 2; sz *= 2;
@ -844,7 +805,6 @@ string_join(PyStringObject *self, PyObject *args)
p += slen; p += slen;
reslen += slen; reslen += slen;
} }
}
if (_PyString_Resize(&res, reslen)) if (_PyString_Resize(&res, reslen))
goto finally; goto finally;
return res; return res;