|
4 | 4 | #include <Python.h> |
5 | 5 | #include <stdint.h> |
6 | 6 | #include "CPy.h" |
| 7 | +#include "codepoint_extra_ops.h" |
7 | 8 | #include "librt_strings.h" |
8 | 9 |
|
9 | 10 | #define CPY_BOOL_ERROR 2 |
@@ -1153,6 +1154,44 @@ read_f64_be(PyObject *module, PyObject *const *args, size_t nargs) { |
1153 | 1154 | return PyFloat_FromDouble(CPyBytes_ReadF64BEUnsafe(data + index)); |
1154 | 1155 | } |
1155 | 1156 |
|
| 1157 | +// Codepoint classification helpers exposed to interpreted callers. |
| 1158 | +// The C-side names are prefixed `cp_` to avoid colliding with libc's |
| 1159 | +// <ctype.h> isspace / isdigit / etc. Compiled callers go through the |
| 1160 | +// LibRTStrings_* static inlines in codepoint_extra_ops.h instead. |
| 1161 | +// |
| 1162 | +// All wrappers parse a single int argument as i32 (codepoint) and |
| 1163 | +// dispatch to the corresponding LibRTStrings_* function. The parse |
| 1164 | +// step accepts any int but rejects values outside the i32 range with |
| 1165 | +// OverflowError, matching the input domain of the compiled fast path. |
| 1166 | + |
| 1167 | +// Parse a Python int as i32 codepoint. Returns 0 on success and writes |
| 1168 | +// the value to *out; returns -1 on error with a Python exception set. |
| 1169 | +static int |
| 1170 | +cp_parse_i32(PyObject *arg, int32_t *out) { |
| 1171 | + int overflow; |
| 1172 | + long c = PyLong_AsLongAndOverflow(arg, &overflow); |
| 1173 | + if (c == -1 && PyErr_Occurred()) |
| 1174 | + return -1; |
| 1175 | + if (overflow != 0 || c < INT32_MIN || c > INT32_MAX) { |
| 1176 | + PyErr_SetString(PyExc_OverflowError, |
| 1177 | + "codepoint out of i32 range"); |
| 1178 | + return -1; |
| 1179 | + } |
| 1180 | + *out = (int32_t)c; |
| 1181 | + return 0; |
| 1182 | +} |
| 1183 | + |
| 1184 | +#define DEFINE_CP_BOOL_WRAPPER(name, fn) \ |
| 1185 | + static PyObject* \ |
| 1186 | + cp_##name(PyObject *module, PyObject *arg) { \ |
| 1187 | + int32_t c; \ |
| 1188 | + if (cp_parse_i32(arg, &c) < 0) \ |
| 1189 | + return NULL; \ |
| 1190 | + return PyBool_FromLong(fn(c)); \ |
| 1191 | + } |
| 1192 | + |
| 1193 | +DEFINE_CP_BOOL_WRAPPER(isspace, LibRTStrings_IsSpace) |
| 1194 | + |
1156 | 1195 | static PyMethodDef librt_strings_module_methods[] = { |
1157 | 1196 | {"write_i16_le", (PyCFunction) write_i16_le, METH_FASTCALL, |
1158 | 1197 | PyDoc_STR("Write a 16-bit signed integer to BytesWriter in little-endian format") |
@@ -1214,6 +1253,9 @@ static PyMethodDef librt_strings_module_methods[] = { |
1214 | 1253 | {"read_f64_be", (PyCFunction) read_f64_be, METH_FASTCALL, |
1215 | 1254 | PyDoc_STR("Read a 64-bit float from bytes in big-endian format") |
1216 | 1255 | }, |
| 1256 | + {"isspace", cp_isspace, METH_O, |
| 1257 | + PyDoc_STR("Test whether a codepoint (i32) is Unicode whitespace.") |
| 1258 | + }, |
1217 | 1259 | {NULL, NULL, 0, NULL} |
1218 | 1260 | }; |
1219 | 1261 |
|
|
0 commit comments