diff options
Diffstat (limited to 'Objects/bytearrayobject.c')
-rw-r--r-- | Objects/bytearrayobject.c | 317 |
1 files changed, 205 insertions, 112 deletions
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 4202ff2..2571858 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -139,7 +139,7 @@ PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size) } else { alloc = size + 1; - new->ob_bytes = PyMem_Malloc(alloc); + new->ob_bytes = PyObject_Malloc(alloc); if (new->ob_bytes == NULL) { Py_DECREF(new); return PyErr_NoMemory(); @@ -209,7 +209,7 @@ PyByteArray_Resize(PyObject *self, Py_ssize_t size) alloc = size + 1; } - sval = PyMem_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc); + sval = PyObject_Realloc(((PyByteArrayObject *)self)->ob_bytes, alloc); if (sval == NULL) { PyErr_NoMemory(); return -1; @@ -850,87 +850,82 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) static PyObject * bytearray_repr(PyByteArrayObject *self) { - static const char *hexdigits = "0123456789abcdef"; const char *quote_prefix = "bytearray(b"; const char *quote_postfix = ")"; Py_ssize_t length = Py_SIZE(self); - /* 14 == strlen(quote_prefix) + 2 + strlen(quote_postfix) */ + /* 15 == strlen(quote_prefix) + 2 + strlen(quote_postfix) + 1 */ size_t newsize; PyObject *v; - if (length > (PY_SSIZE_T_MAX - 14) / 4) { + register Py_ssize_t i; + register char c; + register char *p; + int quote; + char *test, *start; + char *buffer; + + if (length > (PY_SSIZE_T_MAX - 15) / 4) { PyErr_SetString(PyExc_OverflowError, "bytearray object is too large to make repr"); return NULL; } - newsize = 14 + 4 * length; - v = PyUnicode_FromUnicode(NULL, newsize); - if (v == NULL) { + + newsize = 15 + length * 4; + buffer = PyObject_Malloc(newsize); + if (buffer == NULL) { + PyErr_NoMemory(); return NULL; } - else { - register Py_ssize_t i; - register Py_UNICODE c; - register Py_UNICODE *p; - int quote; - - /* Figure out which quote to use; single is preferred */ - quote = '\''; - { - char *test, *start; - start = PyByteArray_AS_STRING(self); - for (test = start; test < start+length; ++test) { - if (*test == '"') { - quote = '\''; /* back to single */ - goto decided; - } - else if (*test == '\'') - quote = '"'; - } - decided: - ; - } - p = PyUnicode_AS_UNICODE(v); - while (*quote_prefix) - *p++ = *quote_prefix++; - *p++ = quote; - - for (i = 0; i < length; i++) { - /* There's at least enough room for a hex escape - and a closing quote. */ - assert(newsize - (p - PyUnicode_AS_UNICODE(v)) >= 5); - c = self->ob_bytes[i]; - if (c == '\'' || c == '\\') - *p++ = '\\', *p++ = c; - else if (c == '\t') - *p++ = '\\', *p++ = 't'; - else if (c == '\n') - *p++ = '\\', *p++ = 'n'; - else if (c == '\r') - *p++ = '\\', *p++ = 'r'; - else if (c == 0) - *p++ = '\\', *p++ = 'x', *p++ = '0', *p++ = '0'; - else if (c < ' ' || c >= 0x7f) { - *p++ = '\\'; - *p++ = 'x'; - *p++ = hexdigits[(c & 0xf0) >> 4]; - *p++ = hexdigits[c & 0xf]; - } - else - *p++ = c; + /* Figure out which quote to use; single is preferred */ + quote = '\''; + start = PyByteArray_AS_STRING(self); + for (test = start; test < start+length; ++test) { + if (*test == '"') { + quote = '\''; /* back to single */ + break; } - assert(newsize - (p - PyUnicode_AS_UNICODE(v)) >= 1); - *p++ = quote; - while (*quote_postfix) { - *p++ = *quote_postfix++; + else if (*test == '\'') + quote = '"'; + } + + p = buffer; + while (*quote_prefix) + *p++ = *quote_prefix++; + *p++ = quote; + + for (i = 0; i < length; i++) { + /* There's at least enough room for a hex escape + and a closing quote. */ + assert(newsize - (p - buffer) >= 5); + c = self->ob_bytes[i]; + if (c == '\'' || c == '\\') + *p++ = '\\', *p++ = c; + else if (c == '\t') + *p++ = '\\', *p++ = 't'; + else if (c == '\n') + *p++ = '\\', *p++ = 'n'; + else if (c == '\r') + *p++ = '\\', *p++ = 'r'; + else if (c == 0) + *p++ = '\\', *p++ = 'x', *p++ = '0', *p++ = '0'; + else if (c < ' ' || c >= 0x7f) { + *p++ = '\\'; + *p++ = 'x'; + *p++ = Py_hexdigits[(c & 0xf0) >> 4]; + *p++ = Py_hexdigits[c & 0xf]; } - *p = '\0'; - if (PyUnicode_Resize(&v, (p - PyUnicode_AS_UNICODE(v)))) { - Py_DECREF(v); - return NULL; - } - return v; + else + *p++ = c; } + assert(newsize - (p - buffer) >= 1); + *p++ = quote; + while (*quote_postfix) { + *p++ = *quote_postfix++; + } + + v = PyUnicode_DecodeASCII(buffer, p - buffer, NULL); + PyObject_Free(buffer); + return v; } static PyObject * @@ -964,23 +959,20 @@ bytearray_richcompare(PyObject *self, PyObject *other, int op) return NULL; } - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + Py_RETURN_NOTIMPLEMENTED; } self_size = _getbuffer(self, &self_bytes); if (self_size < 0) { PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + Py_RETURN_NOTIMPLEMENTED; } other_size = _getbuffer(other, &other_bytes); if (other_size < 0) { PyErr_Clear(); PyBuffer_Release(&self_bytes); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + Py_RETURN_NOTIMPLEMENTED; } if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { @@ -1028,7 +1020,7 @@ bytearray_dealloc(PyByteArrayObject *self) PyErr_Print(); } if (self->ob_bytes != 0) { - PyMem_Free(self->ob_bytes); + PyObject_Free(self->ob_bytes); } Py_TYPE(self)->tp_free((PyObject *)self); } @@ -1037,6 +1029,8 @@ bytearray_dealloc(PyByteArrayObject *self) /* -------------------------------------------------------------------- */ /* Methods */ +#define FASTSEARCH fastsearch +#define STRINGLIB(F) stringlib_##F #define STRINGLIB_CHAR char #define STRINGLIB_LEN PyByteArray_GET_SIZE #define STRINGLIB_STR PyByteArray_AS_STRING @@ -1077,24 +1071,41 @@ Py_LOCAL_INLINE(Py_ssize_t) bytearray_find_internal(PyByteArrayObject *self, PyObject *args, int dir) { PyObject *subobj; + char byte; Py_buffer subbuf; + const char *sub; + Py_ssize_t sub_len; Py_ssize_t start=0, end=PY_SSIZE_T_MAX; Py_ssize_t res; - if (!stringlib_parse_args_finds("find/rfind/index/rindex", - args, &subobj, &start, &end)) - return -2; - if (_getbuffer(subobj, &subbuf) < 0) + if (!stringlib_parse_args_finds_byte("find/rfind/index/rindex", + args, &subobj, &byte, &start, &end)) return -2; + + if (subobj) { + if (_getbuffer(subobj, &subbuf) < 0) + return -2; + + sub = subbuf.buf; + sub_len = subbuf.len; + } + else { + sub = &byte; + sub_len = 1; + } + if (dir > 0) res = stringlib_find_slice( PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - subbuf.buf, subbuf.len, start, end); + sub, sub_len, start, end); else res = stringlib_rfind_slice( PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - subbuf.buf, subbuf.len, start, end); - PyBuffer_Release(&subbuf); + sub, sub_len, start, end); + + if (subobj) + PyBuffer_Release(&subbuf); + return res; } @@ -1127,26 +1138,66 @@ static PyObject * bytearray_count(PyByteArrayObject *self, PyObject *args) { PyObject *sub_obj; - const char *str = PyByteArray_AS_STRING(self); + const char *str = PyByteArray_AS_STRING(self), *sub; + Py_ssize_t sub_len; + char byte; Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; + Py_buffer vsub; PyObject *count_obj; - if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end)) + if (!stringlib_parse_args_finds_byte("count", args, &sub_obj, &byte, + &start, &end)) return NULL; - if (_getbuffer(sub_obj, &vsub) < 0) - return NULL; + if (sub_obj) { + if (_getbuffer(sub_obj, &vsub) < 0) + return NULL; + + sub = vsub.buf; + sub_len = vsub.len; + } + else { + sub = &byte; + sub_len = 1; + } ADJUST_INDICES(start, end, PyByteArray_GET_SIZE(self)); count_obj = PyLong_FromSsize_t( - stringlib_count(str + start, end - start, vsub.buf, vsub.len, PY_SSIZE_T_MAX) + stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX) ); - PyBuffer_Release(&vsub); + + if (sub_obj) + PyBuffer_Release(&vsub); + return count_obj; } +PyDoc_STRVAR(clear__doc__, +"B.clear() -> None\n\ +\n\ +Remove all items from B."); + +static PyObject * +bytearray_clear(PyByteArrayObject *self) +{ + if (PyByteArray_Resize((PyObject *)self, 0) < 0) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(copy__doc__, +"B.copy() -> bytearray\n\ +\n\ +Return a copy of B."); + +static PyObject * +bytearray_copy(PyByteArrayObject *self) +{ + return PyByteArray_FromStringAndSize(PyByteArray_AS_STRING((PyObject *)self), + PyByteArray_GET_SIZE(self)); +} PyDoc_STRVAR(index__doc__, "B.index(sub[, start[, end]]) -> int\n\ @@ -2444,7 +2495,7 @@ If the argument is omitted, strip trailing ASCII whitespace."); static PyObject * bytearray_rstrip(PyByteArrayObject *self, PyObject *args) { - Py_ssize_t left, right, mysize, argsize; + Py_ssize_t right, mysize, argsize; void *myptr, *argptr; PyObject *arg = Py_None; Py_buffer varg; @@ -2462,11 +2513,10 @@ bytearray_rstrip(PyByteArrayObject *self, PyObject *args) } myptr = self->ob_bytes; mysize = Py_SIZE(self); - left = 0; right = rstrip_helper(myptr, mysize, argptr, argsize); if (arg != Py_None) PyBuffer_Release(&varg); - return PyByteArray_FromStringAndSize(self->ob_bytes + left, right - left); + return PyByteArray_FromStringAndSize(self->ob_bytes, right); } PyDoc_STRVAR(decode_doc, @@ -2588,11 +2638,13 @@ Line breaks are not included in the resulting list unless keepends\n\ is given and true."); static PyObject* -bytearray_splitlines(PyObject *self, PyObject *args) +bytearray_splitlines(PyObject *self, PyObject *args, PyObject *kwds) { + static char *kwlist[] = {"keepends", 0}; int keepends = 0; - if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:splitlines", + kwlist, &keepends)) return NULL; return stringlib_splitlines( @@ -2609,7 +2661,7 @@ Spaces between two numbers are accepted.\n\ Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')."); static int -hex_digit_to_int(Py_UNICODE c) +hex_digit_to_int(Py_UCS4 c) { if (c >= 128) return -1; @@ -2629,15 +2681,20 @@ bytearray_fromhex(PyObject *cls, PyObject *args) { PyObject *newbytes, *hexobj; char *buf; - Py_UNICODE *hex; Py_ssize_t hexlen, byteslen, i, j; int top, bot; + void *data; + unsigned int kind; if (!PyArg_ParseTuple(args, "U:fromhex", &hexobj)) return NULL; assert(PyUnicode_Check(hexobj)); - hexlen = PyUnicode_GET_SIZE(hexobj); - hex = PyUnicode_AS_UNICODE(hexobj); + if (PyUnicode_READY(hexobj)) + return NULL; + kind = PyUnicode_KIND(hexobj); + data = PyUnicode_DATA(hexobj); + hexlen = PyUnicode_GET_LENGTH(hexobj); + byteslen = hexlen/2; /* This overestimates if there are spaces */ newbytes = PyByteArray_FromStringAndSize(NULL, byteslen); if (!newbytes) @@ -2645,12 +2702,12 @@ bytearray_fromhex(PyObject *cls, PyObject *args) buf = PyByteArray_AS_STRING(newbytes); for (i = j = 0; i < hexlen; i += 2) { /* skip over spaces in the input */ - while (hex[i] == ' ') + while (PyUnicode_READ(kind, data, i) == ' ') i++; if (i >= hexlen) break; - top = hex_digit_to_int(hex[i]); - bot = hex_digit_to_int(hex[i+1]); + top = hex_digit_to_int(PyUnicode_READ(kind, data, i)); + bot = hex_digit_to_int(PyUnicode_READ(kind, data, i+1)); if (top == -1 || bot == -1) { PyErr_Format(PyExc_ValueError, "non-hexadecimal number found in " @@ -2668,26 +2725,59 @@ bytearray_fromhex(PyObject *cls, PyObject *args) return NULL; } -PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyObject * -bytearray_reduce(PyByteArrayObject *self) +_common_reduce(PyByteArrayObject *self, int proto) { - PyObject *latin1, *dict; - if (self->ob_bytes) - latin1 = PyUnicode_DecodeLatin1(self->ob_bytes, - Py_SIZE(self), NULL); - else - latin1 = PyUnicode_FromString(""); + PyObject *dict; + _Py_IDENTIFIER(__dict__); - dict = PyObject_GetAttrString((PyObject *)self, "__dict__"); + dict = _PyObject_GetAttrId((PyObject *)self, &PyId___dict__); if (dict == NULL) { PyErr_Clear(); dict = Py_None; Py_INCREF(dict); } - return Py_BuildValue("(O(Ns)N)", Py_TYPE(self), latin1, "latin-1", dict); + if (proto < 3) { + /* use str based reduction for backwards compatibility with Python 2.x */ + PyObject *latin1; + if (self->ob_bytes) + latin1 = PyUnicode_DecodeLatin1(self->ob_bytes, Py_SIZE(self), NULL); + else + latin1 = PyUnicode_FromString(""); + return Py_BuildValue("(O(Ns)N)", Py_TYPE(self), latin1, "latin-1", dict); + } + else { + /* use more efficient byte based reduction */ + if (self->ob_bytes) { + return Py_BuildValue("(O(y#)N)", Py_TYPE(self), self->ob_bytes, Py_SIZE(self), dict); + } + else { + return Py_BuildValue("(O()N)", Py_TYPE(self), dict); + } + } +} + +PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + +static PyObject * +bytearray_reduce(PyByteArrayObject *self) +{ + return _common_reduce(self, 2); +} + +PyDoc_STRVAR(reduce_ex_doc, "Return state information for pickling."); + +static PyObject * +bytearray_reduce_ex(PyByteArrayObject *self, PyObject *args) +{ + int proto = 0; + + if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) + return NULL; + + return _common_reduce(self, proto); } PyDoc_STRVAR(sizeof_doc, @@ -2731,11 +2821,14 @@ static PyMethodDef bytearray_methods[] = { {"__alloc__", (PyCFunction)bytearray_alloc, METH_NOARGS, alloc_doc}, {"__reduce__", (PyCFunction)bytearray_reduce, METH_NOARGS, reduce_doc}, + {"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_VARARGS, reduce_ex_doc}, {"__sizeof__", (PyCFunction)bytearray_sizeof, METH_NOARGS, sizeof_doc}, {"append", (PyCFunction)bytearray_append, METH_O, append__doc__}, {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, _Py_capitalize__doc__}, {"center", (PyCFunction)stringlib_center, METH_VARARGS, center__doc__}, + {"clear", (PyCFunction)bytearray_clear, METH_NOARGS, clear__doc__}, + {"copy", (PyCFunction)bytearray_copy, METH_NOARGS, copy__doc__}, {"count", (PyCFunction)bytearray_count, METH_VARARGS, count__doc__}, {"decode", (PyCFunction)bytearray_decode, METH_VARARGS | METH_KEYWORDS, decode_doc}, {"endswith", (PyCFunction)bytearray_endswith, METH_VARARGS, endswith__doc__}, @@ -2779,8 +2872,8 @@ bytearray_methods[] = { {"rsplit", (PyCFunction)bytearray_rsplit, METH_VARARGS, rsplit__doc__}, {"rstrip", (PyCFunction)bytearray_rstrip, METH_VARARGS, rstrip__doc__}, {"split", (PyCFunction)bytearray_split, METH_VARARGS, split__doc__}, - {"splitlines", (PyCFunction)bytearray_splitlines, METH_VARARGS, - splitlines__doc__}, + {"splitlines", (PyCFunction)bytearray_splitlines, + METH_VARARGS | METH_KEYWORDS, splitlines__doc__}, {"startswith", (PyCFunction)bytearray_startswith, METH_VARARGS , startswith__doc__}, {"strip", (PyCFunction)bytearray_strip, METH_VARARGS, strip__doc__}, |