Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
b7097770
Commit
b7097770
authored
Apr 24, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmp() builtin
parent
9ebfc95f
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
588 additions
and
88 deletions
+588
-88
from_cpython/Include/object.h
from_cpython/Include/object.h
+1
-1
src/capi/abstract.cpp
src/capi/abstract.cpp
+47
-14
src/capi/object.cpp
src/capi/object.cpp
+438
-30
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+73
-2
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+5
-3
src/runtime/capi.cpp
src/runtime/capi.cpp
+0
-38
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+1
-0
test/tests/cmp_test.py
test/tests/cmp_test.py
+23
-0
No files found.
from_cpython/Include/object.h
View file @
b7097770
...
...
@@ -553,7 +553,7 @@ PyAPI_FUNC(int) PyNumber_CoerceEx(PyObject **, PyObject **) PYSTON_NOEXCEPT;
PyAPI_FUNC
(
void
)
PyObject_ClearWeakRefs
(
PyObject
*
)
PYSTON_NOEXCEPT
;
/* A slot function whose address we need to compare */
extern
int
_PyObject_SlotCompare
(
PyObject
*
,
PyObject
*
);
extern
int
_PyObject_SlotCompare
(
PyObject
*
,
PyObject
*
)
PYSTON_NOEXCEPT
;
/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes
dict as the last parameter. */
PyAPI_FUNC
(
PyObject
*
)
...
...
src/capi/abstract.cpp
View file @
b7097770
...
...
@@ -27,6 +27,31 @@
namespace
pyston
{
static
PyObject
*
type_error
(
const
char
*
msg
,
PyObject
*
obj
)
noexcept
{
PyErr_Format
(
PyExc_TypeError
,
msg
,
Py_TYPE
(
obj
)
->
tp_name
);
return
NULL
;
}
static
PyObject
*
null_error
(
void
)
noexcept
{
if
(
!
PyErr_Occurred
())
PyErr_SetString
(
PyExc_SystemError
,
"null argument to internal routine"
);
return
NULL
;
}
extern
"C"
int
PyObject_Cmp
(
PyObject
*
o1
,
PyObject
*
o2
,
int
*
result
)
noexcept
{
int
r
;
if
(
o1
==
NULL
||
o2
==
NULL
)
{
null_error
();
return
-
1
;
}
r
=
PyObject_Compare
(
o1
,
o2
);
if
(
PyErr_Occurred
())
return
-
1
;
*
result
=
r
;
return
0
;
}
extern
"C"
Py_ssize_t
_PyObject_LengthHint
(
PyObject
*
o
,
Py_ssize_t
defaultvalue
)
noexcept
{
static
PyObject
*
hintstrobj
=
NULL
;
PyObject
*
ro
,
*
hintmeth
;
...
...
@@ -227,17 +252,6 @@ extern "C" void PyBuffer_Release(Py_buffer* view) noexcept {
view
->
obj
=
NULL
;
}
static
PyObject
*
type_error
(
const
char
*
msg
,
PyObject
*
obj
)
noexcept
{
PyErr_Format
(
PyExc_TypeError
,
msg
,
Py_TYPE
(
obj
)
->
tp_name
);
return
NULL
;
}
static
PyObject
*
null_error
(
void
)
noexcept
{
if
(
!
PyErr_Occurred
())
PyErr_SetString
(
PyExc_SystemError
,
"null argument to internal routine"
);
return
NULL
;
}
static
PyObject
*
objargs_mktuple
(
va_list
va
)
noexcept
{
int
i
,
n
=
0
;
va_list
countva
;
...
...
@@ -1516,9 +1530,28 @@ extern "C" int PyNumber_Coerce(PyObject**, PyObject**) noexcept {
return
-
1
;
}
extern
"C"
int
PyNumber_CoerceEx
(
PyObject
**
,
PyObject
**
)
noexcept
{
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
return
-
1
;
extern
"C"
int
PyNumber_CoerceEx
(
PyObject
**
pv
,
PyObject
**
pw
)
noexcept
{
PyObject
*
v
=
*
pv
;
PyObject
*
w
=
*
pw
;
int
res
;
/* Shortcut only for old-style types */
if
(
v
->
cls
==
w
->
cls
&&
!
PyType_HasFeature
(
v
->
cls
,
Py_TPFLAGS_CHECKTYPES
))
{
Py_INCREF
(
v
);
Py_INCREF
(
w
);
return
0
;
}
if
(
v
->
cls
->
tp_as_number
&&
v
->
cls
->
tp_as_number
->
nb_coerce
)
{
res
=
(
*
v
->
cls
->
tp_as_number
->
nb_coerce
)(
pv
,
pw
);
if
(
res
<=
0
)
return
res
;
}
if
(
w
->
cls
->
tp_as_number
&&
w
->
cls
->
tp_as_number
->
nb_coerce
)
{
res
=
(
*
w
->
cls
->
tp_as_number
->
nb_coerce
)(
pw
,
pv
);
if
(
res
<=
0
)
return
res
;
}
return
1
;
}
extern
"C"
PyObject
*
_PyNumber_ConvertIntegralToInt
(
PyObject
*
integral
,
const
char
*
error_format
)
noexcept
{
...
...
src/capi/object.cpp
View file @
b7097770
...
...
@@ -472,31 +472,6 @@ extern "C" int PyObject_AsWriteBuffer(PyObject* obj, void** buffer, Py_ssize_t*
Py_FatalError
(
"unimplemented"
);
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern
"C"
int
PyObject_RichCompareBool
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
noexcept
{
PyObject
*
res
;
int
ok
;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if
(
v
==
w
)
{
if
(
op
==
Py_EQ
)
return
1
;
else
if
(
op
==
Py_NE
)
return
0
;
}
res
=
PyObject_RichCompare
(
v
,
w
,
op
);
if
(
res
==
NULL
)
return
-
1
;
if
(
PyBool_Check
(
res
))
ok
=
(
res
==
Py_True
);
else
ok
=
PyObject_IsTrue
(
res
);
Py_DECREF
(
res
);
return
ok
;
}
// I'm not sure how we can support this one:
extern
"C"
PyObject
**
_PyObject_GetDictPtr
(
PyObject
*
obj
)
noexcept
{
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
...
...
@@ -564,10 +539,443 @@ extern "C" void Py_ReprLeave(PyObject* obj) noexcept {
}
}
extern
"C"
int
PyObject_Compare
(
PyObject
*
o1
,
PyObject
*
o2
)
noexcept
{
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
// 'On error, the value returned is undefined; use PyErr_Occurred() to detect an error.'
// - https://docs.python.org/2/c-api/object.html
return
0xdeadbeef
;
/* Helper to warn about deprecated tp_compare return values. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w.
(This function cannot return 2.)
*/
static
int
adjust_tp_compare
(
int
c
)
{
if
(
PyErr_Occurred
())
{
if
(
c
!=
-
1
&&
c
!=
-
2
)
{
PyObject
*
t
,
*
v
,
*
tb
;
PyErr_Fetch
(
&
t
,
&
v
,
&
tb
);
if
(
PyErr_Warn
(
PyExc_RuntimeWarning
,
"tp_compare didn't return -1 or -2 "
"for exception"
)
<
0
)
{
Py_XDECREF
(
t
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
}
else
PyErr_Restore
(
t
,
v
,
tb
);
}
return
-
2
;
}
else
if
(
c
<
-
1
||
c
>
1
)
{
if
(
PyErr_Warn
(
PyExc_RuntimeWarning
,
"tp_compare didn't return -1, 0 or 1"
)
<
0
)
return
-
2
;
else
return
c
<
-
1
?
-
1
:
1
;
}
else
{
assert
(
c
>=
-
1
&&
c
<=
1
);
return
c
;
}
}
/* Macro to get the tp_richcompare field of a type if defined */
#define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) ? (t)->tp_richcompare : NULL)
/* Map rich comparison operators to their swapped version, e.g. LT --> GT */
extern
"C"
{
int
_Py_SwappedOp
[]
=
{
Py_GT
,
Py_GE
,
Py_EQ
,
Py_NE
,
Py_LT
,
Py_LE
};
}
/* Try a genuine rich comparison, returning an object. Return:
NULL for exception;
NotImplemented if this particular rich comparison is not implemented or
undefined;
some object not equal to NotImplemented if it is implemented
(this latter object may not be a Boolean).
*/
static
PyObject
*
try_rich_compare
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
{
richcmpfunc
f
;
PyObject
*
res
;
if
(
v
->
cls
!=
w
->
cls
&&
PyType_IsSubtype
(
w
->
cls
,
v
->
cls
)
&&
(
f
=
RICHCOMPARE
(
w
->
cls
))
!=
NULL
)
{
res
=
(
*
f
)(
w
,
v
,
_Py_SwappedOp
[
op
]);
if
(
res
!=
Py_NotImplemented
)
return
res
;
Py_DECREF
(
res
);
}
if
((
f
=
RICHCOMPARE
(
v
->
cls
))
!=
NULL
)
{
res
=
(
*
f
)(
v
,
w
,
op
);
if
(
res
!=
Py_NotImplemented
)
return
res
;
Py_DECREF
(
res
);
}
if
((
f
=
RICHCOMPARE
(
w
->
cls
))
!=
NULL
)
{
return
(
*
f
)(
w
,
v
,
_Py_SwappedOp
[
op
]);
}
res
=
Py_NotImplemented
;
Py_INCREF
(
res
);
return
res
;
}
/* Try a genuine rich comparison, returning an int. Return:
-1 for exception (including the case where try_rich_compare() returns an
object that's not a Boolean);
0 if the outcome is false;
1 if the outcome is true;
2 if this particular rich comparison is not implemented or undefined.
*/
static
int
try_rich_compare_bool
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
{
PyObject
*
res
;
int
ok
;
if
(
RICHCOMPARE
(
v
->
cls
)
==
NULL
&&
RICHCOMPARE
(
w
->
cls
)
==
NULL
)
return
2
;
/* Shortcut, avoid INCREF+DECREF */
res
=
try_rich_compare
(
v
,
w
,
op
);
if
(
res
==
NULL
)
return
-
1
;
if
(
res
==
Py_NotImplemented
)
{
Py_DECREF
(
res
);
return
2
;
}
ok
=
PyObject_IsTrue
(
res
);
Py_DECREF
(
res
);
return
ok
;
}
/* Try rich comparisons to determine a 3-way comparison. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular rich comparison is not implemented or undefined.
*/
static
int
try_rich_to_3way_compare
(
PyObject
*
v
,
PyObject
*
w
)
{
static
struct
{
int
op
;
int
outcome
;
}
tries
[
3
]
=
{
/* Try this operator, and if it is true, use this outcome: */
{
Py_EQ
,
0
},
{
Py_LT
,
-
1
},
{
Py_GT
,
1
},
};
int
i
;
if
(
RICHCOMPARE
(
v
->
cls
)
==
NULL
&&
RICHCOMPARE
(
w
->
cls
)
==
NULL
)
return
2
;
/* Shortcut */
for
(
i
=
0
;
i
<
3
;
i
++
)
{
switch
(
try_rich_compare_bool
(
v
,
w
,
tries
[
i
].
op
))
{
case
-
1
:
return
-
2
;
case
1
:
return
tries
[
i
].
outcome
;
}
}
return
2
;
}
/* Try a 3-way comparison, returning an int. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular 3-way comparison is not implemented or undefined.
*/
static
int
try_3way_compare
(
PyObject
*
v
,
PyObject
*
w
)
{
int
c
;
cmpfunc
f
;
/* Comparisons involving instances are given to instance_compare,
which has the same return conventions as this function. */
f
=
v
->
cls
->
tp_compare
;
if
(
PyInstance_Check
(
v
))
return
(
*
f
)(
v
,
w
);
if
(
PyInstance_Check
(
w
))
return
(
*
w
->
cls
->
tp_compare
)(
v
,
w
);
/* If both have the same (non-NULL) tp_compare, use it. */
if
(
f
!=
NULL
&&
f
==
w
->
cls
->
tp_compare
)
{
c
=
(
*
f
)(
v
,
w
);
return
adjust_tp_compare
(
c
);
}
/* If either tp_compare is _PyObject_SlotCompare, that's safe. */
if
(
f
==
_PyObject_SlotCompare
||
w
->
cls
->
tp_compare
==
_PyObject_SlotCompare
)
return
_PyObject_SlotCompare
(
v
,
w
);
/* If we're here, v and w,
a) are not instances;
b) have different types or a type without tp_compare; and
c) don't have a user-defined tp_compare.
tp_compare implementations in C assume that both arguments
have their type, so we give up if the coercion fails or if
it yields types which are still incompatible (which can
happen with a user-defined nb_coerce).
*/
c
=
PyNumber_CoerceEx
(
&
v
,
&
w
);
if
(
c
<
0
)
return
-
2
;
if
(
c
>
0
)
return
2
;
f
=
v
->
cls
->
tp_compare
;
if
(
f
!=
NULL
&&
f
==
w
->
cls
->
tp_compare
)
{
c
=
(
*
f
)(
v
,
w
);
Py_DECREF
(
v
);
Py_DECREF
(
w
);
return
adjust_tp_compare
(
c
);
}
/* No comparison defined */
Py_DECREF
(
v
);
Py_DECREF
(
w
);
return
2
;
}
/* Final fallback 3-way comparison, returning an int. Return:
-2 if an error occurred;
-1 if v < w;
0 if v == w;
1 if v > w.
*/
static
int
default_3way_compare
(
PyObject
*
v
,
PyObject
*
w
)
{
int
c
;
const
char
*
vname
,
*
wname
;
if
(
v
->
cls
==
w
->
cls
)
{
/* 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
;
}
/* None is smaller than anything */
if
(
v
==
Py_None
)
return
-
1
;
if
(
w
==
Py_None
)
return
1
;
/* different type: compare type names; numbers are smaller */
if
(
PyNumber_Check
(
v
))
vname
=
""
;
else
vname
=
v
->
cls
->
tp_name
;
if
(
PyNumber_Check
(
w
))
wname
=
""
;
else
wname
=
w
->
cls
->
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
->
cls
)
<
(
Py_uintptr_t
)(
w
->
cls
))
?
-
1
:
1
;
}
/* Do a 3-way comparison, by hook or by crook. Return:
-2 for an exception (but see below);
-1 if v < w;
0 if v == w;
1 if v > w;
BUT: 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
->
cls
==
w
->
cls
&&
(
f
=
v
->
cls
->
tp_compare
)
!=
NULL
)
{
c
=
(
*
f
)(
v
,
w
);
if
(
PyInstance_Check
(
v
))
{
/* Instance tp_compare has a different signature.
But if it returns undefined we fall through. */
if
(
c
!=
2
)
return
c
;
/* Else fall through to try_rich_to_3way_compare() */
}
else
return
adjust_tp_compare
(
c
);
}
/* We only get here if one of the following is true:
a) v and w have different types
b) v and w have the same type, which doesn't have tp_compare
c) v and w are instances, and either __cmp__ is not defined or
__cmp__ returns NotImplemented
*/
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 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.
*/
extern
"C"
int
PyObject_Compare
(
PyObject
*
v
,
PyObject
*
w
)
noexcept
{
int
result
;
if
(
v
==
NULL
||
w
==
NULL
)
{
PyErr_BadInternalCall
();
return
-
1
;
}
if
(
v
==
w
)
return
0
;
if
(
Py_EnterRecursiveCall
(
" in cmp"
))
return
-
1
;
result
=
do_cmp
(
v
,
w
);
Py_LeaveRecursiveCall
();
return
result
<
0
?
-
1
:
result
;
}
/* Return (new reference to) Py_True or Py_False. */
static
PyObject
*
convert_3way_to_object
(
int
op
,
int
c
)
noexcept
{
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
)
noexcept
{
int
c
;
c
=
try_3way_compare
(
v
,
w
);
if
(
c
>=
2
)
{
/* Py3K warning if types are not equal and comparison isn't == or != */
if
(
Py_Py3kWarningFlag
&&
v
->
cls
!=
w
->
cls
&&
op
!=
Py_EQ
&&
op
!=
Py_NE
&&
PyErr_WarnEx
(
PyExc_DeprecationWarning
,
"comparing unequal types not supported "
"in 3.x"
,
1
)
<
0
)
{
return
NULL
;
}
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
)
noexcept
{
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).
*/
extern
"C"
PyObject
*
PyObject_RichCompare
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
noexcept
{
PyObject
*
res
;
assert
(
Py_LT
<=
op
&&
op
<=
Py_GE
);
if
(
Py_EnterRecursiveCall
(
" in cmp"
))
return
NULL
;
/* If the types are equal, and not old-style instances, try to
get out cheap (don't bother with coercions etc.). */
if
(
v
->
cls
==
w
->
cls
&&
!
PyInstance_Check
(
v
))
{
cmpfunc
fcmp
;
richcmpfunc
frich
=
RICHCOMPARE
(
v
->
cls
);
/* 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
->
cls
->
tp_compare
;
if
(
fcmp
!=
NULL
)
{
int
c
=
(
*
fcmp
)(
v
,
w
);
c
=
adjust_tp_compare
(
c
);
if
(
c
==
-
2
)
{
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:
Py_LeaveRecursiveCall
();
return
res
;
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern
"C"
int
PyObject_RichCompareBool
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
noexcept
{
PyObject
*
res
;
int
ok
;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if
(
v
==
w
)
{
if
(
op
==
Py_EQ
)
return
1
;
else
if
(
op
==
Py_NE
)
return
0
;
}
res
=
PyObject_RichCompare
(
v
,
w
,
op
);
if
(
res
==
NULL
)
return
-
1
;
if
(
PyBool_Check
(
res
))
ok
=
(
res
==
Py_True
);
else
ok
=
PyObject_IsTrue
(
res
);
Py_DECREF
(
res
);
return
ok
;
}
}
src/capi/typeobject.cpp
View file @
b7097770
...
...
@@ -461,6 +461,26 @@ static PyObject* wrap_delitem(PyObject* self, PyObject* args, void* wrapped) noe
return
Py_None
;
}
static
PyObject
*
wrap_cmpfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
cmpfunc
func
=
(
cmpfunc
)
wrapped
;
int
res
;
PyObject
*
other
;
if
(
!
check_num_args
(
args
,
1
))
return
NULL
;
other
=
PyTuple_GET_ITEM
(
args
,
0
);
if
(
Py_TYPE
(
other
)
->
tp_compare
!=
func
&&
!
PyType_IsSubtype
(
Py_TYPE
(
other
),
Py_TYPE
(
self
)))
{
PyErr_Format
(
PyExc_TypeError
,
"%s.__cmp__(x,y) requires y to be a '%s', not a '%s'"
,
Py_TYPE
(
self
)
->
tp_name
,
Py_TYPE
(
self
)
->
tp_name
,
Py_TYPE
(
other
)
->
tp_name
);
return
NULL
;
}
res
=
(
*
func
)(
self
,
other
);
if
(
PyErr_Occurred
())
return
NULL
;
return
PyInt_FromLong
((
long
)
res
);
}
static
PyObject
*
wrap_init
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
,
PyObject
*
kwds
)
noexcept
{
initproc
func
=
(
initproc
)
wrapped
;
...
...
@@ -565,7 +585,57 @@ static PyObject* call_maybe(PyObject* o, const char* name, PyObject** nameobj, c
return
retval
;
}
PyObject
*
slot_tp_repr
(
PyObject
*
self
)
noexcept
{
static
int
half_compare
(
PyObject
*
self
,
PyObject
*
other
)
noexcept
{
PyObject
*
func
,
*
args
,
*
res
;
static
PyObject
*
cmp_str
;
Py_ssize_t
c
;
func
=
lookup_method
(
self
,
"__cmp__"
,
&
cmp_str
);
if
(
func
==
NULL
)
{
PyErr_Clear
();
}
else
{
args
=
PyTuple_Pack
(
1
,
other
);
if
(
args
==
NULL
)
res
=
NULL
;
else
{
res
=
PyObject_Call
(
func
,
args
,
NULL
);
Py_DECREF
(
args
);
}
Py_DECREF
(
func
);
if
(
res
!=
Py_NotImplemented
)
{
if
(
res
==
NULL
)
return
-
2
;
c
=
PyInt_AsLong
(
res
);
Py_DECREF
(
res
);
if
(
c
==
-
1
&&
PyErr_Occurred
())
return
-
2
;
return
(
c
<
0
)
?
-
1
:
(
c
>
0
)
?
1
:
0
;
}
Py_DECREF
(
res
);
}
return
2
;
}
/* This slot is published for the benefit of try_3way_compare in object.c */
extern
"C"
int
_PyObject_SlotCompare
(
PyObject
*
self
,
PyObject
*
other
)
noexcept
{
int
c
;
if
(
Py_TYPE
(
self
)
->
tp_compare
==
_PyObject_SlotCompare
)
{
c
=
half_compare
(
self
,
other
);
if
(
c
<=
1
)
return
c
;
}
if
(
Py_TYPE
(
other
)
->
tp_compare
==
_PyObject_SlotCompare
)
{
c
=
half_compare
(
other
,
self
);
if
(
c
<
-
1
)
return
-
2
;
if
(
c
<=
1
)
return
-
c
;
}
return
(
void
*
)
self
<
(
void
*
)
other
?
-
1
:
(
void
*
)
self
>
(
void
*
)
other
?
1
:
0
;
}
static
PyObject
*
slot_tp_repr
(
PyObject
*
self
)
noexcept
{
try
{
return
repr
(
self
);
}
catch
(
ExcInfo
e
)
{
...
...
@@ -574,7 +644,7 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
}
}
PyObject
*
slot_tp_str
(
PyObject
*
self
)
noexcept
{
static
PyObject
*
slot_tp_str
(
PyObject
*
self
)
noexcept
{
try
{
return
str
(
self
);
}
catch
(
ExcInfo
e
)
{
...
...
@@ -1264,6 +1334,7 @@ static slotdef slotdefs[]
TPSLOT
(
"__getattr__"
,
tp_getattr
,
NULL
,
NULL
,
""
),
TPSLOT
(
"__setattr__"
,
tp_setattr
,
NULL
,
NULL
,
""
),
TPSLOT
(
"__delattr__"
,
tp_setattr
,
NULL
,
NULL
,
""
),
TPSLOT
(
"__cmp__"
,
tp_compare
,
_PyObject_SlotCompare
,
wrap_cmpfunc
,
"x.__cmp__(y) <==> cmp(x,y)"
),
TPSLOT
(
"__repr__"
,
tp_repr
,
slot_tp_repr
,
wrap_unaryfunc
,
"x.__repr__() <==> repr(x)"
),
TPSLOT
(
"__hash__"
,
tp_hash
,
slot_tp_hash
,
wrap_hashfunc
,
"x.__hash__() <==> hash(x)"
),
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
b7097770
...
...
@@ -969,9 +969,11 @@ Box* builtinRound(Box* _number, Box* _ndigits) {
throwCAPIException
();
}
Box
*
builtinCmp
(
Box
*
lhs
,
Box
*
rhs
)
{
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
throwCAPIException
();
Box
*
builtinCmp
(
Box
*
a
,
Box
*
b
)
{
int
c
;
if
(
PyObject_Cmp
(
a
,
b
,
&
c
)
<
0
)
throwCAPIException
();
return
PyInt_FromLong
((
long
)
c
);
}
Box
*
builtinApply
(
Box
*
func
,
Box
*
args
,
Box
*
keywords
)
{
...
...
src/runtime/capi.cpp
View file @
b7097770
...
...
@@ -306,44 +306,6 @@ extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) noexcept {
return
-
1
;
}
extern
"C"
PyObject
*
PyObject_RichCompare
(
PyObject
*
o1
,
PyObject
*
o2
,
int
opid
)
noexcept
{
int
translated_op
;
switch
(
opid
)
{
case
Py_LT
:
translated_op
=
AST_TYPE
::
Lt
;
break
;
case
Py_LE
:
translated_op
=
AST_TYPE
::
LtE
;
break
;
case
Py_EQ
:
translated_op
=
AST_TYPE
::
Eq
;
break
;
case
Py_NE
:
translated_op
=
AST_TYPE
::
NotEq
;
break
;
case
Py_GT
:
translated_op
=
AST_TYPE
::
Gt
;
break
;
case
Py_GE
:
translated_op
=
AST_TYPE
::
GtE
;
break
;
default:
fatalOrError
(
PyExc_NotImplementedError
,
"unimplemented"
);
return
nullptr
;
};
try
{
return
compare
(
o1
,
o2
,
translated_op
);
}
catch
(
ExcInfo
e
)
{
setCAPIException
(
e
);
return
NULL
;
}
}
extern
"C"
{
int
_Py_SwappedOp
[]
=
{
Py_GT
,
Py_GE
,
Py_EQ
,
Py_NE
,
Py_LT
,
Py_LE
};
}
extern
"C"
long
PyObject_Hash
(
PyObject
*
o
)
noexcept
{
try
{
return
hash
(
o
)
->
n
;
...
...
src/runtime/objmodel.cpp
View file @
b7097770
...
...
@@ -325,6 +325,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_flags
|=
Py_TPFLAGS_HAVE_CLASS
;
tp_flags
|=
Py_TPFLAGS_HAVE_GC
;
tp_flags
|=
Py_TPFLAGS_HAVE_WEAKREFS
;
tp_flags
|=
Py_TPFLAGS_HAVE_RICHCOMPARE
;
if
(
base
&&
(
base
->
tp_flags
&
Py_TPFLAGS_HAVE_NEWBUFFER
))
tp_flags
|=
Py_TPFLAGS_HAVE_NEWBUFFER
;
...
...
test/tests/cmp_test.py
0 → 100644
View file @
b7097770
class
C
(
object
):
def
__eq__
(
self
,
rhs
):
print
"eq"
,
type
(
self
),
type
(
rhs
)
return
False
def
__lt__
(
self
,
rhs
):
print
"lt"
,
type
(
self
),
type
(
rhs
)
return
False
def
__gt__
(
self
,
rhs
):
print
"gt"
,
type
(
self
),
type
(
rhs
)
return
True
class
D
(
C
):
def
__cmp__
(
self
,
rhs
):
print
"cmp"
,
type
(
self
),
type
(
rhs
)
return
0
l
=
[
C
(),
D
()]
for
lhs
in
l
:
for
rhs
in
l
:
r
=
cmp
(
lhs
,
rhs
)
print
type
(
lhs
),
type
(
rhs
),
r
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment