py/rna api speedup for collection slicing in all cases, rather then having an exception for [:].

- avoid looping over the entire collection unless a negative index is used.
- dont use the get index function for building the slice list, instead loop over the collection until the stop value.
This commit is contained in:
2011-01-07 05:33:30 +00:00
parent 5d74d65106
commit 0f2089afa1

View File

@@ -93,7 +93,7 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
#ifdef USE_MATHUTILS
#include "../generic/mathutils.h" /* so we can have mathutils callbacks */
static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length);
static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length);
static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, short order_fallback);
/* bpyrna vector/euler/quat callbacks */
@@ -1470,43 +1470,45 @@ 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(BPy_PropertyRNA *self, int start, int stop, int len)
static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, Py_ssize_t start, Py_ssize_t stop)
{
if(start == 0 && stop == len) {
/* faster */
return pyrna_prop_collection_values(self);
}
else {
PointerRNA *ptr= &self->ptr;
PropertyRNA *prop= self->prop;
int count= 0;
PointerRNA newptr;
PyObject *list = PyList_New(stop - start);
int count;
PyObject *list= PyList_New(0);
PyObject *item;
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;
}
/* first loop up-until the start */
CollectionPropertyIterator rna_macro_iter;
for(RNA_property_collection_begin(&self->ptr, self->prop, &rna_macro_iter); rna_macro_iter.valid; RNA_property_collection_next(&rna_macro_iter)) {
/* PointerRNA itemptr= rna_macro_iter.ptr; */
if(count == start) {
break;
}
return list;
count++;
}
/* add items until stop */
for(; rna_macro_iter.valid; RNA_property_collection_next(&rna_macro_iter)) {
item= pyrna_struct_CreatePyObject(&rna_macro_iter.ptr);
PyList_Append(list, item);
Py_DECREF(item);
count++;
if(count == stop) {
break;
}
}
RNA_property_collection_end(&rna_macro_iter);
return list;
}
/* TODO - dimensions
* note: could also use pyrna_prop_array_to_py_index(self, count) in a loop but its a lot slower
* since at the moment it reads (and even allocates) the entire array for each index.
*/
static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length)
static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length)
{
int count, totdim;
@@ -1592,30 +1594,38 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject
return pyrna_prop_collection_subscript_int(self, i);
}
else if (PySlice_Check(key)) {
PySliceObject *key_slice= (PySliceObject *)key;
Py_ssize_t step= 1;
if(((PySliceObject *)key)->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
if(key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
return NULL;
}
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 if(key_slice->start == Py_None && key_slice->stop == Py_None) {
return pyrna_prop_collection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
}
else {
int len= RNA_property_collection_length(&self->ptr, self->prop);
Py_ssize_t start, stop, slicelength;
Py_ssize_t start= 0, stop= PY_SSIZE_T_MAX;
if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
return NULL;
/* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
if(key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) return NULL;
if(key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop)) return NULL;
if (slicelength <= 0) {
if(start < 0 || stop < 0) {
/* only get the length for negative values */
Py_ssize_t len= (Py_ssize_t)RNA_property_collection_length(&self->ptr, self->prop);
if(start < 0) start += len;
if(stop < 0) start += len;
}
if (stop - start <= 0) {
return PyList_New(0);
}
else {
return pyrna_prop_collection_subscript_slice(self, start, stop, len);
return pyrna_prop_collection_subscript_slice(self, start, stop);
}
}
}
@@ -1638,17 +1648,18 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
}
else if (PySlice_Check(key)) {
Py_ssize_t step= 1;
PySliceObject *key_slice= (PySliceObject *)key;
if(((PySliceObject *)key)->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
if(key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
return NULL;
}
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) {
else if(key_slice->start == Py_None && key_slice->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);
Py_ssize_t len= (Py_ssize_t)pyrna_prop_array_length(self);
return pyrna_prop_array_subscript_slice(self, &self->ptr, self->prop, 0, len, len);
}
else {
@@ -3153,17 +3164,8 @@ static PyObject *pyrna_prop_collection_items(BPy_PropertyRNA *self)
static PyObject *pyrna_prop_collection_values(BPy_PropertyRNA *self)
{
PyObject *ret= PyList_New(0);
PyObject *item;
RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
item = pyrna_struct_CreatePyObject(&itemptr);
PyList_Append(ret, item);
Py_DECREF(item);
}
RNA_PROP_END;
return ret;
/* re-use slice*/
return pyrna_prop_collection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
}
static char pyrna_struct_get_doc[] =