diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-01-06 07:01:06 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-01-06 07:01:06 +0300 |
commit | 68b931b03f8ed0e082850192478f79513063dd62 (patch) | |
tree | b6708776d767e02ffde21f5c571f6d040b0a35ed /source | |
parent | 1246f1c9b5bf41075537e4f124f90a38c988c30e (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
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 164 |
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); |