X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/blobdiff_plain/06cd26e87f5b839d40f0e7b57e38aea6c231b385..9e947555194b0e435f39e6882e36e5b3639e3203:/bytestring.c diff --git a/bytestring.c b/bytestring.c index 0c68d43..82d117f 100644 --- a/bytestring.c +++ b/bytestring.c @@ -32,10 +32,12 @@ PyTypeObject *bytestring_pytype; -static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n) +static PyObject *empty, *bytev[256]; + +static PyObject *allocate(PyTypeObject *ty, size_t n) { - PyStringObject *x = (PyStringObject *)ty->tp_alloc(ty, n); - if (p) memcpy(x->ob_sval, p, n); + PyStringObject *x; + x = (PyStringObject *)ty->tp_alloc(ty, n); x->ob_sval[n] = 0; #if defined(CACHE_HASH) || PY_VERSION_HEX >= 0x02030000 x->ob_shash = -1; @@ -44,6 +46,27 @@ static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n) return ((PyObject *)x); } +static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n) +{ + PyObject *x; + int ch; + + if (p && ty == bytestring_pytype) { + if (!n) { + if (!empty) empty = allocate(ty, 0); + Py_INCREF(empty); return (empty); + } else if (n == 1 && (ch = *(unsigned char *)p) < sizeof(bytev)) { + if (!bytev[ch]) + { bytev[ch] = allocate(ty, 1); *PyString_AS_STRING(bytev[ch]) = ch; } + Py_INCREF(bytev[ch]); return (bytev[ch]); + } + } + + x = allocate(ty, n); + if (p) memcpy(PyString_AS_STRING(x), p, n); + return (x); +} + PyObject *bytestring_pywrap(const void *p, size_t n) { return (dowrap(bytestring_pytype, p, n)); } @@ -55,8 +78,8 @@ static PyObject *bytestring_pynew(PyTypeObject *ty, { const char *p; Py_ssize_t n; - static char *kwlist[] = { "data", 0 }; - if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n)) + static const char *const kwlist[] = { "data", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &n)) return (0); return (dowrap(ty, p, n)); } @@ -118,6 +141,91 @@ static PyObject *bytestring_pyrichcompare(PyObject *me, else RETURN_FALSE; } +static PyObject *bytestring_pyconcat(PyObject *x, PyObject *y) +{ + const void *xv; Py_ssize_t xsz; + const void *yv; Py_ssize_t ysz; + PyObject *z = 0; char *zp; size_t zsz; + + if (PyObject_AsReadBuffer(x, &xv, &xsz) || + PyObject_AsReadBuffer(y, &yv, &ysz)) + goto end; + zsz = (size_t)xsz + (size_t)ysz; + if (xsz < 0 || ysz < 0 || zsz < xsz) VALERR("too long"); + z = bytestring_pywrap(0, zsz); zp = PyString_AS_STRING(z); + memcpy(zp, xv, xsz); memcpy(zp + xsz, yv, ysz); +end: + return (z); +} + +static PyObject *bytestring_pyrepeat(PyObject *me, Py_ssize_t n) +{ + const unsigned char *xp; size_t xsz; + PyObject *z = 0; char *zp; size_t zsz; + + xp = (const unsigned char *)PyString_AS_STRING(me); + xsz = PyString_GET_SIZE(me); + if (n < 0 || (n && xsz >= (size_t)-1/n)) VALERR("too long"); + zsz = n*xsz; z = bytestring_pywrap(0, zsz); zp = PyString_AS_STRING(z); + if (xsz == 1) memset(zp, *xp, zsz); + else while (zsz) { memcpy(zp, xp, xsz); zp += xsz; zsz -= xsz; } +end: + return (z); +} + +static PyObject *bytestring_pyitem(PyObject *me, Py_ssize_t i) +{ + PyObject *rc = 0; + + if (i < 0 || i >= PyString_GET_SIZE(me)) IXERR("out of range"); + rc = bytestring_pywrap(PyString_AS_STRING(me) + i, 1); +end: + return (rc); +} + +static PyObject *bytestring_pyslice(PyObject *me, Py_ssize_t i, Py_ssize_t j) +{ + PyObject *rc = 0; + size_t n = PyString_GET_SIZE(me); + + if (i < 0) i = 0; + if (j < 0) j = 0; + else if (j > n) j = n; + if (j < i) i = j = 0; + if (i == 0 && j == n && me->ob_type == bytestring_pytype) + { Py_INCREF(me); rc = me; goto end; } + rc = bytestring_pywrap(PyString_AS_STRING(me) + i, j - i); +end: + return (rc); +} + +static PyObject *bytestring_pysubscript(PyObject *me, PyObject *ix) +{ + Py_ssize_t i, j, k, n; + const unsigned char *p; + unsigned char *q; + PyObject *rc = 0; + + if (PyIndex_Check(ix)) { + i = PyNumber_AsSsize_t(ix, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) return (0); + if (i < 0) i += PyString_GET_SIZE(me); + rc = bytestring_pyitem(me, i); + } else if (PySlice_Check(ix)) { + if (PySlice_GetIndicesEx((PySliceObject *)ix, PyString_GET_SIZE(me), + &i, &j, &k, &n)) + return (0); + if (k == 1) return bytestring_pyslice(me, i, j); + rc = bytestring_pywrap(0, n); + p = (unsigned char *)PyString_AS_STRING(me) + i; + q = (unsigned char *)PyString_AS_STRING(rc); + while (n--) { *q++ = *p; p += k; } + } else + TYERR("wanted integer or slice"); +end: + return (rc); +} + #define BINOP(name, op) \ static PyObject *bytestring_py##name(PyObject *x, PyObject *y) { \ const void *xv, *yv; \ @@ -183,6 +291,25 @@ static PyNumberMethods bytestring_pynumber = { 0, /* @nb_hex@ */ }; +static PySequenceMethods bytestring_pysequence = { + 0, /* @sq_length@ */ + bytestring_pyconcat, /* @sq_concat@ */ + bytestring_pyrepeat, /* @sq_repeat@ */ + bytestring_pyitem, /* @sq_item@ */ + bytestring_pyslice, /* @sq_slice@ */ + 0, /* @sq_ass_item@ */ + 0, /* @sq_ass_slice@ */ + 0, /* @sq_contains@ */ + 0, /* @sq_inplace_concat@ */ + 0, /* @sq_inplace_repeat@ */ +}; + +static PyMappingMethods bytestring_pymapping = { + 0, /* @mp_length@ */ + bytestring_pysubscript, /* @mp_subscript@ */ + 0, /* @mp_ass_subscript@ */ +}; + static PyBufferProcs bytestring_pybuffer; static PyTypeObject bytestring_pytype_skel = { @@ -198,8 +325,8 @@ static PyTypeObject bytestring_pytype_skel = { 0, /* @tp_compare@ */ 0, /* @tp_repr@ */ &bytestring_pynumber, /* @tp_as_number@ */ - 0, /* @tp_as_sequence@ */ - 0, /* @tp_as_mapping@ */ + &bytestring_pysequence, /* @tp_as_sequence@ */ + &bytestring_pymapping, /* @tp_as_mapping@ */ 0, /* @tp_hash@ */ 0, /* @tp_call@ */ 0, /* @tp_str@ */