Skip to content

Commit f0e6b1f

Browse files
committed
StringDtype bypass PyUnicode creation
1 parent 4d14322 commit f0e6b1f

File tree

3 files changed

+103
-12
lines changed

3 files changed

+103
-12
lines changed

quaddtype/numpy_quaddtype/src/casts.cpp

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,39 @@ quad_to_string_adaptive(Sleef_quad *sleef_val, npy_intp unicode_size_chars)
369369
}
370370
}
371371

372+
static inline const char *
373+
quad_to_string_adaptive_cstr(Sleef_quad *sleef_val, npy_intp unicode_size_chars)
374+
{
375+
// Try positional format first to see if it would fit
376+
const char* positional_str = Dragon4_Positional_QuadDType_CStr(
377+
sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0, 1,
378+
TrimMode_LeaveOneZero, 1, 0);
379+
380+
if (positional_str == NULL) {
381+
PyErr_SetString(PyExc_RuntimeError, "Float formatting failed");
382+
return NULL;
383+
}
384+
385+
// no need to scan full, only checking if its longer
386+
npy_intp pos_len = strnlen(positional_str, unicode_size_chars + 1);
387+
388+
// If positional format fits, use it; otherwise use scientific notation
389+
if (pos_len <= unicode_size_chars) {
390+
return positional_str; // Keep the positional string
391+
}
392+
else {
393+
// Use scientific notation with full precision
394+
const char *scientific_str = Dragon4_Scientific_QuadDType_CStr(sleef_val, DigitMode_Unique,
395+
SLEEF_QUAD_DECIMAL_DIG, 0, 1,
396+
TrimMode_LeaveOneZero, 1, 2);
397+
if (scientific_str == NULL) {
398+
PyErr_SetString(PyExc_RuntimeError, "Float formatting failed");
399+
return NULL;
400+
}
401+
return scientific_str;
402+
}
403+
}
404+
372405
template <bool Aligned>
373406
static int
374407
quad_to_unicode_loop(PyArrayMethod_Context *context, char *const data[],
@@ -739,30 +772,21 @@ quad_to_stringdtype_strided_loop(PyArrayMethod_Context *context, char *const dat
739772

740773
// Get string representation with adaptive notation
741774
// Use a large buffer size to allow for full precision
742-
PyObject *py_str = quad_to_string_adaptive(&sleef_val, QUAD_STR_WIDTH);
743-
if (py_str == NULL) {
744-
NpyString_release_allocator(allocator);
745-
return -1;
746-
}
747-
748-
Py_ssize_t str_size;
749-
const char *str_buf = PyUnicode_AsUTF8AndSize(py_str, &str_size);
775+
const char *str_buf = quad_to_string_adaptive_cstr(&sleef_val, QUAD_STR_WIDTH);
750776
if (str_buf == NULL) {
751-
Py_DECREF(py_str);
752777
NpyString_release_allocator(allocator);
753778
return -1;
754779
}
755780

781+
Py_ssize_t str_size = strnlen(str_buf, QUAD_STR_WIDTH);
782+
756783
npy_packed_static_string *out_ps = (npy_packed_static_string *)out_ptr;
757784
if (NpyString_pack(allocator, out_ps, str_buf, (size_t)str_size) < 0) {
758-
Py_DECREF(py_str);
759785
NpyString_release_allocator(allocator);
760786
PyErr_SetString(PyExc_MemoryError, "Failed to pack string in Quad to StringDType cast");
761787
return -1;
762788
}
763789

764-
Py_DECREF(py_str);
765-
766790
in_ptr += in_stride;
767791
out_ptr += out_stride;
768792
}

quaddtype/numpy_quaddtype/src/dragon4.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,15 @@ Dragon4_Positional_QuadDType_opt(Sleef_quad *val, Dragon4_Options *opt)
19541954
return ret;
19551955
}
19561956

1957+
const char *
1958+
Dragon4_Positional_QuadDType_opt_cstr(Sleef_quad *val, Dragon4_Options *opt)
1959+
{;
1960+
if (Dragon4_PrintFloat_Sleef_quad(val, opt) < 0) {
1961+
return NULL;
1962+
}
1963+
return _bigint_static.repr;
1964+
}
1965+
19571966
PyObject *
19581967
Dragon4_Positional_QuadDType(Sleef_quad *val, DigitMode digit_mode, CutoffMode cutoff_mode,
19591968
int precision, int min_digits, int sign, TrimMode trim, int pad_left,
@@ -1975,6 +1984,27 @@ Dragon4_Positional_QuadDType(Sleef_quad *val, DigitMode digit_mode, CutoffMode c
19751984
return Dragon4_Positional_QuadDType_opt(val, &opt);
19761985
}
19771986

1987+
const char *
1988+
Dragon4_Positional_QuadDType_CStr(Sleef_quad *val, DigitMode digit_mode, CutoffMode cutoff_mode,
1989+
int precision, int min_digits, int sign, TrimMode trim, int pad_left,
1990+
int pad_right)
1991+
{
1992+
Dragon4_Options opt;
1993+
1994+
opt.scientific = 0;
1995+
opt.digit_mode = digit_mode;
1996+
opt.cutoff_mode = cutoff_mode;
1997+
opt.precision = precision;
1998+
opt.min_digits = min_digits;
1999+
opt.sign = sign;
2000+
opt.trim_mode = trim;
2001+
opt.digits_left = pad_left;
2002+
opt.digits_right = pad_right;
2003+
opt.exp_digits = -1;
2004+
2005+
return Dragon4_Positional_QuadDType_opt_cstr(val, &opt);
2006+
}
2007+
19782008
PyObject *
19792009
Dragon4_Scientific_QuadDType_opt(Sleef_quad *val, Dragon4_Options *opt)
19802010
{
@@ -1986,6 +2016,15 @@ Dragon4_Scientific_QuadDType_opt(Sleef_quad *val, Dragon4_Options *opt)
19862016
return ret;
19872017
}
19882018

2019+
const char *
2020+
Dragon4_Scientific_QuadDType_opt_cstr(Sleef_quad *val, Dragon4_Options *opt)
2021+
{
2022+
if (Dragon4_PrintFloat_Sleef_quad(val, opt) < 0) {
2023+
return NULL;
2024+
}
2025+
return _bigint_static.repr;
2026+
}
2027+
19892028
PyObject *
19902029
Dragon4_Scientific_QuadDType(Sleef_quad *val, DigitMode digit_mode, int precision, int min_digits,
19912030
int sign, TrimMode trim, int pad_left, int exp_digits)
@@ -2006,6 +2045,26 @@ Dragon4_Scientific_QuadDType(Sleef_quad *val, DigitMode digit_mode, int precisio
20062045
return Dragon4_Scientific_QuadDType_opt(val, &opt);
20072046
}
20082047

2048+
const char *
2049+
Dragon4_Scientific_QuadDType_CStr(Sleef_quad *val, DigitMode digit_mode, int precision, int min_digits,
2050+
int sign, TrimMode trim, int pad_left, int exp_digits)
2051+
{
2052+
Dragon4_Options opt;
2053+
2054+
opt.scientific = 1;
2055+
opt.digit_mode = digit_mode;
2056+
opt.cutoff_mode = CutoffMode_TotalLength;
2057+
opt.precision = precision;
2058+
opt.min_digits = min_digits;
2059+
opt.sign = sign;
2060+
opt.trim_mode = trim;
2061+
opt.digits_left = pad_left;
2062+
opt.digits_right = -1;
2063+
opt.exp_digits = exp_digits;
2064+
2065+
return Dragon4_Scientific_QuadDType_opt_cstr(val, &opt);
2066+
}
2067+
20092068
PyObject *
20102069
Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode, int precision,
20112070
int min_digits, int sign, TrimMode trim, int pad_left, int pad_right)

quaddtype/numpy_quaddtype/src/dragon4.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,18 @@ PyObject *Dragon4_Positional_QuadDType(Sleef_quad *val, DigitMode digit_mode,
5151
CutoffMode cutoff_mode, int precision, int min_digits,
5252
int sign, TrimMode trim, int pad_left, int pad_right);
5353

54+
const char *Dragon4_Positional_QuadDType_CStr(Sleef_quad *val, DigitMode digit_mode,
55+
CutoffMode cutoff_mode, int precision, int min_digits,
56+
int sign, TrimMode trim, int pad_left, int pad_right);
57+
5458
PyObject *Dragon4_Scientific_QuadDType(Sleef_quad *val, DigitMode digit_mode,
5559
int precision, int min_digits, int sign, TrimMode trim,
5660
int pad_left, int exp_digits);
5761

62+
const char *Dragon4_Scientific_QuadDType_CStr(Sleef_quad *val, DigitMode digit_mode,
63+
int precision, int min_digits, int sign, TrimMode trim,
64+
int pad_left, int exp_digits);
65+
5866
PyObject *Dragon4_Positional(PyObject *obj, DigitMode digit_mode,
5967
CutoffMode cutoff_mode, int precision, int min_digits,
6068
int sign, TrimMode trim, int pad_left, int pad_right);

0 commit comments

Comments
 (0)