[Bf-blender-cvs] [a9d979c] master: mathutils: add freeze() method, is_frozen attr

Campbell Barton noreply at git.blender.org
Sun Feb 15 04:06:13 CET 2015


Commit: a9d979c8ef2b6de25c1953da341dd5e207416540
Author: Campbell Barton
Date:   Sun Feb 15 11:26:31 2015 +1100
Branches: master
https://developer.blender.org/rBa9d979c8ef2b6de25c1953da341dd5e207416540

mathutils: add freeze() method, is_frozen attr

This allows you to make any mathutils object immutable.

===================================================================

M	source/blender/python/mathutils/mathutils.c
M	source/blender/python/mathutils/mathutils.h
M	source/blender/python/mathutils/mathutils_Color.c
M	source/blender/python/mathutils/mathutils_Euler.c
M	source/blender/python/mathutils/mathutils_Matrix.c
M	source/blender/python/mathutils/mathutils_Quaternion.c
M	source/blender/python/mathutils/mathutils_Vector.c

===================================================================

diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index ca20f83..28b2d26d 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -452,6 +452,13 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
 	return -1;
 }
 
+void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self)
+{
+	PyErr_Format(PyExc_TypeError,
+	             "%s is frozen (immutable)",
+	             Py_TYPE(self)->tp_name);
+}
+
 /* BaseMathObject generic functions for all mathutils types */
 char BaseMathObject_owner_doc[] = "The item this is wrapping or None  (read-only).";
 PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
@@ -466,6 +473,33 @@ PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closu
 	return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_WRAP) != 0);
 }
 
+char BaseMathObject_is_frozen_doc[] = "True when this object has been frozen (read-only).\n\n:type: boolean";
+PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure))
+{
+	return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_FROZEN) != 0);
+}
+
+char BaseMathObject_freeze_doc[] =
+".. function:: freeze()\n"
+"\n"
+"   Make this object immutable.\n"
+"\n"
+"   After this the object can be hashed, used in dictionaries & sets.\n"
+"\n"
+"   :return: An instance of this object.\n"
+;
+PyObject *BaseMathObject_freeze(BaseMathObject *self)
+{
+	if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
+		PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data");
+		return NULL;
+	}
+
+	self->flag |= BASE_MATH_FLAG_IS_FROZEN;
+
+	return Py_INCREF_RET((PyObject *)self);;
+}
+
 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
 {
 	Py_VISIT(self->cb_user);
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 296b8cf..03ce9af 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -34,6 +34,7 @@
 struct DynStr;
 
 extern char BaseMathObject_is_wrapped_doc[];
+extern char BaseMathObject_is_frozen_doc[];
 extern char BaseMathObject_owner_doc[];
 
 #define BASE_MATH_NEW(struct_name, root_type, base_type) \
@@ -43,6 +44,7 @@ extern char BaseMathObject_owner_doc[];
 /* BaseMathObject.flag */
 enum {
 	BASE_MATH_FLAG_IS_WRAP    = (1 << 0),
+	BASE_MATH_FLAG_IS_FROZEN  = (1 << 1),
 };
 #define BASE_MATH_FLAG_DEFAULT 0
 
@@ -69,6 +71,10 @@ typedef struct {
 
 PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *);
 PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *);
+PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *);
+
+extern char BaseMathObject_freeze_doc[];
+PyObject *BaseMathObject_freeze(BaseMathObject *self);
 
 int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg);
 int BaseMathObject_clear(BaseMathObject *self);
@@ -102,6 +108,8 @@ int _BaseMathObject_WriteCallback(BaseMathObject *self);
 int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index);
 int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
 
+void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self);
+
 /* since this is called so often avoid where possible */
 #define BaseMath_ReadCallback(_self) \
 	(((_self)->cb_user ?	_BaseMathObject_ReadCallback((BaseMathObject *)_self):0))
@@ -112,6 +120,19 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
 #define BaseMath_WriteIndexCallback(_self, _index) \
 	(((_self)->cb_user ?	_BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):0))
 
+/* support BASE_MATH_FLAG_IS_FROZEN */
+#define BaseMath_ReadCallback_ForWrite(_self) \
+	(UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+	(_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadCallback(_self)))
+
+#define BaseMath_ReadIndexCallback_ForWrite(_self, _index) \
+	(UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+	(_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadIndexCallback(_self, _index)))
+
+#define BaseMath_Prepare_ForWrite(_self) \
+	(UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \
+	(_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : 0)
+
 /* utility func */
 int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
 int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix);
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index ce59099..7fea0e5 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -222,8 +222,12 @@ static PyObject *Color_item(ColorObject *self, int i)
 /* sequence accessor (set) */
 static int Color_ass_item(ColorObject *self, int i, PyObject *value)
 {
-	float f = PyFloat_AsDouble(value);
+	float f;
+
+	if (BaseMath_Prepare_ForWrite(self) == -1)
+		return -1;
 
+	f = PyFloat_AsDouble(value);
 	if (f == -1 && PyErr_Occurred()) {  /* parsed item not a number */
 		PyErr_SetString(PyExc_TypeError,
 		                "color[item] = x: "
@@ -275,7 +279,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
 	int i, size;
 	float col[COLOR_SIZE];
 
-	if (BaseMath_ReadCallback(self) == -1)
+	if (BaseMath_ReadCallback_ForWrite(self) == -1)
 		return -1;
 
 	CLAMP(begin, 0, COLOR_SIZE);
@@ -431,7 +435,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
 	color1 = (ColorObject *)v1;
 	color2 = (ColorObject *)v2;
 
-	if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
+	if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
 		return NULL;
 
 	add_vn_vn(color1->col, color2->col, COLOR_SIZE);
@@ -480,7 +484,7 @@ static PyObject *Color_isub(PyObject *v1, PyObject *v2)
 	color1 = (ColorObject *)v1;
 	color2 = (ColorObject *)v2;
 
-	if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
+	if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
 		return NULL;
 
 	sub_vn_vn(color1->col, color2->col, COLOR_SIZE);
@@ -579,7 +583,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2)
 	ColorObject *color = (ColorObject *)v1;
 	float scalar;
 
-	if (BaseMath_ReadCallback(color) == -1)
+	if (BaseMath_ReadCallback_ForWrite(color) == -1)
 		return NULL;
 
 	/* only support color *= float */
@@ -605,7 +609,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
 	ColorObject *color = (ColorObject *)v1;
 	float scalar;
 
-	if (BaseMath_ReadCallback(color) == -1)
+	if (BaseMath_ReadCallback_ForWrite(color) == -1)
 		return NULL;
 
 	/* only support color /= float */
@@ -728,7 +732,7 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
 		return -1;
 	}
 
-	if (BaseMath_ReadCallback(self) == -1)
+	if (BaseMath_ReadCallback_ForWrite(self) == -1)
 		return -1;
 
 	rgb_to_hsv_v(self->col, hsv);
@@ -769,6 +773,9 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur
 	if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1)
 		return -1;
 
+	if (BaseMath_Prepare_ForWrite(self) == -1)
+		return -1;
+
 	CLAMP(hsv[0], 0.0f, 1.0f);
 	CLAMP(hsv[1], 0.0f, 1.0f);
 	CLAMP(hsv[2], 0.0f, 1.0f);
@@ -796,6 +803,7 @@ static PyGetSetDef Color_getseters[] = {
 	{(char *)"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, (char *)Color_hsv_doc, (void *)0},
 
 	{(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
+	{(char *)"is_frozen",  (getter)BaseMathObject_is_frozen_get,  (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
 	{(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
 	{NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
 };
@@ -806,6 +814,9 @@ static struct PyMethodDef Color_methods[] = {
 	{"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
 	{"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
 	{"__deepcopy__", (PyCFunction) Color_deepcopy, METH_VARARGS, Color_copy_doc},
+
+	/* base-math methods */
+	{"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
 	{NULL, NULL, 0, NULL}
 };
 
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 24aca88..ad761ba 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -182,6 +182,9 @@ PyDoc_STRVAR(Euler_zero_doc,
 );
 static PyObject *Euler_zero(EulerObject *self)
 {
+	if (BaseMath_Prepare_ForWrite(self) == -1)
+		return NULL;
+
 	zero_v3(self->eul);
 
 	if (BaseMath_WriteCallback(self) == -1)
@@ -220,7 +223,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
 		return NULL;
 	}
 
-	if (BaseMath_ReadCallback(self) == -1)
+	if (BaseMath_ReadCallback_ForWrite(self) == -1)
 		return NULL;
 
 
@@ -243,7 +246,7 @@ static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
 {
 	float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
 
-	if (BaseMath_ReadCallback(self) == -1)
+	if (BaseMath_ReadCallback_ForWrite(self) == -1)
 		return NULL;
 
 	if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1)
@@ -270,7 +273,7 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
 {
 	float teul[EULER_SIZE];
 
-	if (BaseMath_ReadCallback(self) == -1)
+	if (BaseMath_ReadCallback_ForWrite(self) == -1)
 		return NULL;
 
 	if (mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value,
@@ -416,8 +419,12 @@ static PyObject *Euler_item(EulerObject *self, int i)
 /* sequence accessor (set) */
 static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
 {
-	float f = PyFloat_AsDouble(value);
+	float f;
 
+	if (BaseMath_Prepare_ForWrite(self) == -1)
+		return -1;
+
+	f = PyFloat_AsDouble(value);
 	if (f == -1 && PyErr_Occurred()) { 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list