From f9585d05f2021b83c7be3aea97ece0288a8bf309 Mon Sep 17 00:00:00 2001 From: stephan-hof Date: Sat, 4 Feb 2017 14:44:58 +0100 Subject: [PATCH] Clean up the __of__method a bit. --- src/Acquisition/_Acquisition.c | 84 ++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/Acquisition/_Acquisition.c b/src/Acquisition/_Acquisition.c index a4d247a..3b65061 100644 --- a/src/Acquisition/_Acquisition.c +++ b/src/Acquisition/_Acquisition.c @@ -181,8 +181,14 @@ static PyExtensionClass Wrappertype, XaqWrappertype; #define isWrapper(o) (isImplicitWrapper(o) || isExplicitWrapper(o)) +/* Same as isWrapper but does a check for NULL pointer. */ +#define XisWrapper(o) ((o) ? isWrapper(o) : 0) + #define WRAPPER(O) ((Wrapper*)(O)) +#define newWrapper(obj, container, Wrappertype) \ + PyObject_CallFunctionObjArgs(OBJECT(Wrappertype), obj, container, NULL) + static int Wrapper__init__(Wrapper *self, PyObject *args, PyObject *kwargs) { @@ -216,48 +222,49 @@ Wrapper__init__(Wrapper *self, PyObject *args, PyObject *kwargs) /* ---------------------------------------------------------------- */ +/* Creates a new Wrapper object with the values from the old one. + * Steals a reference from 'ob' (also in the error case). + * Returns a new reference. + * Returns NULL on error. + */ +static PyObject * +clone_wrapper(Wrapper *ob) +{ + PyObject *tmp; + + /* Only clone if its shared with others. */ + if (Py_REFCNT(ob) == 1) { + return (PyObject*) ob; + } + + tmp = newWrapper(ob->obj, ob->container, Py_TYPE(ob)); + Py_DECREF(ob); + return tmp; +} + static PyObject * __of__(PyObject *inst, PyObject *parent) { - PyObject *r, *t; - - UNLESS(r=PyObject_GetAttr(inst, py__of__)) return NULL; - UNLESS(t=PyTuple_New(1)) goto err; - Py_INCREF(parent); - PyTuple_SET_ITEM(t,0,parent); - ASSIGN(r,PyObject_CallObject(r,t)); - Py_DECREF(t); - - if (r != NULL - && isWrapper(r) - && WRAPPER(r)->container && isWrapper(WRAPPER(r)->container) - ) - while (WRAPPER(r)->obj && isWrapper(WRAPPER(r)->obj) - && (WRAPPER(WRAPPER(r)->obj)->container == - WRAPPER(WRAPPER(r)->container)->obj) - ) - { - if (r->ob_refcnt !=1 ) - { - t = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(r), - WRAPPER(r)->obj, - WRAPPER(r)->container, - NULL); - Py_DECREF(r); - if (t==NULL) - return NULL; - r = t; - } + PyObject *result; + result = PyObject_CallMethodObjArgs(inst, py__of__, parent, NULL); - /* Simplify wrapper */ - Py_XINCREF(WRAPPER(WRAPPER(r)->obj)->obj); - ASSIGN(WRAPPER(r)->obj, WRAPPER(WRAPPER(r)->obj)->obj); - } + if (XisWrapper(result) && XisWrapper(WRAPPER(result)->container)) { + while (XisWrapper(WRAPPER(result)->obj) && + (WRAPPER(WRAPPER(result)->obj)->container == + WRAPPER(WRAPPER(result)->container)->obj)) { - return r; -err: - Py_DECREF(r); - return NULL; + /* Copy it, because the result could be shared with others. */ + if ((result = clone_wrapper(WRAPPER(result))) == NULL) { + return NULL; + } + + /* Simplify wrapper */ + Py_XINCREF(WRAPPER(WRAPPER(result)->obj)->obj); + ASSIGN(WRAPPER(result)->obj, WRAPPER(WRAPPER(result)->obj)->obj); + } + } + + return result; } static PyObject * @@ -274,9 +281,6 @@ Wrapper_descrget(Wrapper *self, PyObject *inst, PyObject *cls) } -#define newWrapper(obj, container, Wrappertype) \ - PyObject_CallFunctionObjArgs(OBJECT(Wrappertype), obj, container, NULL) - static int Wrapper_traverse(Wrapper *self, visitproc visit, void *arg)