📄 object.c
字号:
char *vname, *wname;
if (v->ob_type == w->ob_type) {
/* When comparing these pointers, they must be cast to
* integer types (i.e. Py_uintptr_t, our spelling of C9X's
* uintptr_t). ANSI specifies that pointer compares other
* than == and != to non-related structures are undefined.
*/
Py_uintptr_t vv = (Py_uintptr_t)v;
Py_uintptr_t ww = (Py_uintptr_t)w;
return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
}
#ifdef Py_USING_UNICODE
/* Special case for Unicode */
if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
c = PyUnicode_Compare(v, w);
if (!PyErr_Occurred())
return c;
/* TypeErrors are ignored: if Unicode coercion fails due
to one of the arguments not having the right type, we
continue as defined by the coercion protocol (see
above). Luckily, decoding errors are reported as
ValueErrors and are not masked by this technique. */
if (!PyErr_ExceptionMatches(PyExc_TypeError))
return -2;
PyErr_Clear();
}
#endif
/* None is smaller than anything */
if (v == Py_None)
return -1;
if (w == Py_None)
return 1;
/* different type: compare type names */
if (v->ob_type->tp_as_number)
vname = "";
else
vname = v->ob_type->tp_name;
if (w->ob_type->tp_as_number)
wname = "";
else
wname = w->ob_type->tp_name;
c = strcmp(vname, wname);
if (c < 0)
return -1;
if (c > 0)
return 1;
/* Same type name, or (more likely) incomparable numeric types */
return ((Py_uintptr_t)(v->ob_type) < (
Py_uintptr_t)(w->ob_type)) ? -1 : 1;
}
#define CHECK_TYPES(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_CHECKTYPES)
/* Do a 3-way comparison, by hook or by crook. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
If the object implements a tp_compare function, it returns
whatever this function returns (whether with an exception or not).
*/
static int
do_cmp(PyObject *v, PyObject *w)
{
int c;
cmpfunc f;
if (v->ob_type == w->ob_type
&& (f = v->ob_type->tp_compare) != NULL) {
c = (*f)(v, w);
if (c != 2 || !PyInstance_Check(v))
return c;
}
c = try_rich_to_3way_compare(v, w);
if (c < 2)
return c;
c = try_3way_compare(v, w);
if (c < 2)
return c;
return default_3way_compare(v, w);
}
/* compare_nesting is incremented before calling compare (for
some types) and decremented on exit. If the count exceeds the
nesting limit, enable code to detect circular data structures.
This is a tunable parameter that should only affect the performance
of comparisons, nothing else. Setting it high makes comparing deeply
nested non-cyclical data structures faster, but makes comparing cyclical
data structures slower.
*/
#define NESTING_LIMIT 20
#ifndef SYMBIAN
static int compare_nesting = 0;
#else
#define compare_nesting (pyglobals->compare_nesting)
#endif
static PyObject*
get_inprogress_dict(void)
{
PyObject *tstate_dict, *inprogress;
#ifndef SYMBIAN
static PyObject *s_key;
#else
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#define s_key (pyglobals->object_c_key)
#endif
if (s_key == NULL) {
s_key = PyString_InternFromString("cmp_state");
if (s_key == NULL)
return NULL;
}
tstate_dict = PyThreadState_GetDict();
if (tstate_dict == NULL) {
PyErr_BadInternalCall();
return NULL;
}
inprogress = PyDict_GetItem(tstate_dict, s_key);
if (inprogress == NULL) {
inprogress = PyDict_New();
if (inprogress == NULL)
return NULL;
if (PyDict_SetItem(tstate_dict, s_key, inprogress) == -1) {
Py_DECREF(inprogress);
return NULL;
}
Py_DECREF(inprogress);
}
return inprogress;
}
static PyObject *
check_recursion(PyObject *v, PyObject *w, int op)
{
PyObject *inprogress;
PyObject *token;
Py_uintptr_t iv = (Py_uintptr_t)v;
Py_uintptr_t iw = (Py_uintptr_t)w;
PyObject *x, *y, *z;
inprogress = get_inprogress_dict();
if (inprogress == NULL)
return NULL;
token = PyTuple_New(3);
if (token == NULL)
return NULL;
if (iv <= iw) {
PyTuple_SET_ITEM(token, 0, x = PyLong_FromVoidPtr((void *)v));
PyTuple_SET_ITEM(token, 1, y = PyLong_FromVoidPtr((void *)w));
if (op >= 0)
op = swapped_op[op];
} else {
PyTuple_SET_ITEM(token, 0, x = PyLong_FromVoidPtr((void *)w));
PyTuple_SET_ITEM(token, 1, y = PyLong_FromVoidPtr((void *)v));
}
PyTuple_SET_ITEM(token, 2, z = PyInt_FromLong((long)op));
if (x == NULL || y == NULL || z == NULL) {
Py_DECREF(token);
return NULL;
}
if (PyDict_GetItem(inprogress, token) != NULL) {
Py_DECREF(token);
return Py_None; /* Without INCREF! */
}
if (PyDict_SetItem(inprogress, token, token) < 0) {
Py_DECREF(token);
return NULL;
}
return token;
}
static void
delete_token(PyObject *token)
{
PyObject *inprogress;
if (token == NULL || token == Py_None)
return;
inprogress = get_inprogress_dict();
if (inprogress == NULL)
PyErr_Clear();
else
PyDict_DelItem(inprogress, token);
Py_DECREF(token);
}
/* Compare v to w. Return
-1 if v < w or exception (PyErr_Occurred() true in latter case).
0 if v == w.
1 if v > w.
XXX The docs (C API manual) say the return value is undefined in case
XXX of error.
*/
DL_EXPORT(int)
PyObject_Compare(PyObject *v, PyObject *w)
{
PyTypeObject *vtp;
int result;
#ifdef SYMBIAN
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
#if defined(USE_STACKCHECK)
if (PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "Stack overflow");
return -1;
}
#endif
if (v == NULL || w == NULL) {
PyErr_BadInternalCall();
return -1;
}
if (v == w)
return 0;
vtp = v->ob_type;
compare_nesting++;
if (compare_nesting > NESTING_LIMIT &&
(vtp->tp_as_mapping
|| (vtp->tp_as_sequence
&& !PyString_Check(v)
&& !PyTuple_Check(v)))) {
/* try to detect circular data structures */
PyObject *token = check_recursion(v, w, -1);
if (token == NULL) {
result = -1;
}
else if (token == Py_None) {
/* already comparing these objects. assume
they're equal until shown otherwise */
result = 0;
}
else {
result = do_cmp(v, w);
delete_token(token);
}
}
else {
result = do_cmp(v, w);
}
compare_nesting--;
return result < 0 ? -1 : result;
}
/* Return (new reference to) Py_True or Py_False. */
static PyObject *
convert_3way_to_object(int op, int c)
{
PyObject *result;
switch (op) {
case Py_LT: c = c < 0; break;
case Py_LE: c = c <= 0; break;
case Py_EQ: c = c == 0; break;
case Py_NE: c = c != 0; break;
case Py_GT: c = c > 0; break;
case Py_GE: c = c >= 0; break;
}
result = c ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
/* We want a rich comparison but don't have one. Try a 3-way cmp instead.
Return
NULL if error
Py_True if v op w
Py_False if not (v op w)
*/
static PyObject *
try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
{
int c;
c = try_3way_compare(v, w);
if (c >= 2)
c = default_3way_compare(v, w);
if (c <= -2)
return NULL;
return convert_3way_to_object(op, c);
}
/* Do rich comparison on v and w. Return
NULL if error
Else a new reference to an object other than Py_NotImplemented, usually(?):
Py_True if v op w
Py_False if not (v op w)
*/
static PyObject *
do_richcmp(PyObject *v, PyObject *w, int op)
{
PyObject *res;
res = try_rich_compare(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
return try_3way_to_rich_compare(v, w, op);
}
/* Return:
NULL for exception;
some object not equal to NotImplemented if it is implemented
(this latter object may not be a Boolean).
*/
DL_EXPORT(PyObject *)
PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
#ifdef SYMBIAN
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
assert(Py_LT <= op && op <= Py_GE);
compare_nesting++;
if (compare_nesting > NESTING_LIMIT &&
(v->ob_type->tp_as_mapping
|| (v->ob_type->tp_as_sequence
&& !PyString_Check(v)
&& !PyTuple_Check(v)))) {
/* try to detect circular data structures */
PyObject *token = check_recursion(v, w, op);
if (token == NULL) {
res = NULL;
goto Done;
}
else if (token == Py_None) {
/* already comparing these objects with this operator.
assume they're equal until shown otherwise */
if (op == Py_EQ)
res = Py_True;
else if (op == Py_NE)
res = Py_False;
else {
PyErr_SetString(PyExc_ValueError,
"can't order recursive values");
res = NULL;
}
Py_XINCREF(res);
}
else {
res = do_richcmp(v, w, op);
delete_token(token);
}
goto Done;
}
/* No nesting extremism.
If the types are equal, and not old-style instances, try to
get out cheap (don't bother with coercions etc.). */
if (v->ob_type == w->ob_type && !PyInstance_Check(v)) {
cmpfunc fcmp;
richcmpfunc frich = RICHCOMPARE(v->ob_type);
/* If the type has richcmp, try it first. try_rich_compare
tries it two-sided, which is not needed since we've a
single type only. */
if (frich != NULL) {
res = (*frich)(v, w, op);
if (res != Py_NotImplemented)
goto Done;
Py_DECREF(res);
}
/* No richcmp, or this particular richmp not implemented.
Try 3-way cmp. */
fcmp = v->ob_type->tp_compare;
if (fcmp != NULL) {
int c = (*fcmp)(v, w);
if (c < 0 && PyErr_Occurred()) {
res = NULL;
goto Done;
}
res = convert_3way_to_object(op, c);
goto Done;
}
}
/* Fast path not taken, or couldn't deliver a useful result. */
res = do_richcmp(v, w, op);
Done:
compare_nesting--;
return res;
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
DL_EXPORT(int)
PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
{
PyObject *res = PyObject_RichCompare(v, w, op);
int ok;
if (res == NULL)
return -1;
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
/* Set of hash utility functions to help maintaining the invariant that
iff a==b then hash(a)==hash(b)
All the utility functions (_Py_Hash*()) return "-1" to signify an error.
*/
DL_EXPORT(long)
_Py_HashDouble(double v)
{
double intpart, fractpart;
int expo;
long hipart;
long x; /* the final hash value */
/* This is designed so that Python numbers of different types
* that compare equal hash to the same value; otherwise comparisons
* of mapping keys will turn out weird.
*/
#ifdef MPW /* MPW C modf expects pointer to extended as second argument */
{
extended e;
fractpart = modf(v, &e);
intpart = e;
}
#else
fractpart = modf(v, &intpart);
#endif
if (fractpart == 0.0) {
/* This must return the same hash as an equal int or long. */
if (intpart > LONG_MAX || -intpart > LONG_MAX) {
/* Convert to long and use its hash. */
PyObject *plong; /* converted to Python long */
if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;
plong = PyLong_FromDouble(v);
if (plong == NULL)
return -1;
x = PyObject_Hash(plong);
Py_DECREF(plong);
return x;
}
/* Fits in a C long == a Python int, so is its own hash. */
x = (long)intpart;
if (x == -1)
x = -2;
return x;
}
/* The fractional part is non-zero, so we don't have to worry about
* making this match the hash of some other type.
* Use frexp to get at the bits in the double.
* Since the VAX D double format has 56 mantissa bits, which is the
* most of any double format in use, each of these parts may have as
* many as (but no more than) 56 significant bits.
* So, assuming sizeof(long) >= 4, each part can be broken into two
* longs; frexp and multiplication are used to do that.
* Also, since the Cray double format has 15 exponent bits, which is
* the most of any double format in use, shifting the exponent field
* left by 15 won't overflow a long (again assuming sizeof(long) >= 4).
*/
v = frexp(v, &expo);
v *= 2147483648.0; /* 2**31 */
hipart = (long)v; /* take the top 32 bits */
v = (v - (double)hipart) * 2147483648.0; /* get the next 32 bits */
x = hipart + (long)v + (expo << 15);
if (x == -1)
x = -2;
return x;
}
DL_EXPORT(long)
_Py_HashPointer(void *p)
{
#if SIZEOF_LONG >= SIZEOF_VOID_P
return (long)p;
#else
/* convert to a Python long and hash that */
PyObject* longobj;
long x;
if ((longobj = PyLong_FromVoidPtr(p)) == NULL) {
x = -1;
goto finally;
}
x = PyObject_Hash(longobj);
finally:
Py_XDECREF(longobj);
return x;
#endif
}
DL_EXPORT(long)
PyObject_Hash(PyObject *v)
{
PyTypeObject *tp = v->ob_type;
if (tp->tp_hash != NULL)
return (*tp->tp_hash)(v);
if (tp->tp_compare == NULL && RICHCOMPARE(tp) == NULL) {
return _Py_HashPointer(v); /* Use address as hash value */
}
/* If there's a cmp but no hash defined, the object can't be hashed */
PyErr_SetString(PyExc_TypeError, "unhashable type");
return -1;
}
DL_EXPORT(PyObject *)
PyObject_GetAttrString(PyObject *v, char *name)
{
PyObject *w, *res;
if (v->ob_type->tp_getattr != NULL)
return (*v->ob_type->tp_getattr)(v, name);
w = PyString_InternFromString(name);
if (w == NULL)
return NULL;
res = PyObject_GetAttr(v, w);
Py_XDECREF(w);
return res;
}
DL_EXPORT(int)
PyObject_HasAttrString(PyObject *v, char *name)
{
PyObject *res = PyObject_GetAttrString(v, name);
if (res != NULL) {
Py_DECREF(res);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -