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