[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [34117] trunk/blender/source/blender/ python/intern/bpy_rna.c: py/rna optimizations, will help for faster exporting.
Campbell Barton
ideasman42 at gmail.com
Thu Jan 6 05:01:15 CET 2011
Revision: 34117
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=34117
Author: campbellbarton
Date: 2011-01-06 05:01:06 +0100 (Thu, 06 Jan 2011)
Log Message:
-----------
py/rna optimizations, will help for faster exporting.
Speedup for getting collection indices, avoid getting the collection length unless a negative index is given. This avoids a loop over the entire collection in many cases.
Speedup for getting collection slices by detecting collection[:] and internally calling collection.values(), this gives a big speedup with some collections because each slice item would loop over the list until that index was found.
Rough test with 336 objects.
- getting index of listbase collection ~ 5.0x faster
- getting index of array collection ~ 1.15x faster
- getting slices of listbase collections ~ 34.0x faster
- getting slices of array collections ~ 1.5x faster
Modified Paths:
--------------
trunk/blender/source/blender/python/intern/bpy_rna.c
Modified: trunk/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna.c 2011-01-06 03:10:41 UTC (rev 34116)
+++ trunk/blender/source/blender/python/intern/bpy_rna.c 2011-01-06 04:01:06 UTC (rev 34117)
@@ -57,6 +57,8 @@
#define USE_MATHUTILS
#define USE_STRING_COERCE
+static PyObject *pyrna_prop_collection_values(BPy_PropertyRNA *self);
+
#ifdef USE_PEDANTIC_WRITE
static short rna_disallow_writes= FALSE;
@@ -1414,21 +1416,34 @@
static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_ssize_t keynum)
{
PointerRNA newptr;
- int len= RNA_property_collection_length(&self->ptr, self->prop);
+ Py_ssize_t keynum_abs= keynum;
- if(keynum < 0) keynum += len;
+ /* notice getting the length of the collection is avoided unless negative index is used
+ * or to detect internal error with a valid index.
+ * This is done for faster lookups. */
+ if(keynum < 0) {
+ keynum_abs += RNA_property_collection_length(&self->ptr, self->prop);
- if(keynum >= 0 && keynum < len) {
- if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr)) {
- return pyrna_struct_CreatePyObject(&newptr);
+ if(keynum_abs < 0) {
+ PyErr_Format(PyExc_IndexError, "bpy_prop_collection[%d]: out of range.", keynum);
+ return NULL;
}
+ }
+
+ if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum_abs, &newptr)) {
+ return pyrna_struct_CreatePyObject(&newptr);
+ }
+ else {
+ const int len= RNA_property_collection_length(&self->ptr, self->prop);
+ if(keynum_abs >= len) {
+ PyErr_Format(PyExc_IndexError, "bpy_prop_collection[index]: index %d out of range, size %d", keynum, len);
+ }
else {
- PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection");
- return NULL;
+ PyErr_Format(PyExc_RuntimeError, "bpy_prop_collection[index]: internal error, valid index %d given in %d sized collection but value not found", keynum_abs, len);
}
+
+ return NULL;
}
- PyErr_Format(PyExc_IndexError, "bpy_prop_collection[index]: index %d out of range, size %d", keynum, len);
- return NULL;
}
static PyObject *pyrna_prop_array_subscript_int(BPy_PropertyArrayRNA *self, int keynum)
@@ -1455,27 +1470,36 @@
}
/* static PyObject *pyrna_prop_array_subscript_str(BPy_PropertyRNA *self, char *keyname) */
-static PyObject *pyrna_prop_collection_subscript_slice(PointerRNA *ptr, PropertyRNA *prop, int start, int stop)
+static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, int start, int stop, int len)
{
- PointerRNA newptr;
- PyObject *list = PyList_New(stop - start);
- int count;
+ if(start == 0 && stop == len) {
+ /* faster */
+ return pyrna_prop_collection_values(self);
+ }
+ else {
+ PointerRNA *ptr= &self->ptr;
+ PropertyRNA *prop= self->prop;
- start = MIN2(start,stop); /* values are clamped from */
+ PointerRNA newptr;
+ PyObject *list = PyList_New(stop - start);
+ int count;
- for(count = start; count < stop; count++) {
- if(RNA_property_collection_lookup_int(ptr, prop, count - start, &newptr)) {
- PyList_SET_ITEM(list, count - start, pyrna_struct_CreatePyObject(&newptr));
+ start = MIN2(start,stop); /* values are clamped from */
+
+ for(count = start; count < stop; count++) {
+ if(RNA_property_collection_lookup_int(ptr, prop, count - start, &newptr)) {
+ PyList_SET_ITEM(list, count - start, pyrna_struct_CreatePyObject(&newptr));
+ }
+ else {
+ Py_DECREF(list);
+
+ PyErr_Format(PyExc_RuntimeError, "bpy_prop_collection[%d:%d]: internal error RNA_property_collection_lookup_int(...) failed with array index in range.", start, stop);
+ return NULL;
+ }
}
- else {
- Py_DECREF(list);
- PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection");
- return NULL;
- }
+ return list;
}
-
- return list;
}
/* TODO - dimensions
@@ -1568,21 +1592,31 @@
return pyrna_prop_collection_subscript_int(self, i);
}
else if (PySlice_Check(key)) {
- int len= RNA_property_collection_length(&self->ptr, self->prop);
- Py_ssize_t start, stop, step, slicelength;
+ Py_ssize_t step= 1;
- if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
+ if(((PySliceObject *)key)->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
}
- else if (step == 1) {
- return pyrna_prop_collection_subscript_slice(&self->ptr, self->prop, start, stop);
+ else if (step != 1) {
+ PyErr_SetString(PyExc_TypeError, "bpy_prop_collection[slice]: slice steps not supported");
+ return NULL;
}
+ else if(((PySliceObject *)key)->start == Py_None && ((PySliceObject *)key)->stop == Py_None) {
+ return pyrna_prop_collection_values(self);
+ }
else {
- PyErr_SetString(PyExc_TypeError, "bpy_prop_collection[slice]: slice steps not supported with rna");
- return NULL;
+ int len= RNA_property_collection_length(&self->ptr, self->prop);
+ Py_ssize_t start, stop, slicelength;
+
+ if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
+ return NULL;
+
+ if (slicelength <= 0) {
+ return PyList_New(0);
+ }
+ else {
+ return pyrna_prop_collection_subscript_slice(self, start, stop, len);
+ }
}
}
else {
@@ -1603,21 +1637,33 @@
return pyrna_prop_array_subscript_int(self, PyLong_AsLong(key));
}
else if (PySlice_Check(key)) {
- Py_ssize_t start, stop, step, slicelength;
- int len = pyrna_prop_array_length(self);
+ Py_ssize_t step= 1;
- if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
+ if(((PySliceObject *)key)->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
}
- else if (step == 1) {
- return pyrna_prop_array_subscript_slice(self, &self->ptr, self->prop, start, stop, len);
+ else if (step != 1) {
+ PyErr_SetString(PyExc_TypeError, "bpy_prop_array[slice]: slice steps not supported");
+ return NULL;
}
+ else if(((PySliceObject *)key)->start == Py_None && ((PySliceObject *)key)->stop == Py_None) {
+ /* note, no significant advantage with optimizing [:] slice as with collections but include here for consistency with collection slice func */
+ int len= pyrna_prop_array_length(self);
+ return pyrna_prop_array_subscript_slice(self, &self->ptr, self->prop, 0, len, len);
+ }
else {
- PyErr_SetString(PyExc_TypeError, "bpy_prop_array[slice]: slice steps not supported with rna");
- return NULL;
+ int len= pyrna_prop_array_length(self);
+ Py_ssize_t start, stop, slicelength;
+
+ if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
+ return NULL;
+
+ if (slicelength <= 0) {
+ return PyTuple_New(0);
+ }
+ else {
+ return pyrna_prop_array_subscript_slice(self, &self->ptr, self->prop, start, stop, len);
+ }
}
}
else {
@@ -3047,7 +3093,7 @@
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
-static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_collection_keys(BPy_PropertyRNA *self)
{
PyObject *ret= PyList_New(0);
PyObject *item;
@@ -3072,7 +3118,7 @@
return ret;
}
-static PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_collection_items(BPy_PropertyRNA *self)
{
PyObject *ret= PyList_New(0);
PyObject *item;
@@ -3105,7 +3151,7 @@
return ret;
}
-static PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_collection_values(BPy_PropertyRNA *self)
{
PyObject *ret= PyList_New(0);
PyObject *item;
@@ -3174,7 +3220,7 @@
return PyLong_FromVoidPtr(self->ptr.data);
}
-static PyObject *pyrna_prop_get(BPy_PropertyRNA *self, PyObject *args)
+static PyObject *pyrna_prop_collection_get(BPy_PropertyRNA *self, PyObject *args)
{
PointerRNA newptr;
@@ -3210,7 +3256,7 @@
RNA_PROP_END;
}
-/* pyrna_prop_foreach_get/set both use this */
+/* pyrna_prop_collection_foreach_get/set both use this */
static int foreach_parse_args(
BPy_PropertyRNA *self, PyObject *args,
@@ -3433,12 +3479,12 @@
Py_RETURN_NONE;
}
-static PyObject *pyrna_prop_foreach_get(BPy_PropertyRNA *self, PyObject *args)
+static PyObject *pyrna_prop_collection_foreach_get(BPy_PropertyRNA *self, PyObject *args)
{
return foreach_getset(self, args, 0);
}
-static PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args)
+static PyObject *pyrna_prop_collection_foreach_set(BPy_PropertyRNA *self, PyObject *args)
{
return foreach_getset(self, args, 1);
}
@@ -3468,7 +3514,7 @@
/* Try get values from a collection */
PyObject *ret;
PyObject *iter= NULL;
- ret = pyrna_prop_values(self);
+ ret= pyrna_prop_collection_values(self);
/* we know this is a list so no need to PyIter_Check
* otherwise it could be NULL (unlikely) if conversion failed */
@@ -3519,14 +3565,14 @@
};
static struct PyMethodDef pyrna_prop_collection_methods[] = {
- {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL},
- {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL},
+ {"foreach_get", (PyCFunction)pyrna_prop_collection_foreach_get, METH_VARARGS, NULL},
+ {"foreach_set", (PyCFunction)pyrna_prop_collection_foreach_set, METH_VARARGS, NULL},
- {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, NULL},
- {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS,NULL},
- {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, NULL},
+ {"keys", (PyCFunction)pyrna_prop_collection_keys, METH_NOARGS, NULL},
+ {"items", (PyCFunction)pyrna_prop_collection_items, METH_NOARGS,NULL},
+ {"values", (PyCFunction)pyrna_prop_collection_values, METH_NOARGS, NULL},
- {"get", (PyCFunction)pyrna_prop_get, METH_VARARGS, NULL},
+ {"get", (PyCFunction)pyrna_prop_collection_get, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
@@ -4797,7 +4843,7 @@
PyObject *list, *name;
PyMethodDef *meth;
- list= pyrna_prop_keys(self); /* like calling structs.keys(), avoids looping here */
+ list= pyrna_prop_collection_keys(self); /* like calling structs.keys(), avoids looping here */
for(meth=pyrna_basetype_methods; meth->ml_name; meth++) {
name = PyUnicode_FromString(meth->ml_name);
More information about the Bf-blender-cvs
mailing list