mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 6446408d42
			
		
	
	
		6446408d42
		
			
		
	
	
	
	
		
			
			Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Steve Dower <steve.dower@microsoft.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
		
			
				
	
	
		
			288 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			288 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;
 | |
| }
 |