]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.10/Objects/weakrefobject.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.10 / Objects / weakrefobject.c
CommitLineData
53b2ba57
DM
1#include "Python.h"\r
2#include "structmember.h"\r
3\r
4\r
5#define GET_WEAKREFS_LISTPTR(o) \\r
6 ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))\r
7\r
8\r
9Py_ssize_t\r
10_PyWeakref_GetWeakrefCount(PyWeakReference *head)\r
11{\r
12 Py_ssize_t count = 0;\r
13\r
14 while (head != NULL) {\r
15 ++count;\r
16 head = head->wr_next;\r
17 }\r
18 return count;\r
19}\r
20\r
21\r
22static void\r
23init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)\r
24{\r
25 self->hash = -1;\r
26 self->wr_object = ob;\r
27 Py_XINCREF(callback);\r
28 self->wr_callback = callback;\r
29}\r
30\r
31static PyWeakReference *\r
32new_weakref(PyObject *ob, PyObject *callback)\r
33{\r
34 PyWeakReference *result;\r
35\r
36 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);\r
37 if (result) {\r
38 init_weakref(result, ob, callback);\r
39 PyObject_GC_Track(result);\r
40 }\r
41 return result;\r
42}\r
43\r
44\r
45/* This function clears the passed-in reference and removes it from the\r
46 * list of weak references for the referent. This is the only code that\r
47 * removes an item from the doubly-linked list of weak references for an\r
48 * object; it is also responsible for clearing the callback slot.\r
49 */\r
50static void\r
51clear_weakref(PyWeakReference *self)\r
52{\r
53 PyObject *callback = self->wr_callback;\r
54\r
55 if (self->wr_object != Py_None) {\r
56 PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);\r
57\r
58 if (*list == self)\r
59 /* If 'self' is the end of the list (and thus self->wr_next == NULL)\r
60 then the weakref list itself (and thus the value of *list) will\r
61 end up being set to NULL. */\r
62 *list = self->wr_next;\r
63 self->wr_object = Py_None;\r
64 if (self->wr_prev != NULL)\r
65 self->wr_prev->wr_next = self->wr_next;\r
66 if (self->wr_next != NULL)\r
67 self->wr_next->wr_prev = self->wr_prev;\r
68 self->wr_prev = NULL;\r
69 self->wr_next = NULL;\r
70 }\r
71 if (callback != NULL) {\r
72 Py_DECREF(callback);\r
73 self->wr_callback = NULL;\r
74 }\r
75}\r
76\r
77/* Cyclic gc uses this to *just* clear the passed-in reference, leaving\r
78 * the callback intact and uncalled. It must be possible to call self's\r
79 * tp_dealloc() after calling this, so self has to be left in a sane enough\r
80 * state for that to work. We expect tp_dealloc to decref the callback\r
81 * then. The reason for not letting clear_weakref() decref the callback\r
82 * right now is that if the callback goes away, that may in turn trigger\r
83 * another callback (if a weak reference to the callback exists) -- running\r
84 * arbitrary Python code in the middle of gc is a disaster. The convolution\r
85 * here allows gc to delay triggering such callbacks until the world is in\r
86 * a sane state again.\r
87 */\r
88void\r
89_PyWeakref_ClearRef(PyWeakReference *self)\r
90{\r
91 PyObject *callback;\r
92\r
93 assert(self != NULL);\r
94 assert(PyWeakref_Check(self));\r
95 /* Preserve and restore the callback around clear_weakref. */\r
96 callback = self->wr_callback;\r
97 self->wr_callback = NULL;\r
98 clear_weakref(self);\r
99 self->wr_callback = callback;\r
100}\r
101\r
102static void\r
103weakref_dealloc(PyObject *self)\r
104{\r
105 PyObject_GC_UnTrack(self);\r
106 clear_weakref((PyWeakReference *) self);\r
107 Py_TYPE(self)->tp_free(self);\r
108}\r
109\r
110\r
111static int\r
112gc_traverse(PyWeakReference *self, visitproc visit, void *arg)\r
113{\r
114 Py_VISIT(self->wr_callback);\r
115 return 0;\r
116}\r
117\r
118\r
119static int\r
120gc_clear(PyWeakReference *self)\r
121{\r
122 clear_weakref(self);\r
123 return 0;\r
124}\r
125\r
126\r
127static PyObject *\r
128weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)\r
129{\r
130 static char *kwlist[] = {NULL};\r
131\r
132 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {\r
133 PyObject *object = PyWeakref_GET_OBJECT(self);\r
134 Py_INCREF(object);\r
135 return (object);\r
136 }\r
137 return NULL;\r
138}\r
139\r
140\r
141static long\r
142weakref_hash(PyWeakReference *self)\r
143{\r
144 if (self->hash != -1)\r
145 return self->hash;\r
146 if (PyWeakref_GET_OBJECT(self) == Py_None) {\r
147 PyErr_SetString(PyExc_TypeError, "weak object has gone away");\r
148 return -1;\r
149 }\r
150 self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));\r
151 return self->hash;\r
152}\r
153\r
154\r
155static PyObject *\r
156weakref_repr(PyWeakReference *self)\r
157{\r
158 char buffer[256];\r
159 if (PyWeakref_GET_OBJECT(self) == Py_None) {\r
160 PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self);\r
161 }\r
162 else {\r
163 char *name = NULL;\r
164 PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self),\r
165 "__name__");\r
166 if (nameobj == NULL)\r
167 PyErr_Clear();\r
168 else if (PyString_Check(nameobj))\r
169 name = PyString_AS_STRING(nameobj);\r
170 if (name != NULL) {\r
171 PyOS_snprintf(buffer, sizeof(buffer),\r
172 "<weakref at %p; to '%.50s' at %p (%s)>",\r
173 self,\r
174 Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,\r
175 PyWeakref_GET_OBJECT(self),\r
176 name);\r
177 }\r
178 else {\r
179 PyOS_snprintf(buffer, sizeof(buffer),\r
180 "<weakref at %p; to '%.50s' at %p>",\r
181 self,\r
182 Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,\r
183 PyWeakref_GET_OBJECT(self));\r
184 }\r
185 Py_XDECREF(nameobj);\r
186 }\r
187 return PyString_FromString(buffer);\r
188}\r
189\r
190/* Weak references only support equality, not ordering. Two weak references\r
191 are equal if the underlying objects are equal. If the underlying object has\r
192 gone away, they are equal if they are identical. */\r
193\r
194static PyObject *\r
195weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)\r
196{\r
197 if ((op != Py_EQ && op != Py_NE) || self->ob_type != other->ob_type) {\r
198 Py_INCREF(Py_NotImplemented);\r
199 return Py_NotImplemented;\r
200 }\r
201 if (PyWeakref_GET_OBJECT(self) == Py_None\r
202 || PyWeakref_GET_OBJECT(other) == Py_None) {\r
203 int res = (self == other);\r
204 if (op == Py_NE)\r
205 res = !res;\r
206 if (res)\r
207 Py_RETURN_TRUE;\r
208 else\r
209 Py_RETURN_FALSE;\r
210 }\r
211 return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),\r
212 PyWeakref_GET_OBJECT(other), op);\r
213}\r
214\r
215/* Given the head of an object's list of weak references, extract the\r
216 * two callback-less refs (ref and proxy). Used to determine if the\r
217 * shared references exist and to determine the back link for newly\r
218 * inserted references.\r
219 */\r
220static void\r
221get_basic_refs(PyWeakReference *head,\r
222 PyWeakReference **refp, PyWeakReference **proxyp)\r
223{\r
224 *refp = NULL;\r
225 *proxyp = NULL;\r
226\r
227 if (head != NULL && head->wr_callback == NULL) {\r
228 /* We need to be careful that the "basic refs" aren't\r
229 subclasses of the main types. That complicates this a\r
230 little. */\r
231 if (PyWeakref_CheckRefExact(head)) {\r
232 *refp = head;\r
233 head = head->wr_next;\r
234 }\r
235 if (head != NULL\r
236 && head->wr_callback == NULL\r
237 && PyWeakref_CheckProxy(head)) {\r
238 *proxyp = head;\r
239 /* head = head->wr_next; */\r
240 }\r
241 }\r
242}\r
243\r
244/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */\r
245static void\r
246insert_after(PyWeakReference *newref, PyWeakReference *prev)\r
247{\r
248 newref->wr_prev = prev;\r
249 newref->wr_next = prev->wr_next;\r
250 if (prev->wr_next != NULL)\r
251 prev->wr_next->wr_prev = newref;\r
252 prev->wr_next = newref;\r
253}\r
254\r
255/* Insert 'newref' at the head of the list; 'list' points to the variable\r
256 * that stores the head.\r
257 */\r
258static void\r
259insert_head(PyWeakReference *newref, PyWeakReference **list)\r
260{\r
261 PyWeakReference *next = *list;\r
262\r
263 newref->wr_prev = NULL;\r
264 newref->wr_next = next;\r
265 if (next != NULL)\r
266 next->wr_prev = newref;\r
267 *list = newref;\r
268}\r
269\r
270static int\r
271parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,\r
272 PyObject **obp, PyObject **callbackp)\r
273{\r
274 /* XXX Should check that kwargs == NULL or is empty. */\r
275 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);\r
276}\r
277\r
278static PyObject *\r
279weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)\r
280{\r
281 PyWeakReference *self = NULL;\r
282 PyObject *ob, *callback = NULL;\r
283\r
284 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {\r
285 PyWeakReference *ref, *proxy;\r
286 PyWeakReference **list;\r
287\r
288 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {\r
289 PyErr_Format(PyExc_TypeError,\r
290 "cannot create weak reference to '%s' object",\r
291 Py_TYPE(ob)->tp_name);\r
292 return NULL;\r
293 }\r
294 if (callback == Py_None)\r
295 callback = NULL;\r
296 list = GET_WEAKREFS_LISTPTR(ob);\r
297 get_basic_refs(*list, &ref, &proxy);\r
298 if (callback == NULL && type == &_PyWeakref_RefType) {\r
299 if (ref != NULL) {\r
300 /* We can re-use an existing reference. */\r
301 Py_INCREF(ref);\r
302 return (PyObject *)ref;\r
303 }\r
304 }\r
305 /* We have to create a new reference. */\r
306 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref\r
307 list on ob can be mutated. This means that the ref and\r
308 proxy pointers we got back earlier may have been collected,\r
309 so we need to compute these values again before we use\r
310 them. */\r
311 self = (PyWeakReference *) (type->tp_alloc(type, 0));\r
312 if (self != NULL) {\r
313 init_weakref(self, ob, callback);\r
314 if (callback == NULL && type == &_PyWeakref_RefType) {\r
315 insert_head(self, list);\r
316 }\r
317 else {\r
318 PyWeakReference *prev;\r
319\r
320 get_basic_refs(*list, &ref, &proxy);\r
321 prev = (proxy == NULL) ? ref : proxy;\r
322 if (prev == NULL)\r
323 insert_head(self, list);\r
324 else\r
325 insert_after(self, prev);\r
326 }\r
327 }\r
328 }\r
329 return (PyObject *)self;\r
330}\r
331\r
332static int\r
333weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)\r
334{\r
335 PyObject *tmp;\r
336\r
337 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))\r
338 return 0;\r
339 else\r
340 return -1;\r
341}\r
342\r
343\r
344PyTypeObject\r
345_PyWeakref_RefType = {\r
346 PyVarObject_HEAD_INIT(&PyType_Type, 0)\r
347 "weakref",\r
348 sizeof(PyWeakReference),\r
349 0,\r
350 weakref_dealloc, /*tp_dealloc*/\r
351 0, /*tp_print*/\r
352 0, /*tp_getattr*/\r
353 0, /*tp_setattr*/\r
354 0, /*tp_compare*/\r
355 (reprfunc)weakref_repr, /*tp_repr*/\r
356 0, /*tp_as_number*/\r
357 0, /*tp_as_sequence*/\r
358 0, /*tp_as_mapping*/\r
359 (hashfunc)weakref_hash, /*tp_hash*/\r
360 (ternaryfunc)weakref_call, /*tp_call*/\r
361 0, /*tp_str*/\r
362 0, /*tp_getattro*/\r
363 0, /*tp_setattro*/\r
364 0, /*tp_as_buffer*/\r
365 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE\r
366 | Py_TPFLAGS_BASETYPE, /*tp_flags*/\r
367 0, /*tp_doc*/\r
368 (traverseproc)gc_traverse, /*tp_traverse*/\r
369 (inquiry)gc_clear, /*tp_clear*/\r
370 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/\r
371 0, /*tp_weaklistoffset*/\r
372 0, /*tp_iter*/\r
373 0, /*tp_iternext*/\r
374 0, /*tp_methods*/\r
375 0, /*tp_members*/\r
376 0, /*tp_getset*/\r
377 0, /*tp_base*/\r
378 0, /*tp_dict*/\r
379 0, /*tp_descr_get*/\r
380 0, /*tp_descr_set*/\r
381 0, /*tp_dictoffset*/\r
382 weakref___init__, /*tp_init*/\r
383 PyType_GenericAlloc, /*tp_alloc*/\r
384 weakref___new__, /*tp_new*/\r
385 PyObject_GC_Del, /*tp_free*/\r
386};\r
387\r
388\r
389static int\r
390proxy_checkref(PyWeakReference *proxy)\r
391{\r
392 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {\r
393 PyErr_SetString(PyExc_ReferenceError,\r
394 "weakly-referenced object no longer exists");\r
395 return 0;\r
396 }\r
397 return 1;\r
398}\r
399\r
400\r
401/* If a parameter is a proxy, check that it is still "live" and wrap it,\r
402 * replacing the original value with the raw object. Raises ReferenceError\r
403 * if the param is a dead proxy.\r
404 */\r
405#define UNWRAP(o) \\r
406 if (PyWeakref_CheckProxy(o)) { \\r
407 if (!proxy_checkref((PyWeakReference *)o)) \\r
408 return NULL; \\r
409 o = PyWeakref_GET_OBJECT(o); \\r
410 }\r
411\r
412#define UNWRAP_I(o) \\r
413 if (PyWeakref_CheckProxy(o)) { \\r
414 if (!proxy_checkref((PyWeakReference *)o)) \\r
415 return -1; \\r
416 o = PyWeakref_GET_OBJECT(o); \\r
417 }\r
418\r
419#define WRAP_UNARY(method, generic) \\r
420 static PyObject * \\r
421 method(PyObject *proxy) { \\r
422 UNWRAP(proxy); \\r
423 return generic(proxy); \\r
424 }\r
425\r
426#define WRAP_BINARY(method, generic) \\r
427 static PyObject * \\r
428 method(PyObject *x, PyObject *y) { \\r
429 UNWRAP(x); \\r
430 UNWRAP(y); \\r
431 return generic(x, y); \\r
432 }\r
433\r
434/* Note that the third arg needs to be checked for NULL since the tp_call\r
435 * slot can receive NULL for this arg.\r
436 */\r
437#define WRAP_TERNARY(method, generic) \\r
438 static PyObject * \\r
439 method(PyObject *proxy, PyObject *v, PyObject *w) { \\r
440 UNWRAP(proxy); \\r
441 UNWRAP(v); \\r
442 if (w != NULL) \\r
443 UNWRAP(w); \\r
444 return generic(proxy, v, w); \\r
445 }\r
446\r
447#define WRAP_METHOD(method, special) \\r
448 static PyObject * \\r
449 method(PyObject *proxy) { \\r
450 UNWRAP(proxy); \\r
451 return PyObject_CallMethod(proxy, special, ""); \\r
452 }\r
453\r
454\r
455/* direct slots */\r
456\r
457WRAP_BINARY(proxy_getattr, PyObject_GetAttr)\r
458WRAP_UNARY(proxy_str, PyObject_Str)\r
459WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)\r
460\r
461static PyObject *\r
462proxy_repr(PyWeakReference *proxy)\r
463{\r
464 char buf[160];\r
465 PyOS_snprintf(buf, sizeof(buf),\r
466 "<weakproxy at %p to %.100s at %p>", proxy,\r
467 Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,\r
468 PyWeakref_GET_OBJECT(proxy));\r
469 return PyString_FromString(buf);\r
470}\r
471\r
472\r
473static int\r
474proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)\r
475{\r
476 if (!proxy_checkref(proxy))\r
477 return -1;\r
478 return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);\r
479}\r
480\r
481static int\r
482proxy_compare(PyObject *proxy, PyObject *v)\r
483{\r
484 UNWRAP_I(proxy);\r
485 UNWRAP_I(v);\r
486 return PyObject_Compare(proxy, v);\r
487}\r
488\r
489/* number slots */\r
490WRAP_BINARY(proxy_add, PyNumber_Add)\r
491WRAP_BINARY(proxy_sub, PyNumber_Subtract)\r
492WRAP_BINARY(proxy_mul, PyNumber_Multiply)\r
493WRAP_BINARY(proxy_div, PyNumber_Divide)\r
494WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)\r
495WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)\r
496WRAP_BINARY(proxy_mod, PyNumber_Remainder)\r
497WRAP_BINARY(proxy_divmod, PyNumber_Divmod)\r
498WRAP_TERNARY(proxy_pow, PyNumber_Power)\r
499WRAP_UNARY(proxy_neg, PyNumber_Negative)\r
500WRAP_UNARY(proxy_pos, PyNumber_Positive)\r
501WRAP_UNARY(proxy_abs, PyNumber_Absolute)\r
502WRAP_UNARY(proxy_invert, PyNumber_Invert)\r
503WRAP_BINARY(proxy_lshift, PyNumber_Lshift)\r
504WRAP_BINARY(proxy_rshift, PyNumber_Rshift)\r
505WRAP_BINARY(proxy_and, PyNumber_And)\r
506WRAP_BINARY(proxy_xor, PyNumber_Xor)\r
507WRAP_BINARY(proxy_or, PyNumber_Or)\r
508WRAP_UNARY(proxy_int, PyNumber_Int)\r
509WRAP_UNARY(proxy_long, PyNumber_Long)\r
510WRAP_UNARY(proxy_float, PyNumber_Float)\r
511WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)\r
512WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)\r
513WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)\r
514WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide)\r
515WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)\r
516WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)\r
517WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)\r
518WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)\r
519WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)\r
520WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)\r
521WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)\r
522WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)\r
523WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)\r
524WRAP_UNARY(proxy_index, PyNumber_Index)\r
525\r
526static int\r
527proxy_nonzero(PyWeakReference *proxy)\r
528{\r
529 PyObject *o = PyWeakref_GET_OBJECT(proxy);\r
530 if (!proxy_checkref(proxy))\r
531 return -1;\r
532 return PyObject_IsTrue(o);\r
533}\r
534\r
535static void\r
536proxy_dealloc(PyWeakReference *self)\r
537{\r
538 if (self->wr_callback != NULL)\r
539 PyObject_GC_UnTrack((PyObject *)self);\r
540 clear_weakref(self);\r
541 PyObject_GC_Del(self);\r
542}\r
543\r
544/* sequence slots */\r
545\r
546static PyObject *\r
547proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j)\r
548{\r
549 if (!proxy_checkref(proxy))\r
550 return NULL;\r
551 return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j);\r
552}\r
553\r
554static int\r
555proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value)\r
556{\r
557 if (!proxy_checkref(proxy))\r
558 return -1;\r
559 return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value);\r
560}\r
561\r
562static int\r
563proxy_contains(PyWeakReference *proxy, PyObject *value)\r
564{\r
565 if (!proxy_checkref(proxy))\r
566 return -1;\r
567 return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);\r
568}\r
569\r
570\r
571/* mapping slots */\r
572\r
573static Py_ssize_t\r
574proxy_length(PyWeakReference *proxy)\r
575{\r
576 if (!proxy_checkref(proxy))\r
577 return -1;\r
578 return PyObject_Length(PyWeakref_GET_OBJECT(proxy));\r
579}\r
580\r
581WRAP_BINARY(proxy_getitem, PyObject_GetItem)\r
582\r
583static int\r
584proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)\r
585{\r
586 if (!proxy_checkref(proxy))\r
587 return -1;\r
588\r
589 if (value == NULL)\r
590 return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);\r
591 else\r
592 return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);\r
593}\r
594\r
595/* iterator slots */\r
596\r
597static PyObject *\r
598proxy_iter(PyWeakReference *proxy)\r
599{\r
600 if (!proxy_checkref(proxy))\r
601 return NULL;\r
602 return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));\r
603}\r
604\r
605static PyObject *\r
606proxy_iternext(PyWeakReference *proxy)\r
607{\r
608 if (!proxy_checkref(proxy))\r
609 return NULL;\r
610 return PyIter_Next(PyWeakref_GET_OBJECT(proxy));\r
611}\r
612\r
613\r
614WRAP_METHOD(proxy_unicode, "__unicode__");\r
615\r
616\r
617static PyMethodDef proxy_methods[] = {\r
618 {"__unicode__", (PyCFunction)proxy_unicode, METH_NOARGS},\r
619 {NULL, NULL}\r
620};\r
621\r
622\r
623static PyNumberMethods proxy_as_number = {\r
624 proxy_add, /*nb_add*/\r
625 proxy_sub, /*nb_subtract*/\r
626 proxy_mul, /*nb_multiply*/\r
627 proxy_div, /*nb_divide*/\r
628 proxy_mod, /*nb_remainder*/\r
629 proxy_divmod, /*nb_divmod*/\r
630 proxy_pow, /*nb_power*/\r
631 proxy_neg, /*nb_negative*/\r
632 proxy_pos, /*nb_positive*/\r
633 proxy_abs, /*nb_absolute*/\r
634 (inquiry)proxy_nonzero, /*nb_nonzero*/\r
635 proxy_invert, /*nb_invert*/\r
636 proxy_lshift, /*nb_lshift*/\r
637 proxy_rshift, /*nb_rshift*/\r
638 proxy_and, /*nb_and*/\r
639 proxy_xor, /*nb_xor*/\r
640 proxy_or, /*nb_or*/\r
641 0, /*nb_coerce*/\r
642 proxy_int, /*nb_int*/\r
643 proxy_long, /*nb_long*/\r
644 proxy_float, /*nb_float*/\r
645 0, /*nb_oct*/\r
646 0, /*nb_hex*/\r
647 proxy_iadd, /*nb_inplace_add*/\r
648 proxy_isub, /*nb_inplace_subtract*/\r
649 proxy_imul, /*nb_inplace_multiply*/\r
650 proxy_idiv, /*nb_inplace_divide*/\r
651 proxy_imod, /*nb_inplace_remainder*/\r
652 proxy_ipow, /*nb_inplace_power*/\r
653 proxy_ilshift, /*nb_inplace_lshift*/\r
654 proxy_irshift, /*nb_inplace_rshift*/\r
655 proxy_iand, /*nb_inplace_and*/\r
656 proxy_ixor, /*nb_inplace_xor*/\r
657 proxy_ior, /*nb_inplace_or*/\r
658 proxy_floor_div, /*nb_floor_divide*/\r
659 proxy_true_div, /*nb_true_divide*/\r
660 proxy_ifloor_div, /*nb_inplace_floor_divide*/\r
661 proxy_itrue_div, /*nb_inplace_true_divide*/\r
662 proxy_index, /*nb_index*/\r
663};\r
664\r
665static PySequenceMethods proxy_as_sequence = {\r
666 (lenfunc)proxy_length, /*sq_length*/\r
667 0, /*sq_concat*/\r
668 0, /*sq_repeat*/\r
669 0, /*sq_item*/\r
670 (ssizessizeargfunc)proxy_slice, /*sq_slice*/\r
671 0, /*sq_ass_item*/\r
672 (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/\r
673 (objobjproc)proxy_contains, /* sq_contains */\r
674};\r
675\r
676static PyMappingMethods proxy_as_mapping = {\r
677 (lenfunc)proxy_length, /*mp_length*/\r
678 proxy_getitem, /*mp_subscript*/\r
679 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/\r
680};\r
681\r
682\r
683PyTypeObject\r
684_PyWeakref_ProxyType = {\r
685 PyVarObject_HEAD_INIT(&PyType_Type, 0)\r
686 "weakproxy",\r
687 sizeof(PyWeakReference),\r
688 0,\r
689 /* methods */\r
690 (destructor)proxy_dealloc, /* tp_dealloc */\r
691 0, /* tp_print */\r
692 0, /* tp_getattr */\r
693 0, /* tp_setattr */\r
694 proxy_compare, /* tp_compare */\r
695 (reprfunc)proxy_repr, /* tp_repr */\r
696 &proxy_as_number, /* tp_as_number */\r
697 &proxy_as_sequence, /* tp_as_sequence */\r
698 &proxy_as_mapping, /* tp_as_mapping */\r
699 0, /* tp_hash */\r
700 0, /* tp_call */\r
701 proxy_str, /* tp_str */\r
702 proxy_getattr, /* tp_getattro */\r
703 (setattrofunc)proxy_setattr, /* tp_setattro */\r
704 0, /* tp_as_buffer */\r
705 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC\r
706 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */\r
707 0, /* tp_doc */\r
708 (traverseproc)gc_traverse, /* tp_traverse */\r
709 (inquiry)gc_clear, /* tp_clear */\r
710 0, /* tp_richcompare */\r
711 0, /* tp_weaklistoffset */\r
712 (getiterfunc)proxy_iter, /* tp_iter */\r
713 (iternextfunc)proxy_iternext, /* tp_iternext */\r
714 proxy_methods, /* tp_methods */\r
715};\r
716\r
717\r
718PyTypeObject\r
719_PyWeakref_CallableProxyType = {\r
720 PyVarObject_HEAD_INIT(&PyType_Type, 0)\r
721 "weakcallableproxy",\r
722 sizeof(PyWeakReference),\r
723 0,\r
724 /* methods */\r
725 (destructor)proxy_dealloc, /* tp_dealloc */\r
726 0, /* tp_print */\r
727 0, /* tp_getattr */\r
728 0, /* tp_setattr */\r
729 proxy_compare, /* tp_compare */\r
730 (unaryfunc)proxy_repr, /* tp_repr */\r
731 &proxy_as_number, /* tp_as_number */\r
732 &proxy_as_sequence, /* tp_as_sequence */\r
733 &proxy_as_mapping, /* tp_as_mapping */\r
734 0, /* tp_hash */\r
735 proxy_call, /* tp_call */\r
736 proxy_str, /* tp_str */\r
737 proxy_getattr, /* tp_getattro */\r
738 (setattrofunc)proxy_setattr, /* tp_setattro */\r
739 0, /* tp_as_buffer */\r
740 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC\r
741 | Py_TPFLAGS_CHECKTYPES, /* tp_flags */\r
742 0, /* tp_doc */\r
743 (traverseproc)gc_traverse, /* tp_traverse */\r
744 (inquiry)gc_clear, /* tp_clear */\r
745 0, /* tp_richcompare */\r
746 0, /* tp_weaklistoffset */\r
747 (getiterfunc)proxy_iter, /* tp_iter */\r
748 (iternextfunc)proxy_iternext, /* tp_iternext */\r
749};\r
750\r
751\r
752\r
753PyObject *\r
754PyWeakref_NewRef(PyObject *ob, PyObject *callback)\r
755{\r
756 PyWeakReference *result = NULL;\r
757 PyWeakReference **list;\r
758 PyWeakReference *ref, *proxy;\r
759\r
760 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {\r
761 PyErr_Format(PyExc_TypeError,\r
762 "cannot create weak reference to '%s' object",\r
763 Py_TYPE(ob)->tp_name);\r
764 return NULL;\r
765 }\r
766 list = GET_WEAKREFS_LISTPTR(ob);\r
767 get_basic_refs(*list, &ref, &proxy);\r
768 if (callback == Py_None)\r
769 callback = NULL;\r
770 if (callback == NULL)\r
771 /* return existing weak reference if it exists */\r
772 result = ref;\r
773 if (result != NULL)\r
774 Py_INCREF(result);\r
775 else {\r
776 /* Note: new_weakref() can trigger cyclic GC, so the weakref\r
777 list on ob can be mutated. This means that the ref and\r
778 proxy pointers we got back earlier may have been collected,\r
779 so we need to compute these values again before we use\r
780 them. */\r
781 result = new_weakref(ob, callback);\r
782 if (result != NULL) {\r
783 get_basic_refs(*list, &ref, &proxy);\r
784 if (callback == NULL) {\r
785 if (ref == NULL)\r
786 insert_head(result, list);\r
787 else {\r
788 /* Someone else added a ref without a callback\r
789 during GC. Return that one instead of this one\r
790 to avoid violating the invariants of the list\r
791 of weakrefs for ob. */\r
792 Py_DECREF(result);\r
793 Py_INCREF(ref);\r
794 result = ref;\r
795 }\r
796 }\r
797 else {\r
798 PyWeakReference *prev;\r
799\r
800 prev = (proxy == NULL) ? ref : proxy;\r
801 if (prev == NULL)\r
802 insert_head(result, list);\r
803 else\r
804 insert_after(result, prev);\r
805 }\r
806 }\r
807 }\r
808 return (PyObject *) result;\r
809}\r
810\r
811\r
812PyObject *\r
813PyWeakref_NewProxy(PyObject *ob, PyObject *callback)\r
814{\r
815 PyWeakReference *result = NULL;\r
816 PyWeakReference **list;\r
817 PyWeakReference *ref, *proxy;\r
818\r
819 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {\r
820 PyErr_Format(PyExc_TypeError,\r
821 "cannot create weak reference to '%s' object",\r
822 Py_TYPE(ob)->tp_name);\r
823 return NULL;\r
824 }\r
825 list = GET_WEAKREFS_LISTPTR(ob);\r
826 get_basic_refs(*list, &ref, &proxy);\r
827 if (callback == Py_None)\r
828 callback = NULL;\r
829 if (callback == NULL)\r
830 /* attempt to return an existing weak reference if it exists */\r
831 result = proxy;\r
832 if (result != NULL)\r
833 Py_INCREF(result);\r
834 else {\r
835 /* Note: new_weakref() can trigger cyclic GC, so the weakref\r
836 list on ob can be mutated. This means that the ref and\r
837 proxy pointers we got back earlier may have been collected,\r
838 so we need to compute these values again before we use\r
839 them. */\r
840 result = new_weakref(ob, callback);\r
841 if (result != NULL) {\r
842 PyWeakReference *prev;\r
843\r
844 if (PyCallable_Check(ob))\r
845 Py_TYPE(result) = &_PyWeakref_CallableProxyType;\r
846 else\r
847 Py_TYPE(result) = &_PyWeakref_ProxyType;\r
848 get_basic_refs(*list, &ref, &proxy);\r
849 if (callback == NULL) {\r
850 if (proxy != NULL) {\r
851 /* Someone else added a proxy without a callback\r
852 during GC. Return that one instead of this one\r
853 to avoid violating the invariants of the list\r
854 of weakrefs for ob. */\r
855 Py_DECREF(result);\r
856 Py_INCREF(result = proxy);\r
857 goto skip_insert;\r
858 }\r
859 prev = ref;\r
860 }\r
861 else\r
862 prev = (proxy == NULL) ? ref : proxy;\r
863\r
864 if (prev == NULL)\r
865 insert_head(result, list);\r
866 else\r
867 insert_after(result, prev);\r
868 skip_insert:\r
869 ;\r
870 }\r
871 }\r
872 return (PyObject *) result;\r
873}\r
874\r
875\r
876PyObject *\r
877PyWeakref_GetObject(PyObject *ref)\r
878{\r
879 if (ref == NULL || !PyWeakref_Check(ref)) {\r
880 PyErr_BadInternalCall();\r
881 return NULL;\r
882 }\r
883 return PyWeakref_GET_OBJECT(ref);\r
884}\r
885\r
886/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's\r
887 * handle_weakrefs().\r
888 */\r
889static void\r
890handle_callback(PyWeakReference *ref, PyObject *callback)\r
891{\r
892 PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);\r
893\r
894 if (cbresult == NULL)\r
895 PyErr_WriteUnraisable(callback);\r
896 else\r
897 Py_DECREF(cbresult);\r
898}\r
899\r
900/* This function is called by the tp_dealloc handler to clear weak references.\r
901 *\r
902 * This iterates through the weak references for 'object' and calls callbacks\r
903 * for those references which have one. It returns when all callbacks have\r
904 * been attempted.\r
905 */\r
906void\r
907PyObject_ClearWeakRefs(PyObject *object)\r
908{\r
909 PyWeakReference **list;\r
910\r
911 if (object == NULL\r
912 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))\r
913 || object->ob_refcnt != 0) {\r
914 PyErr_BadInternalCall();\r
915 return;\r
916 }\r
917 list = GET_WEAKREFS_LISTPTR(object);\r
918 /* Remove the callback-less basic and proxy references */\r
919 if (*list != NULL && (*list)->wr_callback == NULL) {\r
920 clear_weakref(*list);\r
921 if (*list != NULL && (*list)->wr_callback == NULL)\r
922 clear_weakref(*list);\r
923 }\r
924 if (*list != NULL) {\r
925 PyWeakReference *current = *list;\r
926 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);\r
927 PyObject *err_type, *err_value, *err_tb;\r
928\r
929 PyErr_Fetch(&err_type, &err_value, &err_tb);\r
930 if (count == 1) {\r
931 PyObject *callback = current->wr_callback;\r
932\r
933 current->wr_callback = NULL;\r
934 clear_weakref(current);\r
935 if (callback != NULL) {\r
936 if (current->ob_refcnt > 0)\r
937 handle_callback(current, callback);\r
938 Py_DECREF(callback);\r
939 }\r
940 }\r
941 else {\r
942 PyObject *tuple;\r
943 Py_ssize_t i = 0;\r
944\r
945 tuple = PyTuple_New(count * 2);\r
946 if (tuple == NULL) {\r
947 _PyErr_ReplaceException(err_type, err_value, err_tb);\r
948 return;\r
949 }\r
950\r
951 for (i = 0; i < count; ++i) {\r
952 PyWeakReference *next = current->wr_next;\r
953\r
954 if (current->ob_refcnt > 0)\r
955 {\r
956 Py_INCREF(current);\r
957 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);\r
958 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);\r
959 }\r
960 else {\r
961 Py_DECREF(current->wr_callback);\r
962 }\r
963 current->wr_callback = NULL;\r
964 clear_weakref(current);\r
965 current = next;\r
966 }\r
967 for (i = 0; i < count; ++i) {\r
968 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);\r
969\r
970 /* The tuple may have slots left to NULL */\r
971 if (callback != NULL) {\r
972 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);\r
973 handle_callback((PyWeakReference *)item, callback);\r
974 }\r
975 }\r
976 Py_DECREF(tuple);\r
977 }\r
978 assert(!PyErr_Occurred());\r
979 PyErr_Restore(err_type, err_value, err_tb);\r
980 }\r
981}\r