Skip to content

Commit d77d2a5

Browse files
committed
Implement C API function PyUnicode_ReadChar
1 parent 9da19f2 commit d77d2a5

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

graalpython/com.oracle.graal.python.cext/src/unicodeobject.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,3 +659,8 @@ void* native_unicode_as_string(PyObject *string) {
659659
assert(kind == PyUnicode_4BYTE_KIND);
660660
return polyglot_from_string_n((const char *)data, sizeof(Py_UCS4) * len, "UTF-32LE");
661661
}
662+
663+
UPCALL_ID(PyUnicode_ReadChar);
664+
Py_UCS4 PyUnicode_ReadChar(PyObject *unicode, Py_ssize_t index) {
665+
return UPCALL_CEXT_I(_jls_PyUnicode_ReadChar, native_to_java(unicode), index);
666+
}

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_unicode.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ def _reference_fromformat(args):
8484
return fmt % fmt_args
8585

8686

87+
def _reference_readchar(args):
88+
s = args[0]
89+
i = args[1]
90+
if i < 0:
91+
# just ensure that it is out of bounds
92+
i = len(s) + 1
93+
return ord(s[i])
94+
95+
8796
class CustomString(str):
8897
pass
8998

@@ -602,4 +611,28 @@ def compile_module(self, name):
602611
cmpfunc=unhandled_error_compare
603612
)
604613

614+
test_PyUnicode_ReadChar = CPyExtFunction(
615+
_reference_readchar,
616+
lambda: (
617+
("hello", 0),
618+
("hello", 4),
619+
("hello", 100),
620+
("hello", -1),
621+
("höllö", 4),
622+
),
623+
code='''PyObject* wrap_PyUnicode_ReadChar(PyObject* unicode, Py_ssize_t index) {
624+
Py_UCS4 res = PyUnicode_ReadChar(unicode, index);
625+
if (res == -1 && PyErr_Occurred()) {
626+
return NULL;
627+
}
628+
return PyLong_FromLong((long) res);
629+
}
630+
''',
631+
resultspec="O",
632+
argspec='On',
633+
arguments=["PyObject* str", "Py_ssize_t index"],
634+
callfunction="wrap_PyUnicode_ReadChar",
635+
cmpfunc=unhandled_error_compare
636+
)
637+
605638

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PythonCextBuiltins.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4547,4 +4547,32 @@ static int doSet(PSet type,
45474547
return lib.length(type.getDictStorage());
45484548
}
45494549
}
4550+
4551+
@Builtin(name = "PyUnicode_ReadChar", minNumOfPositionalArgs = 2)
4552+
@GenerateNodeFactory
4553+
abstract static class PyUnicodeReadChar extends PythonBinaryBuiltinNode {
4554+
@Specialization
4555+
int doGeneric(Object type, long lindex,
4556+
@Cached CastToJavaStringNode castToJavaStringNode,
4557+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode) {
4558+
try {
4559+
try {
4560+
String s = castToJavaStringNode.execute(type);
4561+
int index = PInt.intValueExact(lindex);
4562+
// avoid StringIndexOutOfBoundsException
4563+
if (index < 0 || index >= PString.length(s)) {
4564+
throw raise(IndexError, ErrorMessages.STRING_INDEX_OUT_OF_RANGE);
4565+
}
4566+
return PString.charAt(s, index);
4567+
} catch (CannotCastException e) {
4568+
throw raise(TypeError, ErrorMessages.BAD_ARG_TYPE_FOR_BUILTIN_OP);
4569+
} catch (OverflowException e) {
4570+
throw raise(IndexError, ErrorMessages.STRING_INDEX_OUT_OF_RANGE);
4571+
}
4572+
} catch (PException e) {
4573+
transformExceptionToNativeNode.execute(e);
4574+
return -1;
4575+
}
4576+
}
4577+
}
45504578
}

0 commit comments

Comments
 (0)