* In order to not pack a whole copy of a floating point parser, we copy the * result into ascii and call the Python one. Float parsing isn't super quick * so this is not terrible, but avoiding it would speed up things. * * Also note that parsing the first float of a complex will copy the whole * string to ascii rather than just the first part. * TODO: A tweak of the break might be a simple
| 48 | * @param result Output stored as double value. |
| 49 | */ |
| 50 | static inline int |
| 51 | double_from_ucs4( |
| 52 | const Py_UCS4 *str, const Py_UCS4 *end, |
| 53 | bool strip_whitespace, double *result, const Py_UCS4 **p_end) |
| 54 | { |
| 55 | /* skip leading whitespace */ |
| 56 | if (strip_whitespace) { |
| 57 | while (Py_UNICODE_ISSPACE(*str)) { |
| 58 | str++; |
| 59 | } |
| 60 | } |
| 61 | if (str == end) { |
| 62 | return -1; /* empty or only whitespace: not a floating point number */ |
| 63 | } |
| 64 | |
| 65 | /* We convert to ASCII for the Python parser, use stack if small: */ |
| 66 | char stack_buf[128]; |
| 67 | char *heap_buf = NULL; |
| 68 | char *ascii = stack_buf; |
| 69 | |
| 70 | size_t str_len = end - str + 1; |
| 71 | if (str_len > 128) { |
| 72 | heap_buf = PyMem_MALLOC(str_len); |
| 73 | if (heap_buf == NULL) { |
| 74 | PyErr_NoMemory(); |
| 75 | return -1; |
| 76 | } |
| 77 | ascii = heap_buf; |
| 78 | } |
| 79 | char *c = ascii; |
| 80 | for (; str < end; str++, c++) { |
| 81 | if (NPY_UNLIKELY(*str >= 128)) { |
| 82 | /* Character cannot be used, ignore for end calculation and stop */ |
| 83 | end = str; |
| 84 | break; |
| 85 | } |
| 86 | *c = (char)(*str); |
| 87 | } |
| 88 | *c = '\0'; |
| 89 | |
| 90 | char *end_parsed; |
| 91 | *result = PyOS_string_to_double(ascii, &end_parsed, NULL); |
| 92 | /* Rewind `end` to the first UCS4 character not parsed: */ |
| 93 | end = end - (c - end_parsed); |
| 94 | |
| 95 | PyMem_FREE(heap_buf); |
| 96 | |
| 97 | if (*result == -1. && PyErr_Occurred()) { |
| 98 | return -1; |
| 99 | } |
| 100 | |
| 101 | if (strip_whitespace) { |
| 102 | /* and then skip any remaining whitespace: */ |
| 103 | while (Py_UNICODE_ISSPACE(*end)) { |
| 104 | end++; |
| 105 | } |
| 106 | } |
| 107 | *p_end = end; |
no outgoing calls
no test coverage detected