bytestring.c: Cache empty and singleton strings.
[catacomb-python] / bytestring.c
index 4abb260..124ae9a 100644 (file)
 
 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,17 +78,17 @@ 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));
 }
 
-static PyObject *meth_ctstreq(PyObject *me, PyObject *args)
+static PyObject *meth_ctstreq(PyObject *me, PyObject *arg)
 {
   char *p, *q;
   Py_ssize_t psz, qsz;
-  if (!PyArg_ParseTuple(args, "s#s#:ctstreq", &p, &psz, &q, &qsz))
+  if (!PyArg_ParseTuple(arg, "s#s#:ctstreq", &p, &psz, &q, &qsz))
     goto end;
   if (psz == qsz && ct_memeq(p, q, psz)) RETURN_TRUE;
   else RETURN_FALSE;
@@ -73,6 +96,17 @@ end:
   return (0);
 }
 
+static PyObject *meth__ByteString_zero(PyObject *me, PyObject *arg)
+{
+  size_t sz;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "OO&:zero", &me, convszt, &sz)) goto end;
+  rc = bytestring_pywrap(0, sz);
+  memset(PyString_AS_STRING(rc), 0, sz);
+end:
+  return (rc);
+}
+
 static PyObject *bytestring_pyrichcompare(PyObject *me,
                                          PyObject *you, int op)
 {
@@ -200,7 +234,7 @@ static PyTypeObject bytestring_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-"Byte string class.",
+"ByteString(STR): byte string class.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -228,6 +262,7 @@ static PyTypeObject bytestring_pytype_skel = {
 static PyMethodDef methods[] = {
 #define METHNAME(func) meth_##func
   METH  (ctstreq,              "ctstreq(S, T) -> BOOL")
+  METH (_ByteString_zero,      "zero(N) -> 0000...00")
 #undef METHNAME
   { 0 }
 };