mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Issue #1023290: Added API for the conversion of longs to bytes and vice-versa.
This commit is contained in:
parent
a28e7028f9
commit
c36c3789de
4 changed files with 497 additions and 0 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue