cpython/Modules/_testcapi/long.c

289 lines
7.4 KiB
C

#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "parts.h"
#include "util.h"
#include "clinic/long.c.h"
/*[clinic input]
module _testcapi
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/
/*[clinic input]
_testcapi.call_long_compact_api
arg: object
/
[clinic start generated code]*/
static PyObject *
_testcapi_call_long_compact_api(PyObject *module, PyObject *arg)
/*[clinic end generated code: output=7e3894f611b1b2b7 input=87b87396967af14c]*/
{
assert(PyLong_Check(arg));
int is_compact = PyUnstable_Long_IsCompact((PyLongObject*)arg);
Py_ssize_t value = -1;
if (is_compact) {
value = PyUnstable_Long_CompactValue((PyLongObject*)arg);
}
return Py_BuildValue("in", is_compact, value);
}
static PyObject *
pylong_fromunicodeobject(PyObject *module, PyObject *args)
{
PyObject *unicode;
int base;
if (!PyArg_ParseTuple(args, "Oi", &unicode, &base)) {
return NULL;
}
NULLABLE(unicode);
return PyLong_FromUnicodeObject(unicode, base);
}
static PyObject *
pylong_asnativebytes(PyObject *module, PyObject *args)
{
PyObject *v;
Py_buffer buffer;
Py_ssize_t n, flags;
if (!PyArg_ParseTuple(args, "Ow*nn", &v, &buffer, &n, &flags)) {
return NULL;
}
if (buffer.readonly) {
PyErr_SetString(PyExc_TypeError, "buffer must be writable");
PyBuffer_Release(&buffer);
return NULL;
}
if (buffer.len < n) {
PyErr_SetString(PyExc_ValueError, "buffer must be at least 'n' bytes");
PyBuffer_Release(&buffer);
return NULL;
}
Py_ssize_t res = PyLong_AsNativeBytes(v, buffer.buf, n, (int)flags);
PyBuffer_Release(&buffer);
return res >= 0 ? PyLong_FromSsize_t(res) : NULL;
}
static PyObject *
pylong_fromnativebytes(PyObject *module, PyObject *args)
{
Py_buffer buffer;
Py_ssize_t n, flags, signed_;
if (!PyArg_ParseTuple(args, "y*nnn", &buffer, &n, &flags, &signed_)) {
return NULL;
}
if (buffer.len < n) {
PyErr_SetString(PyExc_ValueError, "buffer must be at least 'n' bytes");
PyBuffer_Release(&buffer);
return NULL;
}
PyObject *res = signed_
? PyLong_FromNativeBytes(buffer.buf, n, (int)flags)
: PyLong_FromUnsignedNativeBytes(buffer.buf, n, (int)flags);
PyBuffer_Release(&buffer);
return res;
}
static PyObject *
pylong_getsign(PyObject *module, PyObject *arg)
{
int sign;
NULLABLE(arg);
if (PyLong_GetSign(arg, &sign) == -1) {
return NULL;
}
return PyLong_FromLong(sign);
}
static PyObject *
pylong_ispositive(PyObject *module, PyObject *arg)
{
NULLABLE(arg);
RETURN_INT(PyLong_IsPositive(arg));
}
static PyObject *
pylong_isnegative(PyObject *module, PyObject *arg)
{
NULLABLE(arg);
RETURN_INT(PyLong_IsNegative(arg));
}
static PyObject *
pylong_iszero(PyObject *module, PyObject *arg)
{
NULLABLE(arg);
RETURN_INT(PyLong_IsZero(arg));
}
static PyObject *
pylong_aspid(PyObject *module, PyObject *arg)
{
NULLABLE(arg);
pid_t value = PyLong_AsPid(arg);
if (value == -1 && PyErr_Occurred()) {
return NULL;
}
return PyLong_FromPid(value);
}
static PyObject *
layout_to_dict(const PyLongLayout *layout)
{
return Py_BuildValue("{sisisisi}",
"bits_per_digit", (int)layout->bits_per_digit,
"digit_size", (int)layout->digit_size,
"digits_order", (int)layout->digits_order,
"digit_endianness", (int)layout->digit_endianness);
}
static PyObject *
pylong_export(PyObject *module, PyObject *obj)
{
PyLongExport export_long;
if (PyLong_Export(obj, &export_long) < 0) {
return NULL;
}
if (export_long.digits == NULL) {
assert(export_long.negative == 0);
assert(export_long.ndigits == 0);
assert(export_long.digits == NULL);
PyObject *res = PyLong_FromInt64(export_long.value);
PyLong_FreeExport(&export_long);
return res;
}
assert(PyLong_GetNativeLayout()->digit_size == sizeof(digit));
const digit *export_long_digits = export_long.digits;
PyObject *digits = PyList_New(0);
if (digits == NULL) {
goto error;
}
for (Py_ssize_t i = 0; i < export_long.ndigits; i++) {
PyObject *item = PyLong_FromUnsignedLong(export_long_digits[i]);
if (item == NULL) {
goto error;
}
if (PyList_Append(digits, item) < 0) {
Py_DECREF(item);
goto error;
}
Py_DECREF(item);
}
assert(export_long.value == 0);
PyObject *res = Py_BuildValue("(iN)", export_long.negative, digits);
PyLong_FreeExport(&export_long);
assert(export_long._reserved == 0);
return res;
error:
Py_XDECREF(digits);
PyLong_FreeExport(&export_long);
return NULL;
}
static PyObject *
pylongwriter_create(PyObject *module, PyObject *args)
{
int negative;
PyObject *list;
// TODO(vstinner): write test for negative ndigits and digits==NULL
if (!PyArg_ParseTuple(args, "iO!", &negative, &PyList_Type, &list)) {
return NULL;
}
Py_ssize_t ndigits = PyList_GET_SIZE(list);
digit *digits = PyMem_Malloc((size_t)ndigits * sizeof(digit));
if (digits == NULL) {
return PyErr_NoMemory();
}
for (Py_ssize_t i = 0; i < ndigits; i++) {
PyObject *item = PyList_GET_ITEM(list, i);
long num = PyLong_AsLong(item);
if (num == -1 && PyErr_Occurred()) {
goto error;
}
if (num < 0 || num >= PyLong_BASE) {
PyErr_SetString(PyExc_ValueError, "digit doesn't fit into digit");
goto error;
}
digits[i] = (digit)num;
}
void *writer_digits;
PyLongWriter *writer = PyLongWriter_Create(negative, ndigits,
&writer_digits);
if (writer == NULL) {
goto error;
}
assert(PyLong_GetNativeLayout()->digit_size == sizeof(digit));
memcpy(writer_digits, digits, (size_t)ndigits * sizeof(digit));
PyObject *res = PyLongWriter_Finish(writer);
PyMem_Free(digits);
return res;
error:
PyMem_Free(digits);
return NULL;
}
static PyObject *
get_pylong_layout(PyObject *module, PyObject *Py_UNUSED(args))
{
const PyLongLayout *layout = PyLong_GetNativeLayout();
return layout_to_dict(layout);
}
static PyMethodDef test_methods[] = {
_TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF
{"pylong_fromunicodeobject", pylong_fromunicodeobject, METH_VARARGS},
{"pylong_asnativebytes", pylong_asnativebytes, METH_VARARGS},
{"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS},
{"pylong_getsign", pylong_getsign, METH_O},
{"pylong_aspid", pylong_aspid, METH_O},
{"pylong_export", pylong_export, METH_O},
{"pylongwriter_create", pylongwriter_create, METH_VARARGS},
{"get_pylong_layout", get_pylong_layout, METH_NOARGS},
{"pylong_ispositive", pylong_ispositive, METH_O},
{"pylong_isnegative", pylong_isnegative, METH_O},
{"pylong_iszero", pylong_iszero, METH_O},
{NULL},
};
int
_PyTestCapi_Init_Long(PyObject *mod)
{
if (PyModule_AddFunctions(mod, test_methods) < 0) {
return -1;
}
return 0;
}