diff options
author | Victor Stinner <vstinner@python.org> | 2022-03-11 23:10:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-11 23:10:02 (GMT) |
commit | 882d8096c262a5945e0cfdd706e5db3ad2b73543 (patch) | |
tree | 5e903c7e87a13203543e3e215f30b6b708df018d /Modules | |
parent | ecfff63e06e77e22035a7f7caa26986f033f3aea (diff) | |
download | cpython-882d8096c262a5945e0cfdd706e5db3ad2b73543.zip cpython-882d8096c262a5945e0cfdd706e5db3ad2b73543.tar.gz cpython-882d8096c262a5945e0cfdd706e5db3ad2b73543.tar.bz2 |
bpo-46906: Add PyFloat_Pack8() to the C API (GH-31657)
Add new functions to pack and unpack C double (serialize and
deserialize):
* PyFloat_Pack2(), PyFloat_Pack4(), PyFloat_Pack8()
* PyFloat_Unpack2(), PyFloat_Unpack4(), PyFloat_Unpack8()
Document these functions and add unit tests.
Rename private functions and move them from the internal C API
to the public C API:
* _PyFloat_Pack2() => PyFloat_Pack2()
* _PyFloat_Pack4() => PyFloat_Pack4()
* _PyFloat_Pack8() => PyFloat_Pack8()
* _PyFloat_Unpack2() => PyFloat_Unpack2()
* _PyFloat_Unpack4() => PyFloat_Unpack4()
* _PyFloat_Unpack8() => PyFloat_Unpack8()
Replace the "unsigned char*" type with "char*" which is more common
and easy to use.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_ctypes/cfield.c | 17 | ||||
-rw-r--r-- | Modules/_pickle.c | 5 | ||||
-rw-r--r-- | Modules/_struct.c | 19 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 81 | ||||
-rw-r--r-- | Modules/arraymodule.c | 11 |
5 files changed, 103 insertions, 30 deletions
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 2992d34..3b769f9 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -10,7 +10,6 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#include "pycore_floatobject.h" // _PyFloat_Pack8() #include <ffi.h> #include "ctypes.h" @@ -1009,10 +1008,10 @@ d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) if (x == -1 && PyErr_Occurred()) return NULL; #ifdef WORDS_BIGENDIAN - if (_PyFloat_Pack8(x, (unsigned char *)ptr, 1)) + if (PyFloat_Pack8(x, ptr, 1)) return NULL; #else - if (_PyFloat_Pack8(x, (unsigned char *)ptr, 0)) + if (PyFloat_Pack8(x, ptr, 0)) return NULL; #endif _RET(value); @@ -1022,9 +1021,9 @@ static PyObject * d_get_sw(void *ptr, Py_ssize_t size) { #ifdef WORDS_BIGENDIAN - return PyFloat_FromDouble(_PyFloat_Unpack8(ptr, 1)); + return PyFloat_FromDouble(PyFloat_Unpack8(ptr, 1)); #else - return PyFloat_FromDouble(_PyFloat_Unpack8(ptr, 0)); + return PyFloat_FromDouble(PyFloat_Unpack8(ptr, 0)); #endif } @@ -1057,10 +1056,10 @@ f_set_sw(void *ptr, PyObject *value, Py_ssize_t size) if (x == -1 && PyErr_Occurred()) return NULL; #ifdef WORDS_BIGENDIAN - if (_PyFloat_Pack4(x, (unsigned char *)ptr, 1)) + if (PyFloat_Pack4(x, ptr, 1)) return NULL; #else - if (_PyFloat_Pack4(x, (unsigned char *)ptr, 0)) + if (PyFloat_Pack4(x, ptr, 0)) return NULL; #endif _RET(value); @@ -1070,9 +1069,9 @@ static PyObject * f_get_sw(void *ptr, Py_ssize_t size) { #ifdef WORDS_BIGENDIAN - return PyFloat_FromDouble(_PyFloat_Unpack4(ptr, 1)); + return PyFloat_FromDouble(PyFloat_Unpack4(ptr, 1)); #else - return PyFloat_FromDouble(_PyFloat_Unpack4(ptr, 0)); + return PyFloat_FromDouble(PyFloat_Unpack4(ptr, 0)); #endif } diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 19e8a71..84f469d 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -9,7 +9,6 @@ #endif #include "Python.h" -#include "pycore_floatobject.h" // _PyFloat_Pack8() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_runtime.h" // _Py_ID() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -2244,7 +2243,7 @@ save_float(PicklerObject *self, PyObject *obj) if (self->bin) { char pdata[9]; pdata[0] = BINFLOAT; - if (_PyFloat_Pack8(x, (unsigned char *)&pdata[1], 0) < 0) + if (PyFloat_Pack8(x, &pdata[1], 0) < 0) return -1; if (_Pickler_Write(self, pdata, 9) < 0) return -1; @@ -5395,7 +5394,7 @@ load_binfloat(UnpicklerObject *self) if (_Unpickler_Read(self, &s, 8) < 0) return -1; - x = _PyFloat_Unpack8((unsigned char *)s, 0); + x = PyFloat_Unpack8(s, 0); if (x == -1.0 && PyErr_Occurred()) return -1; diff --git a/Modules/_struct.c b/Modules/_struct.c index a2e14e8..7cd0ef8 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -10,7 +10,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "pycore_floatobject.h" // _PyFloat_Unpack2() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include <ctype.h> @@ -303,9 +302,7 @@ static PyObject * unpack_halffloat(const char *p, /* start of 2-byte string */ int le) /* true for little-endian, false for big-endian */ { - double x; - - x = _PyFloat_Unpack2((unsigned char *)p, le); + double x = PyFloat_Unpack2(p, le); if (x == -1.0 && PyErr_Occurred()) { return NULL; } @@ -324,7 +321,7 @@ pack_halffloat(_structmodulestate *state, "required argument is not a float"); return -1; } - return _PyFloat_Pack2(x, (unsigned char *)p, le); + return PyFloat_Pack2(x, p, le); } static PyObject * @@ -333,7 +330,7 @@ unpack_float(const char *p, /* start of 4-byte string */ { double x; - x = _PyFloat_Unpack4((unsigned char *)p, le); + x = PyFloat_Unpack4(p, le); if (x == -1.0 && PyErr_Occurred()) return NULL; return PyFloat_FromDouble(x); @@ -345,7 +342,7 @@ unpack_double(const char *p, /* start of 8-byte string */ { double x; - x = _PyFloat_Unpack8((unsigned char *)p, le); + x = PyFloat_Unpack8(p, le); if (x == -1.0 && PyErr_Occurred()) return NULL; return PyFloat_FromDouble(x); @@ -979,7 +976,7 @@ bp_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return _PyFloat_Pack4(x, (unsigned char *)p, 0); + return PyFloat_Pack4(x, p, 0); } static int @@ -991,7 +988,7 @@ bp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return _PyFloat_Pack8(x, (unsigned char *)p, 0); + return PyFloat_Pack8(x, p, 0); } static int @@ -1194,7 +1191,7 @@ lp_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return _PyFloat_Pack4(x, (unsigned char *)p, 1); + return PyFloat_Pack4(x, p, 1); } static int @@ -1206,7 +1203,7 @@ lp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return _PyFloat_Pack8(x, (unsigned char *)p, 1); + return PyFloat_Pack8(x, p, 1); } static formatdef lilendian_table[] = { diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6fa0cce..019c2b8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5775,6 +5775,85 @@ test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) } +// Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() +static PyObject * +test_float_pack(PyObject *self, PyObject *args) +{ + int size; + double d; + int le; + if (!PyArg_ParseTuple(args, "idi", &size, &d, &le)) { + return NULL; + } + switch (size) + { + case 2: + { + char data[2]; + if (PyFloat_Pack2(d, data, le) < 0) { + return NULL; + } + return PyBytes_FromStringAndSize(data, Py_ARRAY_LENGTH(data)); + } + case 4: + { + char data[4]; + if (PyFloat_Pack4(d, data, le) < 0) { + return NULL; + } + return PyBytes_FromStringAndSize(data, Py_ARRAY_LENGTH(data)); + } + case 8: + { + char data[8]; + if (PyFloat_Pack8(d, data, le) < 0) { + return NULL; + } + return PyBytes_FromStringAndSize(data, Py_ARRAY_LENGTH(data)); + } + default: break; + } + + PyErr_SetString(PyExc_ValueError, "size must 2, 4 or 8"); + return NULL; +} + + +// Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() +static PyObject * +test_float_unpack(PyObject *self, PyObject *args) +{ + assert(!PyErr_Occurred()); + const char *data; + Py_ssize_t size; + int le; + if (!PyArg_ParseTuple(args, "y#i", &data, &size, &le)) { + return NULL; + } + double d; + switch (size) + { + case 2: + d = PyFloat_Unpack2(data, le); + break; + case 4: + d = PyFloat_Unpack4(data, le); + break; + case 8: + d = PyFloat_Unpack8(data, le); + break; + default: + PyErr_SetString(PyExc_ValueError, "data length must 2, 4 or 8 bytes"); + return NULL; + } + + if (d == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyFloat_FromDouble(d); +} + + static PyObject *negative_dictoffset(PyObject *, PyObject *); static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*); @@ -6061,6 +6140,8 @@ static PyMethodDef TestMethods[] = { PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")}, {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, + {"float_pack", test_float_pack, METH_VARARGS, NULL}, + {"float_unpack", test_float_unpack, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 73104ce..18991f8 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -9,7 +9,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "pycore_floatobject.h" // _PyFloat_Unpack4() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include <stddef.h> // offsetof() @@ -2056,15 +2055,14 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, Py_ssize_t i; int le = (mformat_code == IEEE_754_FLOAT_LE) ? 1 : 0; Py_ssize_t itemcount = Py_SIZE(items) / 4; - const unsigned char *memstr = - (unsigned char *)PyBytes_AS_STRING(items); + const char *memstr = PyBytes_AS_STRING(items); converted_items = PyList_New(itemcount); if (converted_items == NULL) return NULL; for (i = 0; i < itemcount; i++) { PyObject *pyfloat = PyFloat_FromDouble( - _PyFloat_Unpack4(&memstr[i * 4], le)); + PyFloat_Unpack4(&memstr[i * 4], le)); if (pyfloat == NULL) { Py_DECREF(converted_items); return NULL; @@ -2078,15 +2076,14 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, Py_ssize_t i; int le = (mformat_code == IEEE_754_DOUBLE_LE) ? 1 : 0; Py_ssize_t itemcount = Py_SIZE(items) / 8; - const unsigned char *memstr = - (unsigned char *)PyBytes_AS_STRING(items); + const char *memstr = PyBytes_AS_STRING(items); converted_items = PyList_New(itemcount); if (converted_items == NULL) return NULL; for (i = 0; i < itemcount; i++) { PyObject *pyfloat = PyFloat_FromDouble( - _PyFloat_Unpack8(&memstr[i * 8], le)); + PyFloat_Unpack8(&memstr[i * 8], le)); if (pyfloat == NULL) { Py_DECREF(converted_items); return NULL; |