[Zope-Checkins] CVS: Zope3/lib/python/Zope/ContextWrapper - proxy.c:1.1.2.4

Fred L. Drake, Jr. fdrake@acm.org
Fri, 26 Apr 2002 14:52:24 -0400


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

Modified Files:
      Tag: SecurityProxy-branch
	proxy.c 
Log Message:
Port the math ops from Security.Proxy to the base proxy.

=== Zope3/lib/python/Zope/ContextWrapper/proxy.c 1.1.2.3 => 1.1.2.4 ===
  */
 
+/*
+ * Number methods.
+ */
+
+static PyObject *
+call_int(PyObject *self)
+{
+    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");
+        return NULL;
+    }
+    return nb->nb_int(self);
+}
+
+static PyObject *
+call_long(PyObject *self)
+{
+    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");
+        return NULL;
+    }
+    return nb->nb_long(self);
+}
+
+static PyObject *
+call_float(PyObject *self)
+{
+    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");
+        return NULL;
+    }
+    return nb->nb_float(self);
+}
+
+static PyObject *
+call_oct(PyObject *self)
+{
+    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");
+        return NULL;
+    }
+    return nb->nb_oct(self);
+}
+
+static PyObject *
+call_hex(PyObject *self)
+{
+    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");
+        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);
+}
+
+typedef PyObject *(*function1)(PyObject *);
+
+static PyObject *
+check1(ProxyObject *self, char *opname, function1 operation)
+{
+    PyObject *result = NULL;
+
+    result = operation(Proxy_GET_OBJECT(self));
+#if 0
+    if (result != NULL)
+        /* XXX create proxy for result? */
+        ;
+#endif
+    return result;
+}
+
+static PyObject *
+check2(PyObject *self, PyObject *other,
+       char *opname, char *ropname, binaryfunc operation)
+{
+    PyObject *result = NULL;
+    PyObject *object;
+
+    if (Proxy_Check(self)) {
+        object = Proxy_GET_OBJECT(self);
+        result = operation(object, other);
+    }
+    else if (Proxy_Check(other)) {
+        object = Proxy_GET_OBJECT(other);
+        result = operation(self, object);
+    }
+    else {
+        Py_INCREF(Py_NotImplemented);
+        return Py_NotImplemented;
+    }
+#if 0
+    if (result != NULL)
+        /* XXX create proxy for result? */
+        ;
+#endif
+    return result;
+}
+
+static PyObject *
+check2i(ProxyObject *self, PyObject *other,
+	char *opname, binaryfunc operation)
+{
+	PyObject *result = NULL;
+	PyObject *object = Proxy_GET_OBJECT(self);
+
+        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_INCREF(self);
+            Py_DECREF(object);
+            result = (PyObject *)self;
+        }
+#if 0
+        else if (result != NULL)
+            /* XXX create proxy for result? */
+            ;
+#endif
+	return result;
+}
+
+#define UNOP(NAME, CALL) \
+	static PyObject *wrap_##NAME(PyObject *self) \
+	{ return check1((ProxyObject *)self, "__"#NAME"__", CALL); }
+
+#define BINOP(NAME, CALL) \
+	static PyObject *wrap_##NAME(PyObject *self, PyObject *other) \
+	{ return check2(self, other, "__"#NAME"__", "__r"#NAME"__", CALL); }
+
+#define INPLACE(NAME, CALL) \
+	static PyObject *wrap_i##NAME(PyObject *self, PyObject *other) \
+	{ return check2i((ProxyObject *)self, other, "__i"#NAME"__", CALL); }
+
+BINOP(add, PyNumber_Add)
+BINOP(sub, PyNumber_Subtract)
+BINOP(mul, PyNumber_Multiply)
+BINOP(div, PyNumber_Divide)
+BINOP(mod, PyNumber_Remainder)
+BINOP(divmod, PyNumber_Divmod)
+
+static PyObject *
+wrap_pow(PyObject *self, PyObject *other, PyObject *modulus)
+{
+    PyObject *result = NULL;
+    PyObject *object;
+
+    if (Proxy_Check(self)) {
+        object = Proxy_GET_OBJECT(self);
+        result = PyNumber_Power(object, other, modulus);
+    }
+    else if (Proxy_Check(other)) {
+        object = Proxy_GET_OBJECT(other);
+        result = PyNumber_Power(self, object, modulus);
+    }
+    else if (modulus != NULL && Proxy_Check(modulus)) {
+        object = Proxy_GET_OBJECT(modulus);
+        result = PyNumber_Power(self, other, modulus);
+    }
+    else {
+        Py_INCREF(Py_NotImplemented);
+        return Py_NotImplemented;
+    }
+    return result;
+}
+
+BINOP(lshift, PyNumber_Lshift)
+BINOP(rshift, PyNumber_Rshift)
+BINOP(and, PyNumber_And)
+BINOP(xor, PyNumber_Xor)
+BINOP(or, PyNumber_Or)
+
+static int
+wrap_coerce(PyObject **p_self, PyObject **p_other)
+{
+    PyObject *self = *p_self;
+    PyObject *other = *p_other;
+    PyObject *object;
+    PyObject *left;
+    PyObject *right;
+    int r;
+
+    assert(Proxy_Check(self));
+    object = Proxy_GET_OBJECT(self);
+
+    left = object;
+    right = other;
+    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_INCREF(self);
+        Py_DECREF(left);
+        left = self;
+    }
+#if 0
+    else {
+        /* XXX create proxy for left? */
+    }
+    if (right != other) {
+        /* XXX create proxy for right? */
+    }
+#endif
+    *p_self = left;
+    *p_other = right;
+    return 0;
+}
+
+UNOP(neg, PyNumber_Negative)
+UNOP(pos, PyNumber_Positive)
+UNOP(abs, PyNumber_Absolute)
+UNOP(invert, PyNumber_Invert)
+
+UNOP(int, call_int)
+UNOP(long, call_long)
+UNOP(float, call_float)
+UNOP(oct, call_oct)
+UNOP(hex, call_hex)
+
+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)
+
 static int
 wrap_nonzero(PyObject *self)
 {
@@ -227,17 +481,50 @@
 
 static PyNumberMethods
 wrap_as_number = {
-    0,					/* nb_add */
-    0,					/* nb_subtract */
-    0,					/* nb_multiply */
-    0,					/* nb_divide */
-    0,					/* nb_remainder */
-    0,					/* nb_divmod */
-    0,					/* nb_power */
-    0,					/* nb_negative */
-    0,					/* nb_positive */
-    0,					/* nb_absolute */
+    wrap_add,				/* nb_add */
+    wrap_sub,				/* nb_subtract */
+    wrap_mul,				/* nb_multiply */
+    wrap_div,				/* nb_divide */
+    wrap_mod,				/* nb_remainder */
+    wrap_divmod,			/* nb_divmod */
+    wrap_pow,				/* nb_power */
+    wrap_neg,				/* nb_negative */
+    wrap_pos,				/* nb_positive */
+    wrap_abs,				/* nb_absolute */
     wrap_nonzero,			/* nb_nonzero */
+    wrap_invert,			/* nb_invert */
+    wrap_lshift,			/* nb_lshift */
+    wrap_rshift,			/* nb_rshift */
+    wrap_and,				/* nb_and */
+    wrap_xor,				/* nb_xor */
+    wrap_or,				/* nb_or */
+    wrap_coerce,			/* nb_coerce */
+    wrap_int,				/* nb_int */
+    wrap_long,				/* nb_long */
+    wrap_float,				/* nb_float */
+    wrap_oct,				/* nb_oct */
+    wrap_hex,				/* nb_hex */
+
+    /* Added in release 2.0 */
+    /* These require the Py_TPFLAGS_HAVE_INPLACEOPS flag */
+    wrap_iadd,				/* nb_inplace_add */
+    wrap_isub,				/* nb_inplace_subtract */
+    wrap_imul,				/* nb_inplace_multiply */
+    wrap_idiv,				/* nb_inplace_divide */
+    wrap_imod,				/* nb_inplace_remainder */
+    (ternaryfunc)wrap_ipow,		/* nb_inplace_power */
+    wrap_ilshift,			/* nb_inplace_lshift */
+    wrap_irshift,			/* nb_inplace_rshift */
+    wrap_iand,				/* nb_inplace_and */
+    wrap_ixor,				/* nb_inplace_xor */
+    wrap_ior,				/* nb_inplace_or */
+
+    /* Added in release 2.2 */
+    /* These require the Py_TPFLAGS_HAVE_CLASS flag */
+    wrap_floordiv,			/* nb_floor_divide */
+    wrap_truediv,			/* nb_true_divide */
+    wrap_ifloordiv,			/* nb_inplace_floor_divide */
+    wrap_itruediv,			/* nb_inplace_true_divide */
 };
 
 static PySequenceMethods
@@ -298,7 +585,7 @@
     wrap_setattro,			/* tp_setattro */
     0,					/* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC 
-        | Py_TPFLAGS_BASETYPE, /* tp_flags */
+        | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_BASETYPE, /* tp_flags */
     0,					/* tp_doc */
     wrap_traverse,			/* tp_traverse */
     wrap_clear,				/* tp_clear */