diff -r adbcba130143 Lib/functools.py --- a/Lib/functools.py Tue Mar 29 12:09:45 2011 -0700 +++ b/Lib/functools.py Sat Apr 02 22:52:11 2011 +0200 @@ -92,28 +92,30 @@ opfunc.__doc__ = getattr(int, opname).__doc__ setattr(cls, opname, opfunc) return cls - -def cmp_to_key(mycmp): - """Convert a cmp= function into a key= function""" - class K(object): - __slots__ = ['obj'] - def __init__(self, obj, *args): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - def __hash__(self): - raise TypeError('hash not implemented') - return K +try: + from _functools import cmp_to_key +except ImportError: + def cmp_to_key(mycmp): + """Convert a cmp= function into a key= function""" + class K(object): + __slots__ = ['obj'] + def __init__(self, obj, *args): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + def __ne__(self, other): + return mycmp(self.obj, other.obj) != 0 + def __hash__(self): + raise TypeError('hash not implemented') + return K _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") diff -r adbcba130143 Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c Tue Mar 29 12:09:45 2011 -0700 +++ b/Modules/_functoolsmodule.c Sat Apr 02 22:52:11 2011 +0200 @@ -330,6 +330,116 @@ }; +/* cmp_to_key ***************************************************************/ + +typedef struct { + PyObject_HEAD; + PyObject *cmp; + PyObject *object; +} keyobject; + +static void +keyobject_dealloc(keyobject *ko) +{ + PyObject_FREE(ko); +} + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kw); + +static PyObject * +keyobject_richcompare(PyObject *ko, PyObject *other, int op) +{ + if (!((keyobject *) ko)->object){ + PyErr_Format(PyExc_AttributeError, "object"); + return NULL; + } + PyObject *res = PyObject_CallFunction(((keyobject *) ko)->cmp, "OO", + ((keyobject *) ko)->object, other); + if (!res) + return NULL; + PyObject *zero = PyLong_FromLong(0); + if (!zero) + return NULL; + PyObject *bool = PyObject_RichCompare(res, zero, op); + if (!bool) + return NULL; + return bool; +} + +static PyMethodDef keyobject_methods[] = { + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject keyobject_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "functools.K", /* tp_name */ + sizeof(keyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)keyobject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)keyobject_call, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + keyobject_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + keyobject_methods, /* tp_methods */ + 0 +}; + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kw) +{ + PyObject *object; + keyobject *result; + + if (!PyArg_UnpackTuple(args, "", 1, 1, &object)) + return NULL; + result = PyObject_New(keyobject, &keyobject_type); + if (!result) + return NULL; + Py_INCREF(ko->cmp); + result->cmp = ko->cmp; + Py_INCREF(object); + result->object = object; + return (PyObject *) result; +} + +static PyObject * +functools_cmp_to_key(PyObject *self, PyObject *args){ + PyObject *cmp = NULL; + + if (!PyArg_UnpackTuple(args, "cmp_to_key", 1, 1, &cmp)) + return NULL; + keyobject *object = PyObject_New(keyobject, &keyobject_type); + if (!object) + return NULL; + object->cmp = cmp; + object->object = NULL; + Py_INCREF(cmp); + return (PyObject *) object; + +} +PyDoc_STRVAR(functools_cmp_to_key_doc, +"Convert a cmp= function into a key= function."); + /* reduce (used to be a builtin) ********************************************/ static PyObject * @@ -413,6 +523,7 @@ static PyMethodDef module_methods[] = { {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc}, + {"cmp_to_key", functools_cmp_to_key, METH_VARARGS, functools_cmp_to_key_doc}, {NULL, NULL} /* sentinel */ }; diff -r adbcba130143 Lib/functools.py --- a/Lib/functools.py Tue Mar 29 12:09:45 2011 -0700 +++ b/Lib/functools.py Sat Apr 02 22:52:37 2011 +0200 @@ -92,28 +92,31 @@ opfunc.__doc__ = getattr(int, opname).__doc__ setattr(cls, opname, opfunc) return cls - -def cmp_to_key(mycmp): - """Convert a cmp= function into a key= function""" - class K(object): - __slots__ = ['obj'] - def __init__(self, obj, *args): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - def __hash__(self): - raise TypeError('hash not implemented') - return K + +try: + from _functools import cmp_to_key +except ImportError: + def cmp_to_key(mycmp): + """Convert a cmp= function into a key= function""" + class K(object): + __slots__ = ['obj'] + def __init__(self, obj, *args): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + def __ne__(self, other): + return mycmp(self.obj, other.obj) != 0 + def __hash__(self): + raise TypeError('hash not implemented') + return K _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") diff -r adbcba130143 Modules/_functoolsmodule.c --- a/Modules/_functoolsmodule.c Tue Mar 29 12:09:45 2011 -0700 +++ b/Modules/_functoolsmodule.c Sat Apr 02 22:52:37 2011 +0200 @@ -330,6 +330,116 @@ }; +/* cmp_to_key ***************************************************************/ + +typedef struct { + PyObject_HEAD; + PyObject *cmp; + PyObject *object; +} keyobject; + +static void +keyobject_dealloc(keyobject *ko) +{ + PyObject_FREE(ko); +} + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kw); + +static PyObject * +keyobject_richcompare(PyObject *ko, PyObject *other, int op) +{ + if (!((keyobject *) ko)->object){ + PyErr_Format(PyExc_AttributeError, "object"); + return NULL; + } + PyObject *res = PyObject_CallFunction(((keyobject *) ko)->cmp, "OO", + ((keyobject *) ko)->object, other); + if (!res) + return NULL; + PyObject *zero = PyLong_FromLong(0); + if (!zero) + return NULL; + PyObject *bool = PyObject_RichCompare(res, zero, op); + if (!bool) + return NULL; + return bool; +} + +static PyMethodDef keyobject_methods[] = { + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject keyobject_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "functools.K", /* tp_name */ + sizeof(keyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)keyobject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)keyobject_call, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + keyobject_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + keyobject_methods, /* tp_methods */ + 0 +}; + +static PyObject * +keyobject_call(keyobject *ko, PyObject *args, PyObject *kw) +{ + PyObject *object; + keyobject *result; + + if (!PyArg_UnpackTuple(args, "", 1, 1, &object)) + return NULL; + result = PyObject_New(keyobject, &keyobject_type); + if (!result) + return NULL; + Py_INCREF(ko->cmp); + result->cmp = ko->cmp; + Py_INCREF(object); + result->object = object; + return (PyObject *) result; +} + +static PyObject * +functools_cmp_to_key(PyObject *self, PyObject *args){ + PyObject *cmp = NULL; + + if (!PyArg_UnpackTuple(args, "cmp_to_key", 1, 1, &cmp)) + return NULL; + keyobject *object = PyObject_New(keyobject, &keyobject_type); + if (!object) + return NULL; + object->cmp = cmp; + object->object = NULL; + Py_INCREF(cmp); + return (PyObject *) object; + +} +PyDoc_STRVAR(functools_cmp_to_key_doc, +"Convert a cmp= function into a key= function."); + /* reduce (used to be a builtin) ********************************************/ static PyObject * @@ -413,6 +523,7 @@ static PyMethodDef module_methods[] = { {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc}, + {"cmp_to_key", functools_cmp_to_key, METH_VARARGS, functools_cmp_to_key_doc}, {NULL, NULL} /* sentinel */ };