Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-01-06 07:01:06 +0300
committerCampbell Barton <ideasman42@gmail.com>2011-01-06 07:01:06 +0300
commit68b931b03f8ed0e082850192478f79513063dd62 (patch)
treeb6708776d767e02ffde21f5c571f6d040b0a35ed
parent1246f1c9b5bf41075537e4f124f90a38c988c30e (diff)
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
-rw-r--r--source/blender/python/intern/bpy_rna.c164
1 files changed, 105 insertions, 59 deletions
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index fb6bfe8a86d..74dcc811185 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -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 int pyrna_prop_collection_bool( BPy_PropertyRNA *self )
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_collection_subscript_str(BPy_PropertyRNA *self, cons
}
/* 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));
- }
- else {
- Py_DECREF(list);
+ start = MIN2(start,stop); /* values are clamped from */
- PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection");
- return NULL;
+ 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;
+ }
}
- }
- return list;
+ return list;
+ }
}
/* TODO - dimensions
@@ -1568,21 +1592,31 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject
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 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
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 @@ static PyGetSetDef pyrna_struct_getseters[] = {
{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 @@ static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
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 @@ static PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
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 @@ static PyObject *pyrna_struct_as_pointer(BPy_StructRNA *self)
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 @@ static void foreach_attr_type( BPy_PropertyRNA *self, char *attr,
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 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
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 @@ PyObject *pyrna_prop_collection_iter(BPy_PropertyRNA *self)
/* 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_array_methods[] = {
};
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 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
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);