Python part of multidim. array support for RNA complete.
Multidim. arrays can now be modified at any level, for example: struc.arrayprop = x struc.arrayprop[i] = x struc.arrayprop[i][j] = x struc.arrayprop[i][j][k] = x etc... Approriate rvalue type/length checking is done. To ensure all works correctly, I wrote automated tests in release/test/rna_array.py. These tests cover: array/item access, assignment on different levels, tests that proper exceptions are thrown on invalid item access/assignment. The tests use properties of the RNA Test struct defined in rna_test.c. This struct is only compiled when building with BF_UNIT_TEST=1 scons arg. Currently unit tests are run manually by loading the script in the Text Editor. Here's the output I have: http://www.pasteall.org/7644 Things to improve here: - better exception messages when multidim. array assignment fails. Those we have currently are not very useful for multidim. - add tests for slice assignment
This commit is contained in:
		| @@ -30,33 +30,65 @@ | ||||
|  | ||||
| #include "BLI_string.h" | ||||
|  | ||||
| #include "BKE_global.h" | ||||
|  | ||||
| #include "MEM_guardedalloc.h" | ||||
|  | ||||
| typedef void (*ItemConvertFunc)(PyObject *, char *); | ||||
| typedef int (*ItemTypeCheckFunc)(PyObject *); | ||||
| typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *); | ||||
| #define MAX_ARRAY_DIMENSION 10 | ||||
|  | ||||
| /* Ensures that a python sequence has an expected number of items/sub-items and items are of expected type. */ | ||||
| static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned short totdim, unsigned short dim_size[], | ||||
| 								ItemTypeCheckFunc check_item_type, const char *item_type_str, char *error_str, int error_str_size) | ||||
| /* convenient way to access array dimension size */ | ||||
| #define DIMSIZE(a) (dimsize[a - 1]) | ||||
|  | ||||
| typedef void (*ItemConvertFunc)(PyObject *, char *); | ||||
| typedef int  (*ItemTypeCheckFunc)(PyObject *); | ||||
| typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *); | ||||
| typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *); | ||||
|  | ||||
| /* | ||||
|   arr[3][4][5] | ||||
|       0  1  2  <- dimension index | ||||
| */ | ||||
|  | ||||
| /* | ||||
|   arr[2] = x | ||||
|  | ||||
|   py_to_array_index(arraydim=0, arrayoffset=0, index=2) | ||||
|     validate_array(lvalue_dim=0) | ||||
|     ... make real index ... | ||||
| */ | ||||
|  | ||||
| /* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */ | ||||
| /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */ | ||||
| static int validate_array_type(PyObject *seq, unsigned short dim, unsigned short totdim, unsigned short dimsize[], | ||||
| 							   ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix) | ||||
| { | ||||
| 	int i; | ||||
| 	if (dim < totdim) { | ||||
|  | ||||
| 	/* not the last dimension */ | ||||
| 	if (dim + 1 < totdim) { | ||||
| 		/* check that a sequence contains dimsize[dim] items */ | ||||
|  | ||||
| 		for (i= 0; i < PySequence_Length(seq); i++) { | ||||
| 			PyObject *item; | ||||
| 			int ok= 1; | ||||
| 			item= PySequence_GetItem(seq, i); | ||||
|  | ||||
| 			if (!PySequence_Check(item)) { | ||||
| 				BLI_snprintf(error_str, error_str_size, "expected a %d-dimensional sequence of %s", (int)totdim, item_type_str); | ||||
| 				/* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */ | ||||
| 				PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s", error_prefix, item_type_str); | ||||
| 				ok= 0; | ||||
| 			} | ||||
| 			else if (PySequence_Length(item) != dim_size[dim - 1]) { | ||||
| 				BLI_snprintf(error_str, error_str_size, "dimension %d should contain %d items", (int)dim, (int)dim_size[dim - 1]); | ||||
| 			/* arr[3][4][5] | ||||
| 			   DIMSIZE(1)=4 | ||||
| 			   DIMSIZE(2)=5 | ||||
| 		    | ||||
| 			   dim=0 */ | ||||
| 			else if (PySequence_Length(item) != DIMSIZE(dim + 1)) { | ||||
| 				/* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)DIMSIZE(dim + 1)); */ | ||||
| 				PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)DIMSIZE(dim + 1)); | ||||
| 				ok= 0; | ||||
| 			} | ||||
|  | ||||
| 			if (!pyrna_validate_array(item, dim + 1, totdim, dim_size, check_item_type, item_type_str, error_str, error_str_size)) { | ||||
| 			else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) { | ||||
| 				ok= 0; | ||||
| 			} | ||||
|  | ||||
| @@ -67,13 +99,15 @@ static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned shor | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		/* check that items are of correct type */ | ||||
| 		for (i= 0; i < PySequence_Length(seq); i++) { | ||||
| 			PyObject *item= PySequence_GetItem(seq, i); | ||||
|  | ||||
| 			if (!check_item_type(item)) { | ||||
| 				Py_DECREF(item); | ||||
| 							 | ||||
| 				BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); | ||||
|  | ||||
| 				/* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */ | ||||
| 				PyErr_Format(PyExc_TypeError, "sequence items should be of type %s", item_type_str); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| @@ -85,7 +119,7 @@ static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned shor | ||||
| } | ||||
|  | ||||
| /* Returns the number of items in a single- or multi-dimensional sequence. */ | ||||
| static int pyrna_count_items(PyObject *seq) | ||||
| static int count_items(PyObject *seq) | ||||
| { | ||||
| 	int totitem= 0; | ||||
|  | ||||
| @@ -93,7 +127,7 @@ static int pyrna_count_items(PyObject *seq) | ||||
| 		int i; | ||||
| 		for (i= 0; i < PySequence_Length(seq); i++) { | ||||
| 			PyObject *item= PySequence_GetItem(seq, i); | ||||
| 			totitem += pyrna_count_items(item); | ||||
| 			totitem += count_items(item); | ||||
| 			Py_DECREF(item); | ||||
| 		} | ||||
| 	} | ||||
| @@ -103,40 +137,103 @@ static int pyrna_count_items(PyObject *seq) | ||||
| 	return totitem; | ||||
| } | ||||
|  | ||||
| static int pyrna_apply_array_length(PointerRNA *ptr, PropertyRNA *prop, int totitem, char *error_str, int error_str_size) | ||||
| /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */ | ||||
| static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix) | ||||
| { | ||||
| 	if (RNA_property_flag(prop) & PROP_DYNAMIC) { | ||||
| 		/* length can be flexible */ | ||||
| 		if (RNA_property_array_length(ptr, prop) != totitem) { | ||||
| 			if (!RNA_property_dynamic_array_set_length(ptr, prop, totitem)) { | ||||
| 				BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totitem); | ||||
| 	unsigned short dimsize[MAX_ARRAY_DIMENSION]; | ||||
| 	int tot, totdim, len; | ||||
|  | ||||
| 	tot= count_items(rvalue); | ||||
| 	totdim= RNA_property_array_dimension(prop, dimsize); | ||||
|  | ||||
| 	if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) { | ||||
| 		/* length is flexible */ | ||||
| 		if (RNA_property_array_length(ptr, prop) != tot) { | ||||
| 			if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) { | ||||
| 				/* BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */ | ||||
| 				PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			len= tot; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		/* length is a constraint */ | ||||
| 		int len= RNA_property_array_length(ptr, prop); | ||||
| 		if (totitem != len) { | ||||
| 			BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); | ||||
| 		if (!lvalue_dim) { | ||||
| 			len= RNA_property_array_length(ptr, prop); | ||||
| 		} | ||||
| 		/* array item assignment */ | ||||
| 		else { | ||||
| 			int i; | ||||
|  | ||||
| 			len= 1; | ||||
|  | ||||
| 			/* arr[3][4][5] | ||||
|  | ||||
| 			   arr[2] = x | ||||
| 			   dimsize={4, 5} | ||||
| 			   DIMSIZE(1) = 4 | ||||
| 			   DIMSIZE(2) = 5 | ||||
| 			   lvalue_dim=0, totdim=3 | ||||
|  | ||||
| 			   arr[2][3] = x | ||||
| 			   lvalue_dim=1 | ||||
|  | ||||
| 			   arr[2][3][4] = x | ||||
| 			   lvalue_dim=2 */ | ||||
| 			for (i= lvalue_dim; i < totdim; i++) | ||||
| 				len *= DIMSIZE(i); | ||||
| 		} | ||||
|  | ||||
| 		if (tot != len) { | ||||
| 			/* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */ | ||||
| 			PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total", error_prefix, len); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	*totitem= len; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static char *pyrna_py_to_array(PyObject *seq, unsigned short dim, unsigned short totdim, char *data, unsigned int item_size, ItemConvertFunc convert_item) | ||||
| static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix) | ||||
| { | ||||
| 	unsigned short dimsize[MAX_ARRAY_DIMENSION]; | ||||
| 	int totdim= RNA_property_array_dimension(prop, dimsize); | ||||
|  | ||||
| 	/* validate type first because length validation may modify property array length */ | ||||
|  | ||||
| 	if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix); | ||||
| } | ||||
|  | ||||
| static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, unsigned short dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index) | ||||
| { | ||||
| 	unsigned int i; | ||||
| 	int totdim= RNA_property_array_dimension(prop, NULL); | ||||
|  | ||||
| 	for (i= 0; i < PySequence_Length(seq); i++) { | ||||
| 		PyObject *item= PySequence_GetItem(seq, i); | ||||
|  | ||||
| 		if (dim < totdim) { | ||||
| 			data= pyrna_py_to_array(item, dim + 1, totdim, data, item_size, convert_item); | ||||
| 		if (dim + 1 < totdim) { | ||||
| 			data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index); | ||||
| 		} | ||||
| 		else { | ||||
| 			convert_item(item, data); | ||||
| 			data += item_size; | ||||
| 			if (!data) { | ||||
| 				char value[sizeof(int)]; | ||||
|  | ||||
| 				convert_item(item, value); | ||||
| 				rna_set_index(ptr, prop, *index, value); | ||||
| 				*index = *index + 1; | ||||
| 			} | ||||
| 			else { | ||||
| 				convert_item(item, data); | ||||
| 				data += item_size; | ||||
| 			} | ||||
| 		} | ||||
| 			 | ||||
| 		Py_DECREF(item); | ||||
| @@ -145,21 +242,15 @@ static char *pyrna_py_to_array(PyObject *seq, unsigned short dim, unsigned short | ||||
| 	return data; | ||||
| } | ||||
|  | ||||
| static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size, | ||||
| 									 ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array) | ||||
| static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix) | ||||
| { | ||||
| 	unsigned short totdim, dim_size[100]; | ||||
| 	unsigned short totdim, dim_size[MAX_ARRAY_DIMENSION]; | ||||
| 	int totitem; | ||||
| 	char *data= NULL; | ||||
|  | ||||
| 	totdim= RNA_property_array_dimension(prop, dim_size); | ||||
|  | ||||
| 	if (!pyrna_validate_array(py, 1, totdim, dim_size, check_item_type, item_type_str, error_str, error_str_size)) | ||||
| 		return 0; | ||||
|  | ||||
| 	totitem= pyrna_count_items(py); | ||||
|  | ||||
| 	if (!pyrna_apply_array_length(ptr, prop, totitem, error_str, error_str_size)) | ||||
| 	if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (totitem) { | ||||
| @@ -168,7 +259,7 @@ static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA | ||||
| 		else | ||||
| 			data= param_data; | ||||
|  | ||||
| 		pyrna_py_to_array(py, 1, totdim, data, item_size, convert_item); | ||||
| 		copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL); | ||||
|  | ||||
| 		if (param_data) { | ||||
| 			if (RNA_property_flag(prop) & PROP_DYNAMIC) { | ||||
| @@ -186,50 +277,236 @@ static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void pyrna_py_to_float(PyObject *py, char *data) | ||||
| static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix) | ||||
| { | ||||
| 	unsigned short totdim, dimsize[MAX_ARRAY_DIMENSION]; | ||||
| 	int totitem, i; | ||||
|  | ||||
| 	totdim= RNA_property_array_dimension(prop, dimsize); | ||||
|  | ||||
| 	/* convert index */ | ||||
|  | ||||
| 	/* arr[3][4][5] | ||||
|  | ||||
| 	   arr[2] = x | ||||
| 	   lvalue_dim=0, index = 0 + 2 * 4 * 5 | ||||
|  | ||||
| 	   arr[2][3] = x | ||||
| 	   lvalue_dim=1, index = 40 + 3 * 5 */ | ||||
|  | ||||
| 	lvalue_dim++; | ||||
|  | ||||
| 	for (i= lvalue_dim; i < totdim; i++) | ||||
| 		index *= DIMSIZE(i); | ||||
|  | ||||
| 	index += arrayoffset; | ||||
|  | ||||
| 	if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix)) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (totitem) | ||||
| 		copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void py_to_float(PyObject *py, char *data) | ||||
| { | ||||
| 	*(float*)data= (float)PyFloat_AsDouble(py); | ||||
| } | ||||
|  | ||||
| static void pyrna_py_to_int(PyObject *py, char *data) | ||||
| static void py_to_int(PyObject *py, char *data) | ||||
| { | ||||
| 	*(int*)data= (int)PyLong_AsSsize_t(py); | ||||
| } | ||||
|  | ||||
| static void pyrna_py_to_boolean(PyObject *py, char *data) | ||||
| static void py_to_bool(PyObject *py, char *data) | ||||
| { | ||||
| 	*(int*)data= (int)PyObject_IsTrue(py); | ||||
| } | ||||
|  | ||||
| static int py_float_check(PyObject *py) | ||||
| { | ||||
| 	return PyFloat_Check(py) || (PyIndex_Check(py)); | ||||
| 	/* accept both floats and integers */ | ||||
| 	return PyFloat_Check(py) || PyLong_Check(py); | ||||
| } | ||||
|  | ||||
| static int py_int_check(PyObject *py) | ||||
| { | ||||
| 	return PyLong_Check(py) || (PyIndex_Check(py)); | ||||
| 	/* accept only integers */ | ||||
| 	return PyLong_Check(py); | ||||
| } | ||||
|  | ||||
| static int py_bool_check(PyObject *py) | ||||
| { | ||||
| 	return PyBool_Check(py) || (PyIndex_Check(py)); | ||||
| 	return PyBool_Check(py); | ||||
| } | ||||
|  | ||||
| int pyrna_py_to_float_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size) | ||||
| static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value) | ||||
| { | ||||
| 	return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size, | ||||
| 									 py_float_check, "float", sizeof(float), pyrna_py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array); | ||||
| 	RNA_property_float_set_index(ptr, prop, index, *(float*)value); | ||||
| } | ||||
|  | ||||
| int pyrna_py_to_int_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size) | ||||
| static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value) | ||||
| { | ||||
| 	return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size, | ||||
| 									 py_int_check, "int", sizeof(int), pyrna_py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array); | ||||
| 	RNA_property_int_set_index(ptr, prop, index, *(int*)value); | ||||
| } | ||||
|  | ||||
| int pyrna_py_to_boolean_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size) | ||||
| static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value) | ||||
| { | ||||
| 	return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size, | ||||
| 									 py_bool_check, "boolean", sizeof(int), pyrna_py_to_boolean, (RNA_SetArrayFunc)RNA_property_boolean_set_array); | ||||
| 	RNA_property_boolean_set_index(ptr, prop, index, *(int*)value); | ||||
| } | ||||
|  | ||||
| int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix) | ||||
| { | ||||
| 	int ret; | ||||
| 	switch (RNA_property_type(prop)) { | ||||
| 	case PROP_FLOAT: | ||||
| 		ret= py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix); | ||||
| 		break; | ||||
| 	case PROP_INT: | ||||
| 		ret= py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix); | ||||
| 		break; | ||||
| 	case PROP_BOOLEAN: | ||||
| 		ret= py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix); | ||||
| 		break; | ||||
| 	default: | ||||
| 		PyErr_SetString(PyExc_TypeError, "not an array type"); | ||||
| 		ret= 0; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix) | ||||
| { | ||||
| 	int ret; | ||||
| 	switch (RNA_property_type(prop)) { | ||||
| 	case PROP_FLOAT: | ||||
| 		ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix); | ||||
| 		break; | ||||
| 	case PROP_INT: | ||||
| 		ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix); | ||||
| 		break; | ||||
| 	case PROP_BOOLEAN: | ||||
| 		ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix); | ||||
| 		break; | ||||
| 	default: | ||||
| 		PyErr_SetString(PyExc_TypeError, "not an array type"); | ||||
| 		ret= 0; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static PyObject *pyrna_array_item(PointerRNA *ptr, PropertyRNA *prop, int index) | ||||
| { | ||||
| 	PyObject *item; | ||||
|  | ||||
| 	switch (RNA_property_type(prop)) { | ||||
| 	case PROP_FLOAT: | ||||
| 		item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index)); | ||||
| 		break; | ||||
| 	case PROP_BOOLEAN: | ||||
| 		item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index)); | ||||
| 		break; | ||||
| 	case PROP_INT: | ||||
| 		item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index)); | ||||
| 		break; | ||||
| 	default: | ||||
| 		PyErr_SetString(PyExc_TypeError, "not an array type"); | ||||
| 		item= NULL; | ||||
| 	} | ||||
|  | ||||
| 	return item; | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| /* XXX this is not used (and never will?) */ | ||||
| /* Given an array property, creates an N-dimensional tuple of values. */ | ||||
| static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index) | ||||
| { | ||||
| 	PyObject *tuple; | ||||
| 	int i, len; | ||||
| 	int totdim= RNA_property_array_dimension(prop, NULL); | ||||
|  | ||||
| 	len= RNA_property_multidimensional_array_length(ptr, prop, dim); | ||||
|  | ||||
| 	tuple= PyTuple_New(len); | ||||
|  | ||||
| 	for (i= 0; i < len; i++) { | ||||
| 		PyObject *item; | ||||
|  | ||||
| 		if (dim + 1 < totdim) | ||||
| 			item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index); | ||||
| 		else { | ||||
| 			item= pyrna_array_item(ptr, prop, *index); | ||||
| 			*index= *index + 1; | ||||
| 		} | ||||
|  | ||||
| 		if (!item) { | ||||
| 			Py_DECREF(tuple); | ||||
| 			return NULL; | ||||
| 		} | ||||
|  | ||||
| 		PyTuple_SetItem(tuple, i, item); | ||||
| 	} | ||||
|  | ||||
| 	return tuple; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index) | ||||
| { | ||||
| 	int totdim, i, len; | ||||
| 	unsigned short dimsize[MAX_ARRAY_DIMENSION]; | ||||
| 	BPy_PropertyRNA *ret= NULL; | ||||
|  | ||||
| 	/* just in case check */ | ||||
| 	len= RNA_property_multidimensional_array_length(&self->ptr, self->prop, self->arraydim); | ||||
| 	if (index >= len || index < 0) { | ||||
| 		/* this shouldn't happen because higher level funcs must check for invalid index */ | ||||
| 		if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len); | ||||
|  | ||||
| 		PyErr_SetString(PyExc_IndexError, "out of range"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	totdim= RNA_property_array_dimension(self->prop, dimsize); | ||||
|  | ||||
| 	if (self->arraydim + 1 < totdim) { | ||||
| 		ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(&self->ptr, self->prop); | ||||
| 		ret->arraydim= self->arraydim + 1; | ||||
|  | ||||
| 		/* arr[3][4][5] | ||||
|  | ||||
| 		   x = arr[2] | ||||
| 		   index = 0 + 2 * 4 * 5 | ||||
|  | ||||
| 		   x = arr[2][3] | ||||
| 		   index = offset + 3 * 5 */ | ||||
|  | ||||
| 		for (i= self->arraydim + 1; i < totdim; i++) | ||||
| 			index *= DIMSIZE(i); | ||||
|  | ||||
| 		ret->arrayoffset= self->arrayoffset + index; | ||||
| 	} | ||||
| 	else { | ||||
| 		index = self->arrayoffset + index; | ||||
| 		ret= (BPy_PropertyRNA*)pyrna_array_item(&self->ptr, self->prop, index); | ||||
| 	} | ||||
|  | ||||
| 	return (PyObject*)ret; | ||||
| } | ||||
|  | ||||
| PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop) | ||||
| { | ||||
| 	PyObject *ret; | ||||
|  | ||||
| 	ret= pyrna_math_object_from_array(ptr, prop); | ||||
|  | ||||
| 	/* is this a maths object? */ | ||||
| 	if (ret) return ret; | ||||
|  | ||||
| 	return pyrna_prop_CreatePyObject(ptr, prop); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user