Comparison of cyclic objects (was RE: [Python-Dev] trashcan and PR#7)
Jeremy Hylton
jeremy@cnri.reston.va.us
Thu, 13 Apr 2000 19:30:02 -0400 (EDT)
Here it is contextified. One small difference from the previous patch
is that NESTING_LIMIT is now only 1000. I think this is sufficient to
cover commonly occuring nested containers.
Jeremy
Index: Include/object.h
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Include/object.h,v
retrieving revision 2.52
diff -c -r2.52 object.h
*** object.h 2000/03/21 16:14:47 2.52
--- object.h 2000/04/13 21:50:10
***************
*** 284,289 ****
--- 284,292 ----
extern DL_IMPORT(int) Py_ReprEnter Py_PROTO((PyObject *));
extern DL_IMPORT(void) Py_ReprLeave Py_PROTO((PyObject *));
+ /* tstate dict key for PyObject_Compare helper */
+ extern PyObject *_PyCompareState_Key;
+
/* Flag bits for printing: */
#define Py_PRINT_RAW 1 /* No string quotes etc. */
Index: Python/pythonrun.c
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Python/pythonrun.c,v
retrieving revision 2.91
diff -c -r2.91 pythonrun.c
*** pythonrun.c 2000/03/10 23:03:54 2.91
--- pythonrun.c 2000/04/13 21:50:25
***************
*** 149,154 ****
--- 149,156 ----
/* Init Unicode implementation; relies on the codec registry */
_PyUnicode_Init();
+ _PyCompareState_Key = PyString_InternFromString("cmp_state");
+
bimod = _PyBuiltin_Init_1();
if (bimod == NULL)
Py_FatalError("Py_Initialize: can't initialize __builtin__");
Index: Objects/object.c
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Objects/object.c,v
retrieving revision 2.67
diff -c -r2.67 object.c
*** object.c 2000/04/10 13:42:33 2.67
--- object.c 2000/04/13 21:44:42
***************
*** 298,308 ****
--- 298,316 ----
return PyInt_FromLong(c);
}
+ PyObject *_PyCompareState_Key;
+
+ int _PyCompareState_nesting = 0;
+ int _PyCompareState_flag = 0;
+ #define NESTING_LIMIT 1000
+
int
PyObject_Compare(v, w)
PyObject *v, *w;
{
PyTypeObject *vtp, *wtp;
+ int result;
+
if (v == NULL || w == NULL) {
PyErr_BadInternalCall();
return -1;
***************
*** 369,377 ****
/* Numerical types compare smaller than all other types */
return strcmp(vname, wname);
}
! if (vtp->tp_compare == NULL)
return (v < w) ? -1 : 1;
! return (*vtp->tp_compare)(v, w);
}
long
--- 377,443 ----
/* Numerical types compare smaller than all other types */
return strcmp(vname, wname);
}
! if (vtp->tp_compare == NULL) {
return (v < w) ? -1 : 1;
! }
! ++_PyCompareState_nesting;
! if (_PyCompareState_nesting > NESTING_LIMIT)
! _PyCompareState_flag = 1;
! if (_PyCompareState_flag &&
! (vtp->tp_as_mapping || (vtp->tp_as_sequence &&
! !PyString_Check(v))))
! {
! PyObject *tstate_dict, *cmp_dict, *pair;
!
! tstate_dict = PyThreadState_GetDict();
! if (tstate_dict == NULL) {
! PyErr_BadInternalCall();
! return -1;
! }
! cmp_dict = PyDict_GetItem(tstate_dict, _PyCompareState_Key);
! if (cmp_dict == NULL) {
! cmp_dict = PyDict_New();
! if (cmp_dict == NULL)
! return -1;
! PyDict_SetItem(tstate_dict,
! _PyCompareState_Key,
! cmp_dict);
! }
!
! pair = PyTuple_New(2);
! if (pair == NULL) {
! return -1;
! }
! if ((long)v <= (long)w) {
! PyTuple_SET_ITEM(pair, 0, PyInt_FromLong((long)v));
! PyTuple_SET_ITEM(pair, 1, PyInt_FromLong((long)w));
! } else {
! PyTuple_SET_ITEM(pair, 0, PyInt_FromLong((long)w));
! PyTuple_SET_ITEM(pair, 1, PyInt_FromLong((long)v));
! }
! if (PyDict_GetItem(cmp_dict, pair)) {
! /* already comparing these objects. assume
! they're equal until shown otherwise
! */
! Py_DECREF(pair);
! --_PyCompareState_nesting;
! if (_PyCompareState_nesting == 0)
! _PyCompareState_flag = 0;
! return 0;
! }
! if (PyDict_SetItem(cmp_dict, pair, pair) == -1) {
! return -1;
! }
! result = (*vtp->tp_compare)(v, w);
! PyDict_DelItem(cmp_dict, pair);
! Py_DECREF(pair);
! } else {
! result = (*vtp->tp_compare)(v, w);
! }
! --_PyCompareState_nesting;
! if (_PyCompareState_nesting == 0)
! _PyCompareState_flag = 0;
! return result;
}
long