Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Parsing.py in the limited api #5845

Merged
merged 18 commits into from Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cython/Compiler/ExprNodes.py
Expand Up @@ -14176,6 +14176,7 @@ class CoerceToBooleanNode(CoercionNode):

type = PyrexTypes.c_bint_type

# Note that all of these need a check if CYTHON_ASSUME_SAFE_MACROS is false
_special_builtins = {
Builtin.list_type: '__Pyx_PyList_GET_SIZE',
Builtin.tuple_type: '__Pyx_PyTuple_GET_SIZE',
Expand Down Expand Up @@ -14214,6 +14215,8 @@ def generate_result_code(self, code):
checks = ["(%s != Py_None)" % self.arg.py_result()] if self.arg.may_be_none() else []
checks.append("(%s(%s) != 0)" % (test_func, self.arg.py_result()))
code.putln("%s = %s;" % (self.result(), '&&'.join(checks)))
code.putln(code.error_goto_if(
"((!CYTHON_ASSUME_SAFE_MACROS) && %s < 0)" % self.result(), self.pos))
else:
code.putln(
"%s = __Pyx_PyObject_IsTrue(%s); %s" % (
Expand Down
35 changes: 33 additions & 2 deletions Cython/Utility/Builtins.c
Expand Up @@ -333,14 +333,30 @@ static long __Pyx__PyObject_Ord(PyObject* c) {
if (PyBytes_Check(c)) {
size = __Pyx_PyBytes_GET_SIZE(c);
if (likely(size == 1)) {
#if CYTHON_ASSUME_SAFE_MACROS
return (unsigned char) PyBytes_AS_STRING(c)[0];
#else
char *data = PyBytes_AsString(c);
if (unlikely(!data)) return -1;
return (unsigned char) data[0];
#endif
}
#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))
#if !CYTHON_ASSUME_SAFE_SIZE
else if (unlikely(size < 0)) return -1;
#endif
} else if (PyByteArray_Check(c)) {
size = __Pyx_PyByteArray_GET_SIZE(c);
if (likely(size == 1)) {
#if CYTHON_ASSUME_SAFE_MACROS
return (unsigned char) PyByteArray_AS_STRING(c)[0];
#else
char *data = PyByteArray_AsString(c);
if (unlikely(!data)) return -1;
return (unsigned char) data[0];
#endif
}
#if !CYTHON_ASSUME_SAFE_SIZE
else if (unlikely(size < 0)) return -1;
#endif
} else {
// FIXME: support character buffers - but CPython doesn't support them either
Expand Down Expand Up @@ -475,8 +491,23 @@ static CYTHON_INLINE PyObject* __Pyx_PyFrozenSet_New(PyObject* it) {
result = PyFrozenSet_New(it);
if (unlikely(!result))
return NULL;
if ((PY_VERSION_HEX >= 0x030A00A1) || likely(__Pyx_PySet_GET_SIZE(result)))
if ((__PYX_LIMITED_VERSION_HEX >= 0x030A00A1)
#if CYTHON_COMPILING_IN_LIMITED_API
|| __Pyx_get_runtime_version() >= 0x030A00A1
#endif
)
return result;
{
Py_ssize_t size = __Pyx_PySet_GET_SIZE(result);
if (likely(size))
return result;
#if !CYTHON_ASSUME_SAFE_SIZE
if (unlikely(size < 0)) {
Py_DECREF(result);
return NULL;
}
#endif
scoder marked this conversation as resolved.
Show resolved Hide resolved
}
// empty frozenset is a singleton (on Python <3.10)
// seems wasteful, but CPython does the same
Py_DECREF(result);
Expand Down
34 changes: 28 additions & 6 deletions Cython/Utility/ObjectHandling.c
Expand Up @@ -54,6 +54,9 @@ static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
__Pyx_RaiseNoneNotIterableError();
} else {
Py_ssize_t size = __Pyx_PyTuple_GET_SIZE(t);
#if !CYTHON_ASSUME_SAFE_SIZE
if (unlikely(size < 0)) return;
#endif
if (size < index) {
__Pyx_RaiseNeedMoreValuesError(size);
} else {
Expand Down Expand Up @@ -82,12 +85,8 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {

/////////////// UnpackTuple2.proto ///////////////

#define __Pyx_unpack_tuple2(tuple, value1, value2, is_tuple, has_known_size, decref_tuple) \
(likely(is_tuple || PyTuple_Check(tuple)) ? \
(likely(has_known_size || PyTuple_GET_SIZE(tuple) == 2) ? \
__Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple) : \
(__Pyx_UnpackTupleError(tuple, 2), -1)) : \
__Pyx_unpack_tuple2_generic(tuple, value1, value2, has_known_size, decref_tuple))
static CYTHON_INLINE int __Pyx_unpack_tuple2(
PyObject* tuple, PyObject** value1, PyObject** value2, int is_tuple, int has_known_size, int decref_tuple);

static CYTHON_INLINE int __Pyx_unpack_tuple2_exact(
PyObject* tuple, PyObject** value1, PyObject** value2, int decref_tuple);
Expand All @@ -99,6 +98,29 @@ static int __Pyx_unpack_tuple2_generic(
//@requires: UnpackTupleError
//@requires: RaiseNeedMoreValuesToUnpack

static CYTHON_INLINE int __Pyx_unpack_tuple2(
PyObject* tuple, PyObject** value1, PyObject** value2, int is_tuple, int has_known_size, int decref_tuple) {
if (likely(is_tuple || PyTuple_Check(tuple))) {
Py_ssize_t size;
if (has_known_size) {
return __Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple);
}
#if CYTHON_ASSUME_SAFE_SIZE
size = PyTuple_GET_SIZE(tuple);
#else
size = PyTuple_Size(tuple);
if (unlikely(size < 0)) return -1;
#endif
if (likely(size == 2)) {
return __Pyx_unpack_tuple2_exact(tuple, value1, value2, decref_tuple);
}
__Pyx_UnpackTupleError(tuple, 2);
return -1;
da-woods marked this conversation as resolved.
Show resolved Hide resolved
} else {
return __Pyx_unpack_tuple2_generic(tuple, value1, value2, has_known_size, decref_tuple);
}
}

static CYTHON_INLINE int __Pyx_unpack_tuple2_exact(
PyObject* tuple, PyObject** pvalue1, PyObject** pvalue2, int decref_tuple) {
PyObject *value1 = NULL, *value2 = NULL;
Expand Down
12 changes: 12 additions & 0 deletions Cython/Utility/Optimize.c
Expand Up @@ -361,8 +361,20 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(
}
Py_INCREF(key);
Py_INCREF(value);
#if CYTHON_ASSUME_SAFE_MACROS
PyTuple_SET_ITEM(tuple, 0, key);
PyTuple_SET_ITEM(tuple, 1, value);
#else
if (unlikely(PyTuple_SetItem(tuple, 0, key) < 0)) {
Py_DECREF(value); // we haven't set this yet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't actually set key in this case either. We need to decref both (and value in the failure case below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyTuple_SetItem decrefs key on failure (https://github.com/python/cpython/blob/939fc6d6eab9b7ea8c244d513610dbdd556503a7/Objects/tupleobject.c#L122C10-L122C10) so that it effectively steals a reference whether or not it succeeds.

I'll add a comment because it isn't obvious though

Py_DECREF(tuple);
return -1;
}
if (unlikely(PyTuple_SetItem(tuple, 1, value) < 0)) {
Py_DECREF(tuple);
return -1;
}
#endif
*pitem = tuple;
} else {
if (pkey) {
Expand Down
83 changes: 15 additions & 68 deletions Cython/Utility/StringTools.c
Expand Up @@ -75,75 +75,13 @@ static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 ch

//////////////////// PyUCS4InUnicode ////////////////////

#if PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE))

#if PY_VERSION_HEX < 0x03090000
#define __Pyx_PyUnicode_AS_UNICODE(op) PyUnicode_AS_UNICODE(op)
#define __Pyx_PyUnicode_GET_SIZE(op) PyUnicode_GET_SIZE(op)
#else
// Avoid calling deprecated C-API functions in Py3.9+ that PEP-623 schedules for removal in Py3.12.
// https://www.python.org/dev/peps/pep-0623/
#define __Pyx_PyUnicode_AS_UNICODE(op) (((PyASCIIObject *)(op))->wstr)
#define __Pyx_PyUnicode_GET_SIZE(op) ((PyCompactUnicodeObject *)(op))->wstr_length
#endif

#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2
static int __Pyx_PyUnicodeBufferContainsUCS4_SP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) {
/* handle surrogate pairs for Py_UNICODE buffers in 16bit Unicode builds */
Py_UNICODE high_val, low_val;
Py_UNICODE* pos;
high_val = (Py_UNICODE) (0xD800 | (((character - 0x10000) >> 10) & ((1<<10)-1)));
low_val = (Py_UNICODE) (0xDC00 | ( (character - 0x10000) & ((1<<10)-1)));
for (pos=buffer; pos < buffer+length-1; pos++) {
if (unlikely((high_val == pos[0]) & (low_val == pos[1]))) return 1;
}
return 0;
}
#endif

static int __Pyx_PyUnicodeBufferContainsUCS4_BMP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) {
Py_UNICODE uchar;
Py_UNICODE* pos;
uchar = (Py_UNICODE) character;
for (pos=buffer; pos < buffer+length; pos++) {
if (unlikely(uchar == pos[0])) return 1;
}
return 0;
}
#endif

static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) {
const int kind = PyUnicode_KIND(unicode);
#ifdef PyUnicode_WCHAR_KIND
if (likely(kind != PyUnicode_WCHAR_KIND))
#endif
{
Py_ssize_t i;
const void* udata = PyUnicode_DATA(unicode);
const Py_ssize_t length = PyUnicode_GET_LENGTH(unicode);
for (i=0; i < length; i++) {
if (unlikely(character == PyUnicode_READ(kind, udata, i))) return 1;
}
return 0;
}

#if PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE))
#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2
if ((sizeof(Py_UNICODE) == 2) && unlikely(character > 65535)) {
return __Pyx_PyUnicodeBufferContainsUCS4_SP(
__Pyx_PyUnicode_AS_UNICODE(unicode),
__Pyx_PyUnicode_GET_SIZE(unicode),
character);
} else
#endif
{
return __Pyx_PyUnicodeBufferContainsUCS4_BMP(
__Pyx_PyUnicode_AS_UNICODE(unicode),
__Pyx_PyUnicode_GET_SIZE(unicode),
character);

}
#endif
// Note that from Python 3.7, the indices of FindChar are adjusted to match the bounds
// so need to check the length
Py_ssize_t idx = PyUnicode_FindChar(unicode, character, 0, PY_SSIZE_T_MAX, 1);
if (unlikely(idx == -2)) return -1;
// >= 0: found the index, == -1: not found
return idx >= 0;
}


Expand Down Expand Up @@ -568,8 +506,13 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring(
static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring(
PyObject* text, Py_ssize_t start, Py_ssize_t stop) {
Py_ssize_t length;
#if CYTHON_ASSUME_SAFE_MACROS
if (unlikely(__Pyx_PyUnicode_READY(text) == -1)) return NULL;
#endif
scoder marked this conversation as resolved.
Show resolved Hide resolved
length = __Pyx_PyUnicode_GET_LENGTH(text);
#if !CYTHON_ASSUME_SAFE_MACROS
if (unlikely(length < 0)) return NULL;
#endif
if (start < 0) {
start += length;
if (start < 0)
Expand All @@ -583,8 +526,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring(
return __Pyx_NewRef($empty_unicode);
if (start == 0 && stop == length)
return __Pyx_NewRef(text);
#if !CYTHON_COMPILING_IN_LIMITED_API
return PyUnicode_FromKindAndData(PyUnicode_KIND(text),
PyUnicode_1BYTE_DATA(text) + start*PyUnicode_KIND(text), stop-start);
#else
return PyUnicode_Substring(text, start, stop);
#endif
da-woods marked this conversation as resolved.
Show resolved Hide resolved
}


Expand Down
23 changes: 14 additions & 9 deletions Cython/Utility/TypeConversion.c
Expand Up @@ -584,15 +584,20 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
/////////////// UnicodeAsUCS4 ///////////////

static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) {
Py_ssize_t length;
length = PyUnicode_GET_LENGTH(x);
if (likely(length == 1)) {
return PyUnicode_READ_CHAR(x, 0);
}
PyErr_Format(PyExc_ValueError,
"only single character unicode strings can be converted to Py_UCS4, "
"got length %" CYTHON_FORMAT_SSIZE_T "d", length);
return (Py_UCS4)-1;
Py_ssize_t length;
#if !CYTHON_COMPILING_IN_LIMITED_API
length = PyUnicode_GET_LENGTH(x);
#else
length = PyUnicode_GetLength(x);
if (length < 0) return (Py_UCS4)-1;
#endif
if (likely(length == 1)) {
return __Pyx_PyUnicode_READ_CHAR(x, 0);
}
PyErr_Format(PyExc_ValueError,
"only single character unicode strings can be converted to Py_UCS4, "
"got length %" CYTHON_FORMAT_SSIZE_T "d", length);
return (Py_UCS4)-1;
da-woods marked this conversation as resolved.
Show resolved Hide resolved
}


Expand Down