Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mypy/typeshed/stubs/librt/librt/strings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ def read_f64_be(b: bytes, index: i64, /) -> float: ...
# Codepoint classification helpers operating on i32 codepoints (typically
# obtained via ord(s[i])). Negative inputs return False.
def isspace(c: i32, /) -> bool: ...
def isdigit(c: i32, /) -> bool: ...
4 changes: 4 additions & 0 deletions mypyc/lib-rt/codepoint_extra_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ static inline bool LibRTStrings_IsSpace(int32_t c) {
return c >= 0 && Py_UNICODE_ISSPACE((Py_UCS4)c);
}

static inline bool LibRTStrings_IsDigit(int32_t c) {
return c >= 0 && Py_UNICODE_ISDIGIT((Py_UCS4)c);
}

#endif // MYPYC_CODEPOINT_EXTRA_OPS_H
4 changes: 4 additions & 0 deletions mypyc/lib-rt/strings/librt_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ cp_parse_i32(PyObject *arg, int32_t *out) {
}

DEFINE_CP_BOOL_WRAPPER(isspace, LibRTStrings_IsSpace)
DEFINE_CP_BOOL_WRAPPER(isdigit, LibRTStrings_IsDigit)

static PyMethodDef librt_strings_module_methods[] = {
{"write_i16_le", (PyCFunction) write_i16_le, METH_FASTCALL,
Expand Down Expand Up @@ -1256,6 +1257,9 @@ static PyMethodDef librt_strings_module_methods[] = {
{"isspace", cp_isspace, METH_O,
PyDoc_STR("Test whether a codepoint (i32) is Unicode whitespace.")
},
{"isdigit", cp_isdigit, METH_O,
PyDoc_STR("Test whether a codepoint (i32) is a Unicode digit.")
},
{NULL, NULL, 0, NULL}
};

Expand Down
9 changes: 9 additions & 0 deletions mypyc/primitives/librt_strings_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,12 @@
error_kind=ERR_NEVER,
dependencies=[LIBRT_STRINGS, CODEPOINT_EXTRA_OPS],
)

function_op(
name="librt.strings.isdigit",
arg_types=[int32_rprimitive],
return_type=bool_rprimitive,
c_function_name="LibRTStrings_IsDigit",
error_kind=ERR_NEVER,
dependencies=[LIBRT_STRINGS, CODEPOINT_EXTRA_OPS],
)
14 changes: 14 additions & 0 deletions mypyc/test-data/irbuild-librt-strings.test
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,17 @@ L8:
L9:
r16 = LibRTStrings_IsSpace(r15)
return r16

[case testLibrtStringsIsDigitIR]
from librt.strings import isdigit
from mypy_extensions import i32

def is_d(c: i32) -> bool:
return isdigit(c)
[out]
def is_d(c):
c :: i32
r0 :: bool
L0:
r0 = LibRTStrings_IsDigit(c)
return r0
22 changes: 13 additions & 9 deletions mypyc/test-data/run-librt-strings.test
Original file line number Diff line number Diff line change
Expand Up @@ -1440,19 +1440,23 @@ def test_new_without_init_is_usable() -> None:
sw.write("hello")
assert sw.getvalue() == "hello"

[case testLibrtStringsIsSpace_librt]
[case testLibrtStringsCodepointClassifiers_librt]
from typing import Any
from mypy_extensions import i32
from librt.strings import isspace
from librt.strings import isspace, isdigit


def test_isspace() -> None:
assert not isspace(i32(-1))
assert not isspace(i32(-113))
# Verify our codepoint primitive agrees with str.isspace() across all
# Unicode codepoints, including the ord(chr(i)) round-trip. Any
# forces generic dispatch on the str side.
def test_codepoint_classifiers() -> None:
# Negative values are not codepoints.
for bad in (i32(-1), i32(-113)):
assert not isspace(bad)
assert not isdigit(bad)
# Verify each codepoint primitive agrees with the matching str method
# across all Unicode codepoints, including the ord(chr(i)) round-trip.
# Any forces generic dispatch on the str side.
for i in range(0x110000):
c = chr(i)
a: Any = c
assert isspace(ord(c)) == isspace(i) == a.isspace()
o = ord(c)
assert isspace(o) == isspace(i) == a.isspace()
assert isdigit(o) == isdigit(i) == a.isdigit()
Loading