summaryrefslogtreecommitdiff
path: root/Objects/bytesobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/bytesobject.c')
-rw-r--r--Objects/bytesobject.c113
1 files changed, 83 insertions, 30 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index b93b9ef10d..911a93b9ca 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -71,15 +71,11 @@ static PyBytesObject *nullstring;
PyBytes_FromStringAndSize()) or the length of the string in the `str'
parameter (for PyBytes_FromString()).
*/
-PyObject *
-PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
+static PyObject *
+_PyBytes_FromSize(Py_ssize_t size, int use_calloc)
{
PyBytesObject *op;
- if (size < 0) {
- PyErr_SetString(PyExc_SystemError,
- "Negative size passed to PyBytes_FromStringAndSize");
- return NULL;
- }
+ assert(size >= 0);
if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
null_strings++;
@@ -87,15 +83,6 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
Py_INCREF(op);
return (PyObject *)op;
}
- if (size == 1 && str != NULL &&
- (op = characters[*str & UCHAR_MAX]) != NULL)
- {
-#ifdef COUNT_ALLOCS
- one_strings++;
-#endif
- Py_INCREF(op);
- return (PyObject *)op;
- }
if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
PyErr_SetString(PyExc_OverflowError,
@@ -104,19 +91,52 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
}
/* Inline PyObject_NewVar */
- op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
+ if (use_calloc)
+ op = (PyBytesObject *)PyObject_Calloc(1, PyBytesObject_SIZE + size);
+ else
+ op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + size);
if (op == NULL)
return PyErr_NoMemory();
(void)PyObject_INIT_VAR(op, &PyBytes_Type, size);
op->ob_shash = -1;
- if (str != NULL)
- Py_MEMCPY(op->ob_sval, str, size);
- op->ob_sval[size] = '\0';
- /* share short strings */
+ if (!use_calloc)
+ op->ob_sval[size] = '\0';
+ /* empty byte string singleton */
if (size == 0) {
nullstring = op;
Py_INCREF(op);
- } else if (size == 1 && str != NULL) {
+ }
+ return (PyObject *) op;
+}
+
+PyObject *
+PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
+{
+ PyBytesObject *op;
+ if (size < 0) {
+ PyErr_SetString(PyExc_SystemError,
+ "Negative size passed to PyBytes_FromStringAndSize");
+ return NULL;
+ }
+ if (size == 1 && str != NULL &&
+ (op = characters[*str & UCHAR_MAX]) != NULL)
+ {
+#ifdef COUNT_ALLOCS
+ one_strings++;
+#endif
+ Py_INCREF(op);
+ return (PyObject *)op;
+ }
+
+ op = (PyBytesObject *)_PyBytes_FromSize(size, 0);
+ if (op == NULL)
+ return NULL;
+ if (str == NULL)
+ return (PyObject *) op;
+
+ Py_MEMCPY(op->ob_sval, str, size);
+ /* share short strings */
+ if (size == 1) {
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
@@ -2482,7 +2502,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
"argument");
return NULL;
}
- return PyBytes_FromString("");
+ return PyBytes_FromStringAndSize(NULL, 0);
}
if (PyUnicode_Check(x)) {
@@ -2532,11 +2552,9 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
else {
- new = PyBytes_FromStringAndSize(NULL, size);
+ new = _PyBytes_FromSize(size, 1);
if (new == NULL)
return NULL;
- if (size > 0)
- memset(((PyBytesObject*)new)->ob_sval, 0, size);
return new;
}
@@ -2781,7 +2799,6 @@ PyTypeObject PyBytes_Type = {
void
PyBytes_Concat(PyObject **pv, PyObject *w)
{
- PyObject *v;
assert(pv != NULL);
if (*pv == NULL)
return;
@@ -2789,9 +2806,45 @@ PyBytes_Concat(PyObject **pv, PyObject *w)
Py_CLEAR(*pv);
return;
}
- v = bytes_concat(*pv, w);
- Py_DECREF(*pv);
- *pv = v;
+
+ if (Py_REFCNT(*pv) == 1 && PyBytes_CheckExact(*pv)) {
+ /* Only one reference, so we can resize in place */
+ Py_ssize_t oldsize;
+ Py_buffer wb;
+
+ wb.len = -1;
+ if (_getbuffer(w, &wb) < 0) {
+ PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
+ Py_TYPE(w)->tp_name, Py_TYPE(*pv)->tp_name);
+ Py_CLEAR(*pv);
+ return;
+ }
+
+ oldsize = PyBytes_GET_SIZE(*pv);
+ if (oldsize > PY_SSIZE_T_MAX - wb.len) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ if (_PyBytes_Resize(pv, oldsize + wb.len) < 0)
+ goto error;
+
+ memcpy(PyBytes_AS_STRING(*pv) + oldsize, wb.buf, wb.len);
+ PyBuffer_Release(&wb);
+ return;
+
+ error:
+ PyBuffer_Release(&wb);
+ Py_CLEAR(*pv);
+ return;
+ }
+
+ else {
+ /* Multiple references, need to create new object */
+ PyObject *v;
+ v = bytes_concat(*pv, w);
+ Py_DECREF(*pv);
+ *pv = v;
+ }
}
void