Skip to content

Commit 7094b3c

Browse files
authored
Merge pull request #223 from SwayamInSync/bytes_support
FEAT: Adding Byte support to QuadPrecision scalar constructor
2 parents 2cbc0c6 + 25f0338 commit 7094b3c

File tree

13 files changed

+248
-57
lines changed

13 files changed

+248
-57
lines changed

quaddtype/meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ srcs = [
175175
'numpy_quaddtype/src/umath/matmul.h',
176176
'numpy_quaddtype/src/umath/matmul.cpp',
177177
'numpy_quaddtype/src/constants.hpp',
178+
'numpy_quaddtype/src/lock.h',
179+
'numpy_quaddtype/src/lock.c',
180+
'numpy_quaddtype/src/utilities.h',
181+
'numpy_quaddtype/src/utilities.c',
178182
]
179183

180184
py.install_sources(

quaddtype/numpy_quaddtype/_quaddtype_main.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ _IntoQuad: TypeAlias = (
99
QuadPrecision
1010
| float
1111
| str
12+
| bytes
1213
| np.floating[Any]
1314
| np.integer[Any]
1415
| np.bool_

quaddtype/numpy_quaddtype/src/casts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ init_casts_internal(void)
830830
add_spec(quad2quad_spec);
831831

832832
PyArray_DTypeMeta **void_dtypes = new PyArray_DTypeMeta *[2]{&PyArray_VoidDType, &QuadPrecDType};
833-
PyType_Slot *void_slots = new PyType_Slot[]{
833+
PyType_Slot *void_slots = new PyType_Slot[4]{
834834
{NPY_METH_resolve_descriptors, (void *)&void_to_quad_resolve_descriptors},
835835
{NPY_METH_strided_loop, (void *)&void_to_quad_strided_loop},
836836
{NPY_METH_unaligned_strided_loop, (void *)&void_to_quad_strided_loop},

quaddtype/numpy_quaddtype/src/dtype.c

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
#include "numpy/ndarraytypes.h"
1414
#include "numpy/dtype_api.h"
1515

16+
#include "quad_common.h"
1617
#include "scalar.h"
1718
#include "casts.h"
1819
#include "dtype.h"
1920
#include "dragon4.h"
2021
#include "constants.hpp"
22+
#include "utilities.h"
2123

2224
static inline int
2325
quad_load(void *x, char *data_ptr, QuadBackendType backend)
@@ -353,19 +355,16 @@ quadprec_scanfunc(FILE *fp, void *dptr, char *ignore, PyArray_Descr *descr_gener
353355

354356
/* Convert string to quad precision */
355357
char *endptr;
358+
quad_value val;
359+
int err = cstring_to_quad(buffer, descr->backend, &val, &endptr, true);
360+
if (err < 0) {
361+
return 0; /* Return 0 on parse error (no items read) */
362+
}
356363
if (descr->backend == BACKEND_SLEEF) {
357-
Sleef_quad val = Sleef_strtoq(buffer, &endptr);
358-
if (endptr == buffer) {
359-
return 0; /* Return 0 on parse error (no items read) */
360-
}
361-
*(Sleef_quad *)dptr = val;
364+
*(Sleef_quad *)dptr = val.sleef_value;
362365
}
363366
else {
364-
long double val = strtold(buffer, &endptr);
365-
if (endptr == buffer) {
366-
return 0; /* Return 0 on parse error (no items read) */
367-
}
368-
*(long double *)dptr = val;
367+
*(long double *)dptr = val.longdouble_value;
369368
}
370369

371370
return 1; /* Return 1 on success (1 item read) */
@@ -375,22 +374,17 @@ static int
375374
quadprec_fromstr(char *s, void *dptr, char **endptr, PyArray_Descr *descr_generic)
376375
{
377376
QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)descr_generic;
378-
379-
if (descr->backend == BACKEND_SLEEF) {
380-
Sleef_quad val = Sleef_strtoq(s, endptr);
381-
if (*endptr == s) {
382-
return -1;
383-
}
384-
*(Sleef_quad *)dptr = val;
377+
quad_value val;
378+
int err = cstring_to_quad(s, descr->backend, &val, endptr, false);
379+
if (err < 0) {
380+
return -1;
381+
}
382+
if(descr->backend == BACKEND_SLEEF) {
383+
*(Sleef_quad *)dptr = val.sleef_value;
385384
}
386385
else {
387-
long double val = strtold(s, endptr);
388-
if (*endptr == s) {
389-
return -1;
390-
}
391-
*(long double *)dptr = val;
386+
*(long double *)dptr = val.longdouble_value;
392387
}
393-
394388
return 0;
395389
}
396390

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "lock.h"
2+
3+
#if PY_VERSION_HEX < 0x30d00b3
4+
PyThread_type_lock sleef_lock = NULL;
5+
#else
6+
PyMutex sleef_lock = {0};
7+
#endif
8+
9+
void init_sleef_locks(void)
10+
{
11+
#if PY_VERSION_HEX < 0x30d00b3
12+
sleef_lock = PyThread_allocate_lock();
13+
if (!sleef_lock) {
14+
PyErr_NoMemory();
15+
}
16+
#endif
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef _QUADDTYPE_LOCK_H
2+
#define _QUADDTYPE_LOCK_H
3+
4+
#include <Python.h>
5+
6+
#if PY_VERSION_HEX < 0x30d00b3
7+
extern PyThread_type_lock sleef_lock;
8+
#define LOCK_SLEEF PyThread_acquire_lock(sleef_lock, WAIT_LOCK)
9+
#define UNLOCK_SLEEF PyThread_release_lock(sleef_lock)
10+
#else
11+
extern PyMutex sleef_lock;
12+
#define LOCK_SLEEF PyMutex_Lock(&sleef_lock)
13+
#define UNLOCK_SLEEF PyMutex_Unlock(&sleef_lock)
14+
#endif
15+
16+
void init_sleef_locks(void);
17+
18+
#endif // _QUADDTYPE_LOCK_H

quaddtype/numpy_quaddtype/src/quad_common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
extern "C" {
66
#endif
77

8+
#include <sleef.h>
9+
#include <sleefquad.h>
10+
811
typedef enum {
912
BACKEND_INVALID = -1,
1013
BACKEND_SLEEF,
1114
BACKEND_LONGDOUBLE
1215
} QuadBackendType;
1316

17+
typedef union {
18+
Sleef_quad sleef_value;
19+
long double longdouble_value;
20+
} quad_value;
21+
1422
#ifdef __cplusplus
1523
}
1624
#endif

quaddtype/numpy_quaddtype/src/quaddtype_main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "numpy/dtype_api.h"
1313
#include "numpy/ufuncobject.h"
1414

15+
#include "lock.h"
1516
#include "scalar.h"
1617
#include "dtype.h"
1718
#include "umath/umath.h"
@@ -96,6 +97,8 @@ PyInit__quaddtype_main(void)
9697
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
9798
#endif
9899

100+
init_sleef_locks();
101+
99102
if (init_quadprecision_scalar() < 0)
100103
goto error;
101104

quaddtype/numpy_quaddtype/src/scalar.c

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,15 @@
1515
#include "scalar_ops.h"
1616
#include "dragon4.h"
1717
#include "dtype.h"
18+
#include "lock.h"
19+
#include "utilities.h"
1820

1921
// For IEEE 754 binary128 (quad precision), we need 36 decimal digits
2022
// to guarantee round-trip conversion (string -> parse -> equals original value)
2123
// Formula: ceil(1 + MANT_DIG * log10(2)) = ceil(1 + 113 * 0.30103) = 36
2224
// src: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
2325
#define SLEEF_QUAD_DECIMAL_DIG 36
2426

25-
#if PY_VERSION_HEX < 0x30d00b3
26-
static PyThread_type_lock sleef_lock;
27-
#define LOCK_SLEEF PyThread_acquire_lock(sleef_lock, WAIT_LOCK)
28-
#define UNLOCK_SLEEF PyThread_release_lock(sleef_lock)
29-
#else
30-
static PyMutex sleef_lock = {0};
31-
#define LOCK_SLEEF PyMutex_Lock(&sleef_lock)
32-
#define UNLOCK_SLEEF PyMutex_Unlock(&sleef_lock)
33-
#endif
34-
35-
36-
3727

3828
QuadPrecisionObject *
3929
QuadPrecision_raw_new(QuadBackendType backend)
@@ -207,14 +197,23 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
207197
else if (PyUnicode_Check(value)) {
208198
const char *s = PyUnicode_AsUTF8(value);
209199
char *endptr = NULL;
210-
if (backend == BACKEND_SLEEF) {
211-
self->value.sleef_value = Sleef_strtoq(s, &endptr);
200+
int err = cstring_to_quad(s, backend, &self->value, &endptr, true);
201+
if (err < 0) {
202+
PyErr_SetString(PyExc_ValueError, "Unable to parse string to QuadPrecision");
203+
Py_DECREF(self);
204+
return NULL;
212205
}
213-
else {
214-
self->value.longdouble_value = strtold(s, &endptr);
206+
}
207+
else if (PyBytes_Check(value)) {
208+
const char *s = PyBytes_AsString(value);
209+
if (s == NULL) {
210+
Py_DECREF(self);
211+
return NULL;
215212
}
216-
if (*endptr != '\0' || endptr == s) {
217-
PyErr_SetString(PyExc_ValueError, "Unable to parse string to QuadPrecision");
213+
char *endptr = NULL;
214+
int err = cstring_to_quad(s, backend, &self->value, &endptr, true);
215+
if (err < 0) {
216+
PyErr_SetString(PyExc_ValueError, "Unable to parse bytes to QuadPrecision");
218217
Py_DECREF(self);
219218
return NULL;
220219
}
@@ -242,21 +241,21 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
242241
const char *type_cstr = PyUnicode_AsUTF8(type_str);
243242
if (type_cstr != NULL) {
244243
PyErr_Format(PyExc_TypeError,
245-
"QuadPrecision value must be a quad, float, int, string, array or sequence, but got %s "
244+
"QuadPrecision value must be a quad, float, int, string, bytes, array or sequence, but got %s "
246245
"instead",
247246
type_cstr);
248247
}
249248
else {
250249
PyErr_SetString(
251250
PyExc_TypeError,
252-
"QuadPrecision value must be a quad, float, int, string, array or sequence, but got an "
251+
"QuadPrecision value must be a quad, float, int, string, bytes, array or sequence, but got an "
253252
"unknown type instead");
254253
}
255254
Py_DECREF(type_str);
256255
}
257256
else {
258257
PyErr_SetString(PyExc_TypeError,
259-
"QuadPrecision value must be a quad, float, int, string, array or sequence, but got an "
258+
"QuadPrecision value must be a quad, float, int, string, bytes, array or sequence, but got an "
260259
"unknown type instead");
261260
}
262261
Py_DECREF(self);
@@ -636,13 +635,6 @@ PyTypeObject QuadPrecision_Type = {
636635
int
637636
init_quadprecision_scalar(void)
638637
{
639-
#if PY_VERSION_HEX < 0x30d00b3
640-
sleef_lock = PyThread_allocate_lock();
641-
if (sleef_lock == NULL) {
642-
PyErr_NoMemory();
643-
return -1;
644-
}
645-
#endif
646638
QuadPrecision_Type.tp_base = &PyFloatingArrType_Type;
647639
return PyType_Ready(&QuadPrecision_Type);
648640
}

quaddtype/numpy_quaddtype/src/scalar.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ extern "C" {
99
#include <sleef.h>
1010
#include "quad_common.h"
1111

12-
typedef union {
13-
Sleef_quad sleef_value;
14-
long double longdouble_value;
15-
} quad_value;
16-
1712
typedef struct {
1813
PyObject_HEAD
1914
quad_value value;

0 commit comments

Comments
 (0)