Implement TemplateIO in C. This gives a nice spee ... (quixote/src/_c_htmltext.c)
Neil Schemenauer <nascheme-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Wed, 08 Jan 2003 19:16:28 -0500
| Newsgroups | gmane.comp.web.quixote.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /home/cvs/quixote/src
In directory hewson:/tmp/cvs-serv20578/src
Modified Files:
_c_htmltext.c
Log Message:
Implement TemplateIO in C. This gives a nice speedup according to a
silly template intensive benchmark. Real applications probably see a
few percent speed increase.
Use larger integer types in some places to prevent overflows.
Index: _c_htmltext.c
===================================================================
RCS file: /home/cvs/quixote/src/_c_htmltext.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- _c_htmltext.c 8 Jan 2003 20:38:16 -0000 1.2
+++ _c_htmltext.c 9 Jan 2003 00:16:26 -0000 1.3
@@ -23,6 +23,18 @@
#define QuoteWrapper_Check(v) ((v)->ob_type == &QuoteWrapper_Type)
+typedef struct {
+ PyObject_HEAD
+ int html;
+ char *buf;
+ size_t size;
+ size_t pos;
+} TemplateIO_Object;
+
+static PyTypeObject TemplateIO_Type;
+
+#define TemplateIO_Check(v) ((v)->ob_type == &TemplateIO_Type)
+
static PyObject *
type_error(const char *msg)
@@ -36,7 +48,7 @@
{
PyObject *new_s;
char *ss, *new_ss;
- int i, j, extra_space, size, new_size;
+ size_t i, j, extra_space, size, new_size;
if (!PyString_Check(s))
return type_error("str object required");
ss = PyString_AS_STRING(s);
@@ -290,7 +302,7 @@
if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) &&
!PyString_Check(args)) {
char *fmt = PyString_AS_STRING(htmltext_STR(self));
- int i, n = PyString_GET_SIZE(htmltext_STR(self));
+ size_t i, n = PyString_GET_SIZE(htmltext_STR(self));
char last = 0;
/* second check necessary since '%s' % {} => '{}' */
for (i=0; i < n; i++) {
@@ -319,7 +331,7 @@
}
}
else if (PyTuple_Check(args)) {
- int i, n = PyTuple_GET_SIZE(args);
+ long i, n = PyTuple_GET_SIZE(args);
wargs = PyTuple_New(n);
for (i=0; i < n; i++) {
PyObject *wvalue = wrap_arg(PyTuple_GET_ITEM(args, i));
@@ -387,7 +399,7 @@
static PyObject *
htmltext_join(PyObject *self, PyObject *args)
{
- int i;
+ long i;
PyObject *qargs, *rv;
if (!PySequence_Check(args)) {
return type_error("argument must be a sequence");
@@ -515,6 +527,145 @@
"capitalize", ""));
}
+static PyObject *
+template_io_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ TemplateIO_Object *self;
+ int html = 0;
+ static char *kwlist[] = {"html", 0};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:TemplateIO",
+ kwlist, &html))
+ return NULL;
+ self = (TemplateIO_Object *)type->tp_alloc(type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->html = html != 0;
+ self->buf = NULL;
+ self->size = 0;
+ self->pos = 0;
+ return (PyObject *)self;
+}
+
+static void
+template_io_dealloc(TemplateIO_Object *self)
+{
+ if (self->size > 0)
+ PyMem_Free(self->buf);
+ self->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *
+template_io_str(TemplateIO_Object *self)
+{
+ return PyString_FromStringAndSize(self->buf, self->pos);
+}
+
+static PyObject *
+template_io_getvalue(TemplateIO_Object *self)
+{
+ if (self->html) {
+ return htmltext_from_string(template_io_str(self));
+ }
+ else {
+ return template_io_str(self);
+ }
+}
+
+static PyObject *
+template_io_repr(TemplateIO_Object *self)
+{
+ PyObject *s, *sr, *rv;
+ s = template_io_str(self);
+ if (s == NULL)
+ return NULL;
+ sr = PyObject_Repr(s);
+ Py_DECREF(s);
+ if (sr == NULL)
+ return NULL;
+ rv = PyString_FromFormat("<htmltext %s>", PyString_AsString(sr));
+ Py_DECREF(sr);
+ return rv;
+}
+
+
+static PyObject *
+template_io_do_concat(TemplateIO_Object *self, char *s, size_t size)
+{
+ /* note this adds a reference to self */
+ size_t i;
+ if (self->pos + size > self->size) {
+ size_t new_size;
+ char *new_buf;
+ if (self->size > size)
+ new_size = self->size * 2;
+ else
+ new_size = size * 2;
+ new_buf = PyMem_Realloc(self->buf, new_size);
+ if (new_buf == NULL)
+ return NULL;
+ self->buf = new_buf;
+ self->size = new_size;
+ }
+ for (i=0; i < size; i++) {
+ self->buf[self->pos] = s[i];
+ self->pos++;
+ }
+ assert (self->pos < self->size);
+ Py_INCREF(self);
+ return (PyObject *)self;
+}
+
+
+static PyObject *
+template_io_iconcat(TemplateIO_Object *self, PyObject *other)
+{
+ PyObject *rv;
+ PyObject *s = NULL;
+ assert (TemplateIO_Check(self));
+ if (other == Py_None) {
+ Py_INCREF(self);
+ return (PyObject *)self;
+ }
+ else if (TemplateIO_Check(other)) {
+ TemplateIO_Object *o = (TemplateIO_Object *)other;
+ if (self->html && !o->html) {
+ PyObject *ss = PyString_FromStringAndSize(o->buf,
+ o->pos);
+ if (ss == NULL)
+ return NULL;
+ s = escape_string(ss);
+ Py_DECREF(ss);
+ goto concat_str;
+ }
+ rv = template_io_do_concat(self, o->buf, o->pos);
+ }
+ else if (htmltextObject_Check(other)) {
+ PyStringObject *s = ((htmltextObject *)other)->s;
+ rv = template_io_do_concat(self,
+ PyString_AS_STRING(s),
+ PyString_GET_SIZE(s));
+ }
+ else {
+ if (self->html) {
+ PyObject *ss = PyObject_Str(other);
+ if (ss == NULL)
+ return NULL;
+ s = escape_string(ss);
+ Py_DECREF(ss);
+ } else {
+ s = PyObject_Str(other);
+ }
+concat_str:
+ if (s == NULL)
+ return NULL;
+ rv = template_io_do_concat(self, PyString_AS_STRING(s),
+ PyString_GET_SIZE(s));
+ Py_XDECREF(s);
+ }
+ return rv;
+}
+
static PyMethodDef htmltext_methods[] = {
{"join", (PyCFunction)htmltext_join, METH_O, ""},
{"startswith", (PyCFunction)htmltext_startswith, METH_O, ""},
@@ -656,6 +807,69 @@
0, /*tp_call*/
(unaryfunc)quote_wrapper_str, /*tp_str*/
};
+
+static PySequenceMethods template_io_as_sequence = {
+ 0, /*sq_length*/
+ 0, /*sq_concat*/
+ 0, /*sq_repeat*/
+ 0, /*sq_item*/
+ 0, /*sq_slice*/
+ 0, /*sq_ass_item*/
+ 0, /*sq_ass_slice*/
+ 0, /*sq_contains*/
+ (binaryfunc)template_io_iconcat,/*sq_inplace_concat*/
+};
+
+static PyMethodDef template_io_methods[] = {
+ {"getvalue", (PyCFunction)template_io_getvalue, METH_NOARGS, ""},
+ {NULL, NULL}
+};
+
+static PyTypeObject TemplateIO_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /*ob_size*/
+ "TemplateIO", /*tp_name*/
+ sizeof(TemplateIO_Object),/*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)template_io_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (unaryfunc)template_io_repr,/*tp_repr*/
+ 0, /*tp_as_number*/
+ &template_io_as_sequence,/*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ (unaryfunc)template_io_str,/*tp_str*/
+ PyObject_GenericGetAttr,/*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ template_io_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ 0, /*tp_init*/
+ PyType_GenericAlloc, /*tp_alloc*/
+ template_io_new, /*tp_new*/
+ _PyObject_Del, /*tp_free*/
+ 0, /*tp_is_gc*/
+};
+
/* --------------------------------------------------------------------- */
static PyObject *
@@ -704,6 +918,8 @@
/* Initialize the type of the new type object here; doing it here
* is required for portability to Windows without requiring C++. */
htmltext_Type.ob_type = &PyType_Type;
+ QuoteWrapper_Type.ob_type = &PyType_Type;
+ TemplateIO_Type.ob_type = &PyType_Type;
/* Create the module and add the functions */
m = Py_InitModule4("_c_htmltext", htmltext_module_methods, module_doc,
@@ -711,5 +927,7 @@
Py_INCREF((PyObject *)&htmltext_Type);
Py_INCREF((PyObject *)&QuoteWrapper_Type);
+ Py_INCREF((PyObject *)&TemplateIO_Type);
PyModule_AddObject(m, "htmltext", (PyObject *)&htmltext_Type);
+ PyModule_AddObject(m, "TemplateIO", (PyObject *)&TemplateIO_Type);
}