[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - _Proxy.c:1.1.2.14

Guido van Rossum guido@python.org
Thu, 25 Apr 2002 22:31:06 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Security
In directory cvs.zope.org:/tmp/cvs-serv17346

Modified Files:
      Tag: SecurityProxy-branch
	_Proxy.c 
Log Message:
- Add pow().

- Add inplace operators.

- Add coerce().

- Fold some long lines.

- Rearrange some code.

- Tidy up the proxy_as_number initializer.


=== Zope3/lib/python/Zope/Security/_Proxy.c 1.1.2.13 => 1.1.2.14 ===
 }
 
-#define BINOP(NAME, CALL) \
-	static PyObject *proxy_##NAME(PyObject *self, PyObject *other) \
-	{ return check2(self, other, "__" #NAME "__", "__r" #NAME "__", CALL); }
+static PyObject *
+check2i(ProxyObject *self, PyObject *other,
+	char *opname, binaryfunc operation)
+{
+	PyObject *result = NULL;
+	PyObject *object = self->proxy_object;
+	PyObject *checker = self->proxy_checker;
+
+	if (check(checker, opname, object)) {
+		result = operation(object, other);
+		if (result == object) {
+			/* If the operation was really carried out inplace,
+			   don't create a new proxy, but use the old one. */
+			Py_DECREF(object);
+			Py_INCREF(self);
+			result = (PyObject *)self;
+		}
+		else if (result != NULL)
+			result = PyObject_CallMethod(checker, "proxy",
+						     "(N)", result);
+	}
+	return result;
+}
 
 #define UNOP(NAME, CALL) \
 	static PyObject *proxy_##NAME(PyObject *self) \
-	{ return check1((ProxyObject *)self, "__" #NAME "__", CALL); }
+	{ return check1((ProxyObject *)self, "__"#NAME"__", CALL); }
+
+#define BINOP(NAME, CALL) \
+	static PyObject *proxy_##NAME(PyObject *self, PyObject *other) \
+	{ return check2(self, other, "__"#NAME"__", "__r"#NAME"__", CALL); }
+
+#define INPLACE(NAME, CALL) \
+	static PyObject *proxy_i##NAME(PyObject *self, PyObject *other) \
+	{ return check2i((ProxyObject *)self, other, "__i"#NAME"__", CALL); }
 
 
 /*
@@ -291,7 +319,8 @@
 {
 	PyNumberMethods *nb = self->ob_type->tp_as_number;
 	if (nb == NULL || nb->nb_int == NULL) {
-		PyErr_SetString(PyExc_TypeError, "object can't be converted to int");
+		PyErr_SetString(PyExc_TypeError,
+				"object can't be converted to int");
 		return NULL;
 	}
 	return nb->nb_int(self);
@@ -302,7 +331,8 @@
 {
 	PyNumberMethods *nb = self->ob_type->tp_as_number;
 	if (nb == NULL || nb->nb_long == NULL) {
-		PyErr_SetString(PyExc_TypeError, "object can't be converted to long");
+		PyErr_SetString(PyExc_TypeError,
+				"object can't be converted to long");
 		return NULL;
 	}
 	return nb->nb_long(self);
@@ -313,7 +343,8 @@
 {
 	PyNumberMethods *nb = self->ob_type->tp_as_number;
 	if (nb == NULL || nb->nb_float== NULL) {
-		PyErr_SetString(PyExc_TypeError, "object can't be converted to float");
+		PyErr_SetString(PyExc_TypeError,
+				"object can't be converted to float");
 		return NULL;
 	}
 	return nb->nb_float(self);
@@ -324,7 +355,8 @@
 {
 	PyNumberMethods *nb = self->ob_type->tp_as_number;
 	if (nb == NULL || nb->nb_oct== NULL) {
-		PyErr_SetString(PyExc_TypeError, "object can't be converted to oct");
+		PyErr_SetString(PyExc_TypeError,
+				"object can't be converted to oct");
 		return NULL;
 	}
 	return nb->nb_oct(self);
@@ -335,24 +367,118 @@
 {
 	PyNumberMethods *nb = self->ob_type->tp_as_number;
 	if (nb == NULL || nb->nb_hex == NULL) {
-		PyErr_SetString(PyExc_TypeError, "object can't be converted to hex");
+		PyErr_SetString(PyExc_TypeError,
+				"object can't be converted to hex");
 		return NULL;
 	}
 	return nb->nb_hex(self);
 }
 
+static PyObject *
+call_ipow(PyObject *self, PyObject *other)
+{
+	/* PyNumber_InPlacePower has three args.  How silly. :-) */
+	return PyNumber_InPlacePower(self, other, Py_None);
+}
+
 BINOP(add, PyNumber_Add)
 BINOP(sub, PyNumber_Subtract)
 BINOP(mul, PyNumber_Multiply)
 BINOP(div, PyNumber_Divide)
 BINOP(mod, PyNumber_Remainder)
 BINOP(divmod, PyNumber_Divmod)
-#define proxy_pow 0
+
+static PyObject *
+proxy_pow(PyObject *self, PyObject *other, PyObject *modulus)
+{
+	PyObject *result = NULL;
+	PyObject *object;
+	PyObject *checker;
+
+	if (Proxy_Check(self)) {
+		object = Proxy_GetObject(self);
+		checker = Proxy_GetChecker(self);
+		if (check(checker, "__pow__", object))
+			result = PyNumber_Power(object, other, modulus);
+	}
+	else if (Proxy_Check(other)) {
+		object = Proxy_GetObject(other);
+		checker = Proxy_GetChecker(other);
+		if (check(checker, "__rpow__", object))
+			result = PyNumber_Power(self, object, modulus);
+	}
+	else if (modulus != NULL && Proxy_Check(modulus)) {
+		object = Proxy_GetObject(modulus);
+		checker = Proxy_GetChecker(modulus);
+		if (check(checker, "__3pow__", object))
+			result = PyNumber_Power(self, other, modulus);
+	}
+	else {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	if (result != NULL)
+		result = PyObject_CallMethod(checker, "proxy", "(N)", result);
+	return result;
+}
+
 BINOP(lshift, PyNumber_Lshift)
 BINOP(rshift, PyNumber_Rshift)
 BINOP(and, PyNumber_And)
 BINOP(xor, PyNumber_Xor)
 BINOP(or, PyNumber_Or)
+
+static int
+proxy_coerce(PyObject **p_self, PyObject **p_other)
+{
+	PyObject *self = *p_self;
+	PyObject *other = *p_other;
+	PyObject *object;
+	PyObject *checker;
+
+	assert(Proxy_Check(self));
+	object = Proxy_GetObject(self);
+	checker = Proxy_GetChecker(self);
+
+	if (check(checker, "__coerce__", object)) {
+		PyObject *left = object;
+		PyObject *right = other;
+		int r;
+		r = PyNumber_CoerceEx(&left, &right);
+		if (r != 0)
+			return r;
+		/* Now left and right have been INCREF'ed.
+		   Any new value that comes out is proxied;
+		   any unchanged value is left unchanged. */
+		if (left == object) {
+			/* Keep the old proxy */
+			Py_DECREF(left);
+			Py_INCREF(self);
+			left = self;
+		}
+		else {
+			left = PyObject_CallMethod(checker, "proxy",
+						   "(N)", left);
+			if (left == NULL) {
+				Py_DECREF(right);
+				return -1;
+			}
+		}
+		if (right != other) {
+			right = PyObject_CallMethod(checker, "proxy",
+						    "(N)", right);
+			if (right == NULL) {
+				Py_DECREF(left);
+				return -1;
+			}
+		}
+		*p_self = left;
+		*p_other = right;
+		return 0;
+	}
+	return -1;
+}
+
 UNOP(neg, PyNumber_Negative)
 UNOP(pos, PyNumber_Positive)
 UNOP(abs, PyNumber_Absolute)
@@ -375,22 +501,22 @@
 UNOP(oct, call_oct)
 UNOP(hex, call_hex)
 
-#define proxy_inplace_add 0
-#define proxy_inplace_subtract 0
-#define proxy_inplace_multiply 0
-#define proxy_inplace_divide 0
-#define proxy_inplace_remainder 0
-#define proxy_inplace_power 0
-#define proxy_inplace_lshift 0
-#define proxy_inplace_rshift 0
-#define proxy_inplace_and 0
-#define proxy_inplace_xor 0
-#define proxy_inplace_or 0
-
-BINOP(floor_divide, PyNumber_FloorDivide)
-BINOP(true_divide, PyNumber_TrueDivide)
-#define proxy_inplace_floor_divide 0
-#define proxy_inplace_true_divide 0
+INPLACE(add, PyNumber_InPlaceAdd)
+INPLACE(sub, PyNumber_InPlaceSubtract)
+INPLACE(mul, PyNumber_InPlaceMultiply)
+INPLACE(div, PyNumber_InPlaceDivide)
+INPLACE(mod, PyNumber_InPlaceRemainder)
+INPLACE(pow, call_ipow)
+INPLACE(lshift, PyNumber_InPlaceLshift)
+INPLACE(rshift, PyNumber_InPlaceRshift)
+INPLACE(and, PyNumber_InPlaceAnd)
+INPLACE(xor, PyNumber_InPlaceXor)
+INPLACE(or, PyNumber_InPlaceOr)
+
+BINOP(floordiv, PyNumber_FloorDivide)
+BINOP(truediv, PyNumber_TrueDivide)
+INPLACE(floordiv, PyNumber_InPlaceFloorDivide)
+INPLACE(truediv, PyNumber_InPlaceTrueDivide)
 
 /*
  * Sequence methods.
@@ -484,50 +610,50 @@
 
 static PyNumberMethods
 proxy_as_number = {
-	proxy_add, /* nb_add */
-	proxy_sub, /* nb_subtract */
-	proxy_mul, /* nb_multiply */
-	proxy_div, /* nb_divide */
-	proxy_mod, /* nb_remainder */
-	proxy_divmod, /* nb_divmod */
-	proxy_pow, /* nb_power */
-	proxy_neg, /* nb_negative */
-	proxy_pos, /* nb_positive */
-	proxy_abs, /* nb_absolute */
-	proxy_nonzero, /* nb_nonzero */
-	proxy_invert, /* nb_invert */
-	proxy_lshift, /* nb_lshift */
-	proxy_rshift, /* nb_rshift */
-	proxy_and, /* nb_and */
-	proxy_xor, /* nb_xor */
-	proxy_or, /* nb_or */
-	0, /* nb_coerce */
-	proxy_int, /* nb_int */
-	proxy_long, /* nb_long */
-	proxy_float, /* nb_float */
-	proxy_oct, /* nb_oct */
-	proxy_hex, /* nb_hex */
+	proxy_add,				/* nb_add */
+	proxy_sub,				/* nb_subtract */
+	proxy_mul,				/* nb_multiply */
+	proxy_div,				/* nb_divide */
+	proxy_mod,				/* nb_remainder */
+	proxy_divmod,				/* nb_divmod */
+	proxy_pow,				/* nb_power */
+	proxy_neg,				/* nb_negative */
+	proxy_pos,				/* nb_positive */
+	proxy_abs,				/* nb_absolute */
+	proxy_nonzero,				/* nb_nonzero */
+	proxy_invert,				/* nb_invert */
+	proxy_lshift,				/* nb_lshift */
+	proxy_rshift,				/* nb_rshift */
+	proxy_and,				/* nb_and */
+	proxy_xor,				/* nb_xor */
+	proxy_or,				/* nb_or */
+	proxy_coerce,				/* nb_coerce */
+	proxy_int,				/* nb_int */
+	proxy_long,				/* nb_long */
+	proxy_float,				/* nb_float */
+	proxy_oct,				/* nb_oct */
+	proxy_hex,				/* nb_hex */
 
 	/* Added in release 2.0 */
 	/* These require the Py_TPFLAGS_HAVE_INPLACEOPS flag */
-	proxy_inplace_add, /* nb_inplace_add */
-	proxy_inplace_subtract, /* nb_inplace_subtract */
-	proxy_inplace_multiply, /* nb_inplace_multiply */
-	proxy_inplace_divide, /* nb_inplace_divide */
-	proxy_inplace_remainder, /* nb_inplace_remainder */
-	proxy_inplace_power, /* nb_inplace_power */
-	proxy_inplace_lshift, /* nb_inplace_lshift */
-	proxy_inplace_rshift, /* nb_inplace_rshift */
-	proxy_inplace_and, /* nb_inplace_and */
-	proxy_inplace_xor, /* nb_inplace_xor */
-	proxy_inplace_or, /* nb_inplace_or */
+	proxy_iadd,				/* nb_inplace_add */
+	proxy_isub,				/* nb_inplace_subtract */
+	proxy_imul,				/* nb_inplace_multiply */
+	proxy_idiv,				/* nb_inplace_divide */
+	proxy_imod,				/* nb_inplace_remainder */
+	(ternaryfunc)proxy_ipow,		/* nb_inplace_power */
+	proxy_ilshift,				/* nb_inplace_lshift */
+	proxy_irshift,				/* nb_inplace_rshift */
+	proxy_iand,				/* nb_inplace_and */
+	proxy_ixor,				/* nb_inplace_xor */
+	proxy_ior,				/* nb_inplace_or */
 
 	/* Added in release 2.2 */
 	/* These require the Py_TPFLAGS_HAVE_CLASS flag */
-	proxy_floor_divide, /* nb_floor_divide */
-	proxy_true_divide, /* nb_true_divide */
-	proxy_inplace_floor_divide, /* nb_inplace_floor_divide */
-	proxy_inplace_true_divide, /* nb_inplace_true_divide */
+	proxy_floordiv,				/* nb_floor_divide */
+	proxy_truediv,				/* nb_true_divide */
+	proxy_ifloordiv,			/* nb_inplace_floor_divide */
+	proxy_itruediv,				/* nb_inplace_true_divide */
 };
 
 static PySequenceMethods