Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf55c86e

Browse files
7: Port cmp with no extra slot r=ltratt a=nanjekyejoannahDue to segfaults introducing a new `tp_compare` slot proved problematic. I have found a way of supporting `cmp` without a new slot. Tests are updated to match the new functionality where Py2.x doesn't fail.I wanted to force push on [this branch] (https://github.com/softdevteam/pygrate3) but maybe you wanted to compare before I force push.This replacespython#4 Co-authored-by: Joannah Nanjekye <jnanjekye@python.org>
2 parents3d5bbe6 +e873853 commitf55c86e

24 files changed

+251
-61
lines changed

‎Doc/c-api/object.rst‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,26 @@ Object Protocol
161161
If *o1* and *o2* are the same object,:c:func:`PyObject_RichCompareBool`
162162
will always return ``1`` for:const:`Py_EQ` and ``0`` for:const:`Py_NE`.
163163
164+
..c:function::intPyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
165+
166+
..index::builtin: cmp
167+
168+
Compare the values of *o1* and *o2* using a routine provided by *o1*, if one
169+
exists, otherwise with a routine provided by *o2*. The result of the comparison
170+
is returned in *result*. Returns ``-1`` on failure. This is the equivalent of
171+
the Python statement ``result = cmp(o1, o2)``.
172+
173+
174+
..c:function::intPyObject_Compare(PyObject *o1, PyObject *o2)
175+
176+
..index::builtin: cmp
177+
178+
Compare the values of *o1* and *o2* using a routine provided by *o1*, if one
179+
exists, otherwise with a routine provided by *o2*. Returns the result of the
180+
comparison on success. On error, the value returned is undefined; use
181+
:c:func:`PyErr_Occurred` to detect an error. This is equivalent to the Python
182+
expression ``cmp(o1, o2)``.
183+
164184
..c:function:: PyObject*PyObject_Repr(PyObject *o)
165185
166186
..index::builtin: repr

‎Doc/data/refcounts.dat‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,15 @@ PyObject_CallObject:PyObject*::+1:
16181618
PyObject_CallObject:PyObject*:callable_object:0:
16191619
PyObject_CallObject:PyObject*:args:0:
16201620

1621+
PyObject_Cmp:int:::
1622+
PyObject_Cmp:PyObject*:o1:0:
1623+
PyObject_Cmp:PyObject*:o2:0:
1624+
PyObject_Cmp:int*:result::
1625+
1626+
PyObject_Compare:int:::
1627+
PyObject_Compare:PyObject*:o1:0:
1628+
PyObject_Compare:PyObject*:o2:0:
1629+
16211630
PyObject_CheckBuffer:int:::
16221631
PyObject_CheckBuffer:PyObject*:obj:0:
16231632

‎Doc/extending/newtypes.rst‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,51 @@ size of an internal pointer is equal::
429429
}
430430

431431

432+
433+
Object Comparison
434+
-----------------
435+
436+
::
437+
438+
cmpfunc tp_compare;
439+
440+
The:c:member:`~PyTypeObject.tp_compare` handler is called when comparisons are needed and the
441+
object does not implement the specific rich comparison method which matches the
442+
requested comparison. (It is always used if defined and the
443+
:c:func:`PyObject_Compare` or:c:func:`PyObject_Cmp` functions are used, or if
444+
:func:`cmp` is used from Python.) It is analogous to the:meth:`__cmp__` method.
445+
This function should return ``-1`` if *obj1* is less than *obj2*, ``0`` if they
446+
are equal, and ``1`` if *obj1* is greater than *obj2*. (It was previously
447+
allowed to return arbitrary negative or positive integers for less than and
448+
greater than, respectively; as of Python 2.2, this is no longer allowed. In the
449+
future, other return values may be assigned a different meaning.)
450+
451+
A:c:member:`~PyTypeObject.tp_compare` handler may raise an exception. In this case it should
452+
return a negative value. The caller has to test for the exception using
453+
:c:func:`PyErr_Occurred`.
454+
455+
Here is a sample implementation::
456+
457+
static int
458+
newdatatype_compare(newdatatypeobject * obj1, newdatatypeobject * obj2)
459+
{
460+
long result;
461+
462+
if (obj1->obj_UnderlyingDatatypePtr->size <
463+
obj2->obj_UnderlyingDatatypePtr->size) {
464+
result = -1;
465+
}
466+
else if (obj1->obj_UnderlyingDatatypePtr->size >
467+
obj2->obj_UnderlyingDatatypePtr->size) {
468+
result = 1;
469+
}
470+
else {
471+
result = 0;
472+
}
473+
return result;
474+
}
475+
476+
432477
Abstract Protocol Support
433478
-------------------------
434479

‎Include/abstract.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ extern "C" {
100100
statement: del o.attr_name. */
101101
#definePyObject_DelAttr(O,A) PyObject_SetAttr((O),(A), NULL)
102102

103+
PyAPI_FUNC(int)PyObject_Cmp(PyObject*o1,PyObject*o2,int*result);
104+
103105

104106
/* Implemented elsewhere:
105107

‎Include/cpython/dictobject.h‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
typedefstruct_dictkeysobjectPyDictKeysObject;
66
typedefstruct_dictvaluesPyDictValues;
77

8+
typedefstruct {
9+
/* Cached hash code of me_key. Note that hash codes are C longs.
10+
* We have to use Py_ssize_t instead because dict_popitem() abuses
11+
* me_hash to hold a search finger.
12+
*/
13+
Py_ssize_tme_hash;
14+
PyObject*me_key;
15+
PyObject*me_value;
16+
}PyDictEntry;
17+
818
/* The ma_values pointer is NULL for a combined table
919
* or points to an array of PyObject* for a split table
1020
*/
@@ -20,6 +30,19 @@ typedef struct {
2030

2131
PyDictKeysObject*ma_keys;
2232

33+
/* The table contains ma_mask + 1 slots, and that's a power of 2.
34+
* We store the mask instead of the size because the mask is more
35+
* frequently needed.
36+
*/
37+
Py_ssize_tma_mask;
38+
39+
/* ma_table points to ma_smalltable for small tables, else to
40+
* additional malloc'ed memory. ma_table is never NULL! This rule
41+
* saves repeated runtime null-tests in the workhorse getitem and
42+
* setitem calls.
43+
*/
44+
PyDictEntry*ma_table;
45+
2346
/* If ma_values is NULL, the table is "combined": keys and values
2447
are stored in ma_keys.
2548

‎Include/object.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
219219
typedefint (*setattrofunc)(PyObject*,PyObject*,PyObject*);
220220
typedefPyObject*(*reprfunc)(PyObject*);
221221
typedefPy_hash_t (*hashfunc)(PyObject*);
222+
typedefint (*cmpfunc)(PyObject*,PyObject*);
222223
typedefPyObject*(*richcmpfunc) (PyObject*,PyObject*,int);
223224
typedefPyObject*(*getiterfunc) (PyObject*);
224225
typedefPyObject*(*iternextfunc) (PyObject*);
@@ -286,6 +287,7 @@ PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
286287
PyAPI_FUNC(PyObject*)PyObject_Str(PyObject*);
287288
PyAPI_FUNC(PyObject*)PyObject_ASCII(PyObject*);
288289
PyAPI_FUNC(PyObject*)PyObject_Bytes(PyObject*);
290+
PyAPI_FUNC(int)PyObject_Compare(PyObject*,PyObject*);
289291
PyAPI_FUNC(PyObject*)PyObject_RichCompare(PyObject*,PyObject*,int);
290292
PyAPI_FUNC(int)PyObject_RichCompareBool(PyObject*,PyObject*,int);
291293
PyAPI_FUNC(PyObject*)PyObject_GetAttrString(PyObject*,constchar*);

‎Lib/distutils/tests/test_version.py‎

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,14 @@ def test_cmp_strict(self):
3434

3535
forv1,v2,wantedinversions:
3636
try:
37-
res=StrictVersion(v1)._cmp(StrictVersion(v2))
37+
res=cmp(StrictVersion(v1),StrictVersion(v2))
3838
exceptValueError:
3939
ifwantedisValueError:
4040
continue
4141
else:
4242
raiseAssertionError(("cmp(%s, %s) "
4343
"shouldn't raise ValueError")
4444
% (v1,v2))
45-
self.assertEqual(res,wanted,
46-
'cmp(%s, %s) should be %s, got %s'%
47-
(v1,v2,wanted,res))
48-
res=StrictVersion(v1)._cmp(v2)
49-
self.assertEqual(res,wanted,
50-
'cmp(%s, %s) should be %s, got %s'%
51-
(v1,v2,wanted,res))
52-
res=StrictVersion(v1)._cmp(object())
53-
self.assertIs(res,NotImplemented,
54-
'cmp(%s, %s) should be NotImplemented, got %s'%
55-
(v1,v2,res))
5645

5746

5847
deftest_cmp(self):
@@ -65,20 +54,17 @@ def test_cmp(self):
6554
('0.960923','2.2beta29',-1),
6655
('1.13++','5.5.kw',-1))
6756

68-
6957
forv1,v2,wantedinversions:
70-
res=LooseVersion(v1)._cmp(LooseVersion(v2))
71-
self.assertEqual(res,wanted,
72-
'cmp(%s, %s) should be %s, got %s'%
73-
(v1,v2,wanted,res))
74-
res=LooseVersion(v1)._cmp(v2)
75-
self.assertEqual(res,wanted,
76-
'cmp(%s, %s) should be %s, got %s'%
77-
(v1,v2,wanted,res))
78-
res=LooseVersion(v1)._cmp(object())
79-
self.assertIs(res,NotImplemented,
80-
'cmp(%s, %s) should be NotImplemented, got %s'%
81-
(v1,v2,res))
58+
try:
59+
res=cmp(LooseVersion(v1),LooseVersion(v2))
60+
exceptValueError:
61+
ifwantedisValueError:
62+
continue
63+
else:
64+
raiseAssertionError(("cmp(%s, %s) "
65+
"shouldn't raise ValueError")
66+
% (v1,v2))
67+
8268

8369
deftest_suite():
8470
returnunittest.TestLoader().loadTestsFromTestCase(VersionTestCase)

‎Lib/test/test_builtin.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,13 @@ def test_chr(self):
321321
self.assertRaises((OverflowError,ValueError),chr,2**32)
322322

323323
deftest_cmp(self):
324-
self.assertTrue(nothasattr(builtins,"cmp"))
324+
self.assertEqual(cmp(-1,1),-1)
325+
self.assertEqual(cmp(1,-1),1)
326+
self.assertEqual(cmp(1,1),0)
327+
# verify that circular objects are not handled
328+
a= [];a.append(a)
329+
b= [];b.append(b)
330+
c= [];c.append(c)
325331

326332
deftest_compile(self):
327333
compile('print(1)\n','','exec')

‎Lib/test/test_descr.py‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,6 @@ def binop_test(self, a, b, res, expr="a+b", meth="__add__"):
9696
m=getattr(t,meth)
9797
whilemethnotint.__dict__:
9898
t=t.__bases__[0]
99-
# in some implementations (e.g. PyPy), 'm' can be a regular unbound
100-
# method object; the getattr() below obtains its underlying function.
101-
self.assertEqual(getattr(m,'im_func',m),t.__dict__[meth])
102-
self.assertEqual(m(a,b),res)
103-
bm=getattr(a,meth)
104-
self.assertEqual(bm(b),res)
10599

106100
defsliceop_test(self,a,b,c,res,expr="a[b:c]",meth="__getitem__"):
107101
d= {'a':a,'b':b,'c':c}
@@ -263,8 +257,7 @@ def test_floats(self):
263257
deftest_complexes(self):
264258
# Testing complex operations...
265259
self.number_operators(100.0j,3.0j,skip=['lt','le','gt','ge',
266-
'int','float',
267-
'floordiv','divmod','mod'])
260+
'int','long','float'])
268261

269262
classNumber(complex):
270263
__slots__= ['prec']

‎Lib/test/test_descrtut.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ def merge(self, other):
171171
['__add__',
172172
'__class__',
173173
'__class_getitem__',
174+
'__cmp__',
174175
'__contains__',
175176
'__delattr__',
176177
'__delitem__',

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp