-
-
Notifications
You must be signed in to change notification settings - Fork 3k
[mypyc] feat: new primitive for int.to_bytes
#19674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 23 commits
2058f81
f62bfd2
813c510
4be77d6
cb93329
6ff1c9b
166b6f4
be2d2de
9ff3a7c
8399619
db7b483
ed05c00
a0c147b
5bab265
b346bbf
8d523a0
85652a2
8e97165
3660a01
6a8a83c
ec95008
95fa8b0
78f4ca1
326484b
245a122
d2994e1
1138448
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -581,3 +581,59 @@ double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y) { | |
} | ||
return 1.0; | ||
} | ||
|
||
// int.to_bytes(length, byteorder, signed=False) | ||
PyObject *CPyTagged_ToBytes(CPyTagged self, Py_ssize_t length, PyObject *byteorder, int signed_flag) { | ||
PyObject *pyint = CPyTagged_StealAsObject(self); | ||
if (!PyLong_Check(pyint)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the second thought, all these type checks look unnecessary, normally Python wrappers should do them. You can probably verify this by adding some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what, like this? def f(x: Any) -> bytes:
return int.to_bytes(x) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
First, not just the def to_bytes(n: int, length: int, byteorder: str = "little", signed: bool = False) -> bytes:
return n.to_bytes(length, byteorder, signed=signed)
x: Any = "no"
bad: Any = "way"
to_bytes(x, bad) and check that a |
||
Py_DECREF(pyint); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I think these decrefs may be wrong, can you add a test with a long integer (something that doesn't fit in 64 bits)? |
||
PyErr_SetString(PyExc_TypeError, "self must be int"); | ||
return NULL; | ||
} | ||
if (!PyUnicode_Check(byteorder)) { | ||
Py_DECREF(pyint); | ||
PyErr_SetString(PyExc_TypeError, "byteorder must be str"); | ||
return NULL; | ||
} | ||
const char *order = PyUnicode_AsUTF8(byteorder); | ||
if (!order) { | ||
Py_DECREF(pyint); | ||
return NULL; | ||
} | ||
PyObject *result = CPyLong_ToBytes(pyint, length, order, signed_flag); | ||
Py_DECREF(pyint); | ||
return result; | ||
} | ||
|
||
|
||
// Helper for CPyLong_ToBytes (Python 3.2+) | ||
PyObject *CPyLong_ToBytes(PyObject *v, Py_ssize_t length, const char *byteorder, int signed_flag) { | ||
BobTheBuidler marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// This is a wrapper for PyLong_AsByteArray and PyBytes_FromStringAndSize | ||
unsigned char *bytes = (unsigned char *)PyMem_Malloc(length); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can avoid allocating a temporary buffer if you call |
||
if (!bytes) { | ||
PyErr_NoMemory(); | ||
return NULL; | ||
} | ||
int little_endian; | ||
if (strcmp(byteorder, "big") == 0) { | ||
little_endian = 0; | ||
} else if (strcmp(byteorder, "little") == 0) { | ||
little_endian = 1; | ||
} else { | ||
PyMem_Free(bytes); | ||
PyErr_SetString(PyExc_ValueError, "byteorder must be either 'little' or 'big'"); | ||
return NULL; | ||
} | ||
#if PY_VERSION_HEX >= 0x030D0000 // 3.13.0 | ||
int res = _PyLong_AsByteArray((PyLongObject *)v, bytes, length, little_endian, signed_flag, 1); | ||
#else | ||
int res = _PyLong_AsByteArray((PyLongObject *)v, bytes, length, little_endian, signed_flag); | ||
#endif | ||
if (res < 0) { | ||
PyMem_Free(bytes); | ||
return NULL; | ||
} | ||
PyObject *result = PyBytes_FromStringAndSize((const char *)bytes, length); | ||
PyMem_Free(bytes); | ||
return result; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -572,3 +572,12 @@ class subc(int): | |
[file userdefinedint.py] | ||
class int: | ||
pass | ||
|
||
[case testIntToBytes] | ||
def to_bytes(n: int, length: int, byteorder: str, signed: bool = False) -> bytes: | ||
return n.to_bytes(length, byteorder, signed=signed) | ||
def test_to_bytes() -> None: | ||
assert to_bytes(255, 2, "big") == b'\x00\xff' | ||
assert to_bytes(255, 2, "little") == b'\xff\x00' | ||
assert to_bytes(-1, 2, "big", True) == b'\xff\xff' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add overflow error tests. |
||
assert to_bytes(0, 1, "big") == b'\x00' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe also test calling |
Uh oh!
There was an error while loading. Please reload this page.