Skip to content

Commit 7e9df19

Browse files
committed
refactoring duplicated logic
1 parent d1605c7 commit 7e9df19

File tree

3 files changed

+116
-141
lines changed

3 files changed

+116
-141
lines changed

quaddtype/numpy_quaddtype/src/casts.cpp

Lines changed: 100 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,42 @@ unicode_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
198198
return NPY_UNSAFE_CASTING;
199199
}
200200

201+
// Helper function: Convert UCS4 string to quad_value
202+
static inline int
203+
unicode_to_quad_convert(const Py_UCS4 *ucs4_str, npy_intp unicode_size_chars,
204+
QuadBackendType backend, quad_value *out_val)
205+
{
206+
// Temporary buffer to convert UCS4 to null-terminated char string
207+
char temp_str[QUAD_STR_WIDTH + 1];
208+
npy_intp copy_len = unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
209+
210+
// Convert UCS4 characters to ASCII/char
211+
npy_intp i;
212+
for (i = 0; i < copy_len; i++) {
213+
Py_UCS4 c = ucs4_str[i];
214+
215+
// reject non-ASCII characters
216+
if (c > 127) {
217+
PyErr_Format(PyExc_ValueError,
218+
"Cannot cast non-ASCII character '%c' to QuadPrecision", c);
219+
return -1;
220+
}
221+
222+
temp_str[i] = (char)c;
223+
}
224+
temp_str[i] = '\0';
225+
226+
char *endptr;
227+
int err = cstring_to_quad(temp_str, backend, out_val, &endptr, true);
228+
if (err < 0) {
229+
PyErr_Format(PyExc_ValueError,
230+
"could not convert string to QuadPrecision: np.str_('%s')", temp_str);
231+
return -1;
232+
}
233+
234+
return 0;
235+
}
236+
201237
static int
202238
unicode_to_quad_strided_loop_unaligned(PyArrayMethod_Context *context, char *const data[],
203239
npy_intp const dimensions[], npy_intp const strides[],
@@ -217,33 +253,10 @@ unicode_to_quad_strided_loop_unaligned(PyArrayMethod_Context *context, char *con
217253
npy_intp unicode_size_chars = descrs[0]->elsize / 4;
218254

219255
while (N--) {
220-
// Temporary buffer to convert UCS4 to null-terminated char string
221-
char temp_str[QUAD_STR_WIDTH + 1];
222-
npy_intp copy_len =
223-
unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
224-
// Convert UCS4 characters to ASCII/char
225256
Py_UCS4 *ucs4_str = (Py_UCS4 *)in_ptr;
226-
npy_intp i;
227-
for (i = 0; i < copy_len; i++) {
228-
Py_UCS4 c = ucs4_str[i];
229-
230-
// reject non-ASCII characters
231-
if (c > 127) {
232-
PyErr_Format(PyExc_ValueError,
233-
"Cannot cast non-ASCII character '%c' to QuadPrecision", c);
234-
return -1;
235-
}
236-
237-
temp_str[i] = (char)c;
238-
}
239-
temp_str[i] = '\0';
240-
241257
quad_value out_val;
242-
char *endptr;
243-
int err = cstring_to_quad(temp_str, backend, &out_val, &endptr, true);
244-
if (err < 0) {
245-
PyErr_Format(PyExc_ValueError,
246-
"could not convert string to QuadPrecision: np.str_('%s')", temp_str);
258+
259+
if (unicode_to_quad_convert(ucs4_str, unicode_size_chars, backend, &out_val) < 0) {
247260
return -1;
248261
}
249262

@@ -280,33 +293,10 @@ unicode_to_quad_strided_loop_aligned(PyArrayMethod_Context *context, char *const
280293
npy_intp unicode_size_chars = descrs[0]->elsize / 4;
281294

282295
while (N--) {
283-
// Temporary buffer to convert UCS4 to null-terminated char string
284-
char temp_str[QUAD_STR_WIDTH + 1];
285-
npy_intp copy_len =
286-
unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
287-
// Convert UCS4 characters to ASCII/char
288296
Py_UCS4 *ucs4_str = (Py_UCS4 *)in_ptr;
289-
npy_intp i;
290-
for (i = 0; i < copy_len; i++) {
291-
Py_UCS4 c = ucs4_str[i];
292-
293-
// reject non-ASCII characters
294-
if (c > 127) {
295-
PyErr_Format(PyExc_ValueError,
296-
"Cannot cast non-ASCII character '%c' to QuadPrecision", c);
297-
return -1;
298-
}
299-
300-
temp_str[i] = (char)c;
301-
}
302-
temp_str[i] = '\0';
303-
304297
quad_value out_val;
305-
char *endptr;
306-
int err = cstring_to_quad(temp_str, backend, &out_val, &endptr, true);
307-
if (err < 0) {
308-
PyErr_Format(PyExc_ValueError,
309-
"could not convert string to QuadPrecision: np.str_('%s')", temp_str);
298+
299+
if (unicode_to_quad_convert(ucs4_str, unicode_size_chars, backend, &out_val) < 0) {
310300
return -1;
311301
}
312302

@@ -351,6 +341,56 @@ quad_to_unicode_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
351341
return NPY_UNSAFE_CASTING;
352342
}
353343

344+
// Helper function: Convert quad to string with adaptive notation
345+
static inline PyObject *
346+
quad_to_string_adaptive(Sleef_quad *sleef_val, npy_intp unicode_size_chars)
347+
{
348+
// Try positional format first to see if it would fit
349+
PyObject *positional_str = Dragon4_Positional_QuadDType(
350+
sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0, 1,
351+
TrimMode_LeaveOneZero, 1, 0);
352+
353+
if (positional_str == NULL) {
354+
return NULL;
355+
}
356+
357+
const char *pos_str = PyUnicode_AsUTF8(positional_str);
358+
if (pos_str == NULL) {
359+
Py_DECREF(positional_str);
360+
return NULL;
361+
}
362+
363+
npy_intp pos_len = strlen(pos_str);
364+
365+
// If positional format fits, use it; otherwise use scientific notation
366+
if (pos_len <= unicode_size_chars) {
367+
return positional_str; // Keep the positional string
368+
}
369+
else {
370+
Py_DECREF(positional_str);
371+
// Use scientific notation with full precision
372+
return Dragon4_Scientific_QuadDType(sleef_val, DigitMode_Unique,
373+
SLEEF_QUAD_DECIMAL_DIG, 0, 1,
374+
TrimMode_LeaveOneZero, 1, 2);
375+
}
376+
}
377+
378+
// Helper function: Copy string to UCS4 output buffer
379+
static inline void
380+
copy_string_to_ucs4(const char *str, Py_UCS4 *out_ucs4, npy_intp unicode_size_chars)
381+
{
382+
npy_intp str_len = strlen(str);
383+
384+
for (npy_intp i = 0; i < unicode_size_chars; i++) {
385+
if (i < str_len) {
386+
out_ucs4[i] = (Py_UCS4)str[i];
387+
}
388+
else {
389+
out_ucs4[i] = 0;
390+
}
391+
}
392+
}
393+
354394
static int
355395
quad_to_unicode_loop_unaligned(PyArrayMethod_Context *context, char *const data[],
356396
npy_intp const dimensions[], npy_intp const strides[],
@@ -379,46 +419,14 @@ quad_to_unicode_loop_unaligned(PyArrayMethod_Context *context, char *const data[
379419
}
380420

381421
// Convert to Sleef_quad for Dragon4
382-
Sleef_quad sleef_val;
383-
if (backend == BACKEND_SLEEF) {
384-
sleef_val = in_val.sleef_value;
385-
}
386-
else {
387-
sleef_val = Sleef_cast_from_doubleq1(in_val.longdouble_value);
388-
}
389-
390-
// If positional format fits, use it; otherwise use scientific notation
391-
PyObject *py_str;
392-
PyObject *positional_str = Dragon4_Positional_QuadDType(
393-
&sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0, 1,
394-
TrimMode_LeaveOneZero, 1, 0);
395-
396-
if (positional_str == NULL) {
397-
return -1;
398-
}
422+
Sleef_quad sleef_val = quad_to_sleef_quad(&in_val, backend);
399423

400-
const char *pos_str = PyUnicode_AsUTF8(positional_str);
401-
if (pos_str == NULL) {
402-
Py_DECREF(positional_str);
424+
// Get string representation with adaptive notation
425+
PyObject *py_str = quad_to_string_adaptive(&sleef_val, unicode_size_chars);
426+
if (py_str == NULL) {
403427
return -1;
404428
}
405429

406-
npy_intp pos_len = strlen(pos_str);
407-
408-
if (pos_len <= unicode_size_chars) {
409-
py_str = positional_str; // Keep the positional string
410-
}
411-
else {
412-
Py_DECREF(positional_str);
413-
// Use scientific notation with full precision
414-
py_str = Dragon4_Scientific_QuadDType(&sleef_val, DigitMode_Unique,
415-
SLEEF_QUAD_DECIMAL_DIG, 0, 1,
416-
TrimMode_LeaveOneZero, 1, 2);
417-
if (py_str == NULL) {
418-
return -1;
419-
}
420-
}
421-
422430
const char *temp_str = PyUnicode_AsUTF8(py_str);
423431
if (temp_str == NULL) {
424432
Py_DECREF(py_str);
@@ -427,16 +435,7 @@ quad_to_unicode_loop_unaligned(PyArrayMethod_Context *context, char *const data[
427435

428436
// Convert char string to UCS4 and store in output
429437
Py_UCS4 *out_ucs4 = (Py_UCS4 *)out_ptr;
430-
npy_intp str_len = strlen(temp_str);
431-
432-
for (npy_intp i = 0; i < unicode_size_chars; i++) {
433-
if (i < str_len) {
434-
out_ucs4[i] = (Py_UCS4)temp_str[i];
435-
}
436-
else {
437-
out_ucs4[i] = 0;
438-
}
439-
}
438+
copy_string_to_ucs4(temp_str, out_ucs4, unicode_size_chars);
440439

441440
Py_DECREF(py_str);
442441

@@ -474,45 +473,14 @@ quad_to_unicode_loop_aligned(PyArrayMethod_Context *context, char *const data[],
474473
}
475474

476475
// Convert to Sleef_quad for Dragon4
477-
Sleef_quad sleef_val;
478-
if (backend == BACKEND_SLEEF) {
479-
sleef_val = in_val.sleef_value;
480-
}
481-
else {
482-
sleef_val = Sleef_cast_from_doubleq1(in_val.longdouble_value);
483-
}
476+
Sleef_quad sleef_val = quad_to_sleef_quad(&in_val, backend);
484477

485-
PyObject *py_str;
486-
PyObject *positional_str = Dragon4_Positional_QuadDType(
487-
&sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0, 1,
488-
TrimMode_LeaveOneZero, 1, 0);
489-
490-
if (positional_str == NULL) {
478+
// Get string representation with adaptive notation
479+
PyObject *py_str = quad_to_string_adaptive(&sleef_val, unicode_size_chars);
480+
if (py_str == NULL) {
491481
return -1;
492482
}
493483

494-
const char *pos_str = PyUnicode_AsUTF8(positional_str);
495-
if (pos_str == NULL) {
496-
Py_DECREF(positional_str);
497-
return -1;
498-
}
499-
500-
npy_intp pos_len = strlen(pos_str);
501-
502-
if (pos_len <= unicode_size_chars) {
503-
py_str = positional_str;
504-
}
505-
else {
506-
Py_DECREF(positional_str);
507-
// Use scientific notation with full precision
508-
py_str = Dragon4_Scientific_QuadDType(&sleef_val, DigitMode_Unique,
509-
SLEEF_QUAD_DECIMAL_DIG, 0, 1,
510-
TrimMode_LeaveOneZero, 1, 2);
511-
if (py_str == NULL) {
512-
return -1;
513-
}
514-
}
515-
516484
const char *temp_str = PyUnicode_AsUTF8(py_str);
517485
if (temp_str == NULL) {
518486
Py_DECREF(py_str);
@@ -521,16 +489,7 @@ quad_to_unicode_loop_aligned(PyArrayMethod_Context *context, char *const data[],
521489

522490
// Convert char string to UCS4 and store in output
523491
Py_UCS4 *out_ucs4 = (Py_UCS4 *)out_ptr;
524-
npy_intp str_len = strlen(temp_str);
525-
526-
for (npy_intp i = 0; i < unicode_size_chars; i++) {
527-
if (i < str_len) {
528-
out_ucs4[i] = (Py_UCS4)temp_str[i];
529-
}
530-
else {
531-
out_ucs4[i] = 0;
532-
}
533-
}
492+
copy_string_to_ucs4(temp_str, out_ucs4, unicode_size_chars);
534493

535494
Py_DECREF(py_str);
536495

quaddtype/numpy_quaddtype/src/utilities.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,16 @@ char **endptr, bool require_full_parse)
1717
return -1; // parse error - characters remain to be converted
1818

1919
return 0; // success
20+
}
21+
22+
// Helper function: Convert quad_value to Sleef_quad for Dragon4
23+
Sleef_quad
24+
quad_to_sleef_quad(const quad_value *in_val, QuadBackendType backend)
25+
{
26+
if (backend == BACKEND_SLEEF) {
27+
return in_val->sleef_value;
28+
}
29+
else {
30+
return Sleef_cast_from_doubleq1(in_val->longdouble_value);
31+
}
2032
}

quaddtype/numpy_quaddtype/src/utilities.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ extern "C" {
1212

1313
int cstring_to_quad(const char *str, QuadBackendType backend, quad_value *out_value, char **endptr, bool require_full_parse);
1414

15+
// Helper function: Convert quad_value to Sleef_quad for Dragon4
16+
Sleef_quad
17+
quad_to_sleef_quad(const quad_value *in_val, QuadBackendType backend);
18+
1519
#ifdef __cplusplus
1620
}
1721
#endif

0 commit comments

Comments
 (0)