summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-03-11 23:10:02 (GMT)
committerGitHub <noreply@github.com>2022-03-11 23:10:02 (GMT)
commit882d8096c262a5945e0cfdd706e5db3ad2b73543 (patch)
tree5e903c7e87a13203543e3e215f30b6b708df018d /Modules
parentecfff63e06e77e22035a7f7caa26986f033f3aea (diff)
downloadcpython-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.c17
-rw-r--r--Modules/_pickle.c5
-rw-r--r--Modules/_struct.c19
-rw-r--r--Modules/_testcapimodule.c81
-rw-r--r--Modules/arraymodule.c11
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;