diff options
author | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-09 20:35:09 (GMT) |
---|---|---|
committer | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-09 20:35:09 (GMT) |
commit | c36c3789dee99b3e2d01ee47731b62200157ba16 (patch) | |
tree | 2e872beff3aec978f274d6cdde057175465c738c /Objects | |
parent | a28e7028f99701c4f216dfbe4fcdf5f00cfee7e0 (diff) | |
download | cpython-c36c3789dee99b3e2d01ee47731b62200157ba16.zip cpython-c36c3789dee99b3e2d01ee47731b62200157ba16.tar.gz cpython-c36c3789dee99b3e2d01ee47731b62200157ba16.tar.bz2 |
Issue #1023290: Added API for the conversion of longs to bytes and vice-versa.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/longobject.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c index 2e2eca8..cfe7b5c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4296,6 +4296,201 @@ long_is_finite(PyObject *v) } #endif + +PyDoc_STRVAR(long_to_bytes_doc, +"int.to_bytes(length, byteorder, *, signed=False) -> bytes\n\ +\n\ +Return an array of bytes representing an integer.\n\ +\n\ +The integer is represented using length bytes. An OverflowError is\n\ +raised if the integer is not representable with the given number of\n\ +bytes.\n\ +\n\ +The byteorder argument determines the byte order used to represent the\n\ +integer. If byteorder is 'big', the most significant byte is at the\n\ +beginning of the byte array. If byteorder is 'little', the most\n\ +significant byte is at the end of the byte array. To request the native\n\ +byte order of the host system, use `sys.byteorder' as the byte order value.\n\ +\n\ +The signed keyword-only argument determines whether two's complement is\n\ +used to represent the integer. If signed is False and a negative integer\n\ +is given, an OverflowError is raised."); + +static PyObject * +long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) +{ + PyObject *byteorder_str; + PyObject *is_signed_obj = NULL; + Py_ssize_t length; + int little_endian; + int is_signed; + PyObject *bytes; + static PyObject *little_str = NULL, *big_str = NULL; + static char *kwlist[] = {"length", "byteorder", "signed", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "nO|O:to_bytes", kwlist, + &length, &byteorder_str, + &is_signed_obj)) + return NULL; + + if (args != NULL && Py_SIZE(args) > 2) { + PyErr_SetString(PyExc_TypeError, + "'signed' is a keyword-only argument"); + return NULL; + } + if (little_str == NULL) { + little_str = PyUnicode_InternFromString("little"); + big_str = PyUnicode_InternFromString("big"); + if (little_str == NULL || big_str == NULL) + return NULL; + } + + if (PyObject_RichCompareBool(byteorder_str, little_str, Py_EQ)) + little_endian = 1; + else if (PyObject_RichCompareBool(byteorder_str, big_str, Py_EQ)) + little_endian = 0; + else { + PyErr_SetString(PyExc_ValueError, + "byteorder must be either 'little' or 'big'"); + return NULL; + } + + if (is_signed_obj != NULL) { + int cmp = PyObject_IsTrue(is_signed_obj); + if (cmp < 0) + return NULL; + is_signed = cmp ? 1 : 0; + } + else { + /* If the signed argument was omitted, use False as the + default. */ + is_signed = 0; + } + + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length argument must be non-negative"); + return NULL; + } + + bytes = PyBytes_FromStringAndSize(NULL, length); + if (bytes == NULL) + return NULL; + + if (_PyLong_AsByteArray(v, (unsigned char *)PyBytes_AS_STRING(bytes), + length, little_endian, is_signed) < 0) { + Py_DECREF(bytes); + return NULL; + } + + return bytes; +} + +PyDoc_STRVAR(long_from_bytes_doc, +"int.from_bytes(bytes, byteorder, *, signed=False) -> int\n\ +\n\ +Return the integer represented by the given array of bytes.\n\ +\n\ +The bytes argument must either support the buffer protocol or be an\n\ +iterable object producing bytes. Bytes and bytearray are examples of\n\ +built-in objects that support the buffer protocol.\n\ +\n\ +The byteorder argument determines the byte order used to represent the\n\ +integer. If byteorder is 'big', the most significant byte is at the\n\ +beginning of the byte array. If byteorder is 'little', the most\n\ +significant byte is at the end of the byte array. To request the native\n\ +byte order of the host system, use `sys.byteorder' as the byte order value.\n\ +\n\ +The signed keyword-only argument indicates whether two's complement is\n\ +used to represent the integer."); + +static PyObject * +long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *byteorder_str; + PyObject *is_signed_obj = NULL; + int little_endian; + int is_signed; + PyObject *obj; + PyObject *bytes; + PyObject *long_obj; + static PyObject *little_str = NULL, *big_str = NULL; + static char *kwlist[] = {"bytes", "byteorder", "signed", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:from_bytes", kwlist, + &obj, &byteorder_str, + &is_signed_obj)) + return NULL; + + if (args != NULL && Py_SIZE(args) > 2) { + PyErr_SetString(PyExc_TypeError, + "'signed' is a keyword-only argument"); + return NULL; + } + if (little_str == NULL) { + little_str = PyUnicode_InternFromString("little"); + big_str = PyUnicode_InternFromString("big"); + if (little_str == NULL || big_str == NULL) + return NULL; + } + + if (PyObject_RichCompareBool(byteorder_str, little_str, Py_EQ)) + little_endian = 1; + else if (PyObject_RichCompareBool(byteorder_str, big_str, Py_EQ)) + little_endian = 0; + else { + PyErr_SetString(PyExc_ValueError, + "byteorder must be either 'little' or 'big'"); + return NULL; + } + + if (is_signed_obj != NULL) { + int cmp = PyObject_IsTrue(is_signed_obj); + if (cmp < 0) + return NULL; + is_signed = cmp ? 1 : 0; + } + else { + /* If the signed argument was omitted, use False as the + default. */ + is_signed = 0; + } + + bytes = PyObject_Bytes(obj); + if (bytes == NULL) + return NULL; + + long_obj = _PyLong_FromByteArray( + (unsigned char *)PyBytes_AS_STRING(bytes), Py_SIZE(bytes), + little_endian, is_signed); + Py_DECREF(bytes); + + /* If from_bytes() was used on subclass, allocate new subclass + * instance, initialize it with decoded long value and return it. + */ + if (type != &PyLong_Type && PyType_IsSubtype(type, &PyLong_Type)) { + PyLongObject *newobj; + int i; + Py_ssize_t n = ABS(Py_SIZE(long_obj)); + + newobj = (PyLongObject *)type->tp_alloc(type, n); + if (newobj == NULL) { + Py_DECREF(long_obj); + return NULL; + } + assert(PyLong_Check(newobj)); + Py_SIZE(newobj) = Py_SIZE(long_obj); + for (i = 0; i < n; i++) { + newobj->ob_digit[i] = + ((PyLongObject *)long_obj)->ob_digit[i]; + } + Py_DECREF(long_obj); + return (PyObject *)newobj; + } + + return long_obj; +} + static PyMethodDef long_methods[] = { {"conjugate", (PyCFunction)long_long, METH_NOARGS, "Returns self, the complex conjugate of any int."}, @@ -4305,6 +4500,10 @@ static PyMethodDef long_methods[] = { {"is_finite", (PyCFunction)long_is_finite, METH_NOARGS, "Returns always True."}, #endif + {"to_bytes", (PyCFunction)long_to_bytes, + METH_VARARGS|METH_KEYWORDS, long_to_bytes_doc}, + {"from_bytes", (PyCFunction)long_from_bytes, + METH_VARARGS|METH_KEYWORDS|METH_CLASS, long_from_bytes_doc}, {"__trunc__", (PyCFunction)long_long, METH_NOARGS, "Truncating an Integral returns itself."}, {"__floor__", (PyCFunction)long_long, METH_NOARGS, |