/* * Optional optimisations of built-in functions and methods. * * Required replacements of builtins are in Builtins.c. * * General object operations and protocols are in ObjectHandling.c. */ /////////////// append.proto /////////////// static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x); /*proto*/ /////////////// append /////////////// //@requires: ListAppend //@requires: ObjectHandling.c::PyObjectCallMethod1 static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) { if (likely(PyList_CheckExact(L))) { if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return -1; } else { PyObject* retval = __Pyx_PyObject_CallMethod1(L, PYIDENT("append"), x); if (unlikely(!retval)) return -1; Py_DECREF(retval); } return 0; } /////////////// ListAppendAndDecrefInternal /////////////// #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE void __Pyx__ListComp_AppendAndDecref(PyObject* list, Py_ssize_t len, PyObject* x) { PyList_SET_ITEM(list, len, x); Py_SET_SIZE(list, len + 1); } #endif /////////////// ListAppend.proto /////////////// #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x); /*proto*/ #else #define __Pyx_PyList_Append(L,x) PyList_Append(L,x) #endif /////////////// ListAppend /////////////// //@requires: ListAppendAndDecrefInternal #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { PyListObject* L = (PyListObject*) list; Py_ssize_t len = Py_SIZE(list); if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { Py_INCREF(x); __Pyx__ListComp_AppendAndDecref(list, len, x); return 0; } return PyList_Append(list, x); } #endif /////////////// ListCompAppend.proto /////////////// #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x); /*proto*/ #else #define __Pyx_ListComp_Append(L,x) PyList_Append(L,x) #endif /////////////// ListCompAppend /////////////// //@requires: ListAppendAndDecrefInternal #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { PyListObject* L = (PyListObject*) list; Py_ssize_t len = Py_SIZE(list); if (likely(L->allocated > len)) { Py_INCREF(x); __Pyx__ListComp_AppendAndDecref(list, len, x); return 0; } return PyList_Append(list, x); } #endif /////////////// ListCompAppendAndDecref.proto /////////////// static CYTHON_INLINE int __Pyx_ListComp_AppendAndDecref(PyObject* list, PyObject* x); /*proto*/ /////////////// ListCompAppendAndDecref /////////////// //@requires: ListAppendAndDecrefInternal #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE int __Pyx_ListComp_AppendAndDecref(PyObject* list, PyObject* x) { PyListObject* L = (PyListObject*) list; Py_ssize_t len = Py_SIZE(list); if (likely(L->allocated > len)) { __Pyx__ListComp_AppendAndDecref(list, len, x); return 0; } int result = PyList_Append(list, x); Py_DECREF(x); return result; } #else static CYTHON_INLINE int __Pyx_ListComp_AppendAndDecref(PyObject* list, PyObject* x) { int result = PyList_Append(list, x); Py_DECREF(x); return result; } #endif //////////////////// ListExtend.proto //////////////////// #if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030d0000) && !defined(PyList_Extend) static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v); /*proto*/ #else #define __Pyx_PyList_Extend(L, v) PyList_Extend(L, v) #endif //////////////////// ListExtend //////////////////// #if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030d0000) && !defined(PyList_Extend) static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { #if CYTHON_COMPILING_IN_CPYTHON PyObject* none = _PyList_Extend((PyListObject*)L, v); if (unlikely(!none)) return -1; Py_DECREF(none); return 0; #else return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); #endif } #endif /////////////// pop.proto /////////////// static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/ #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L); /*proto*/ #define __Pyx_PyObject_Pop(L) (likely(PyList_CheckExact(L)) ? \ __Pyx_PyList_Pop(L) : __Pyx__PyObject_Pop(L)) #else #define __Pyx_PyList_Pop(L) __Pyx__PyObject_Pop(L) #define __Pyx_PyObject_Pop(L) __Pyx__PyObject_Pop(L) #endif /////////////// pop /////////////// //@requires: ObjectHandling.c::PyObjectCallMethod0 static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L) { if (Py_IS_TYPE(L, &PySet_Type)) { return PySet_Pop(L); } return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop")); } #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) { /* Check that both the size is positive and no reallocation shrinking needs to be done. */ if (likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) { Py_SET_SIZE(L, Py_SIZE(L) - 1); return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); } return CALL_UNBOUND_METHOD(PyList_Type, "pop", L); } #endif /////////////// pop_index.proto /////////////// static PyObject* __Pyx__PyObject_PopNewIndex(PyObject* L, PyObject* py_ix); /*proto*/ static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix); /*proto*/ #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t ix); /*proto*/ #define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \ (likely(PyList_CheckExact(L) && __Pyx_fits_Py_ssize_t(ix, type, is_signed))) ? \ __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \ (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \ __Pyx__PyObject_PopIndex(L, py_ix))) #define __Pyx_PyList_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \ __Pyx_fits_Py_ssize_t(ix, type, is_signed) ? \ __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \ (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \ __Pyx__PyObject_PopIndex(L, py_ix))) #else #define __Pyx_PyList_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) \ __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) #define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \ (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \ __Pyx__PyObject_PopIndex(L, py_ix)) #endif /////////////// pop_index /////////////// //@requires: ObjectHandling.c::PyObjectCallMethod1 static PyObject* __Pyx__PyObject_PopNewIndex(PyObject* L, PyObject* py_ix) { PyObject *r; if (unlikely(!py_ix)) return NULL; r = __Pyx__PyObject_PopIndex(L, py_ix); Py_DECREF(py_ix); return r; } static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix) { return __Pyx_PyObject_CallMethod1(L, PYIDENT("pop"), py_ix); } #if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t ix) { Py_ssize_t size = PyList_GET_SIZE(L); if (likely(size > (((PyListObject*)L)->allocated >> 1))) { Py_ssize_t cix = ix; if (cix < 0) { cix += size; } if (likely(__Pyx_is_valid_index(cix, size))) { PyObject* v = PyList_GET_ITEM(L, cix); Py_SET_SIZE(L, Py_SIZE(L) - 1); size -= 1; memmove(&PyList_GET_ITEM(L, cix), &PyList_GET_ITEM(L, cix+1), (size_t)(size-cix)*sizeof(PyObject*)); return v; } } if (py_ix == Py_None) { return __Pyx__PyObject_PopNewIndex(L, PyLong_FromSsize_t(ix)); } else { return __Pyx__PyObject_PopIndex(L, py_ix); } } #endif /////////////// dict_getitem_default.proto /////////////// static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value); /*proto*/ /////////////// dict_getitem_default /////////////// static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value) { PyObject* value; #if !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000 value = PyDict_GetItemWithError(d, key); if (unlikely(!value)) { if (unlikely(PyErr_Occurred())) return NULL; value = default_value; } Py_INCREF(value); // avoid C compiler warning about unused utility functions if ((1)); #else if (PyBytes_CheckExact(key) || PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) { /* these presumably have safe hash functions */ value = PyDict_GetItem(d, key); if (unlikely(!value)) { value = default_value; } Py_INCREF(value); } #endif else { if (default_value == Py_None) value = CALL_UNBOUND_METHOD(PyDict_Type, "get", d, key); else value = CALL_UNBOUND_METHOD(PyDict_Type, "get", d, key, default_value); } return value; } /////////////// py_dict_clear.proto /////////////// #define __Pyx_PyDict_Clear(d) (PyDict_Clear(d), 0) /////////////// py_dict_pop.proto /////////////// static CYTHON_INLINE PyObject *__Pyx_PyDict_Pop(PyObject *d, PyObject *key, PyObject *default_value); /*proto*/ /////////////// py_dict_pop /////////////// static CYTHON_INLINE PyObject *__Pyx_PyDict_Pop(PyObject *d, PyObject *key, PyObject *default_value) { #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d00A2 || defined(PyDict_Pop) PyObject *value; if (PyDict_Pop(d, key, &value) == 0) { if (default_value) { Py_INCREF(default_value); } else { PyErr_SetObject(PyExc_KeyError, key); } value = default_value; } // On error, PyDict_Pop() returns -1 and sets value to NULL (our own exception return value). return value; #elif CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 return _PyDict_Pop(d, key, default_value); #else if (default_value) { return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key, default_value); } else { return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key); } #endif } /////////////// py_dict_pop_ignore.proto /////////////// static CYTHON_INLINE int __Pyx_PyDict_Pop_ignore(PyObject *d, PyObject *key, PyObject *default_value); /*proto*/ /////////////// py_dict_pop_ignore /////////////// static CYTHON_INLINE int __Pyx_PyDict_Pop_ignore(PyObject *d, PyObject *key, PyObject *default_value) { // We take the "default_value" as argument to avoid "unused" warnings, but we ignore it here. #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d00A2 || defined(PyDict_Pop) int result = PyDict_Pop(d, key, NULL); CYTHON_UNUSED_VAR(default_value); return (unlikely(result == -1)) ? -1 : 0; #else PyObject *value; CYTHON_UNUSED_VAR(default_value); #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 value = _PyDict_Pop(d, key, Py_None); #else value = CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key, Py_None); #endif if (unlikely(value == NULL)) return -1; Py_DECREF(value); return 0; #endif } /////////////// dict_iter_common.proto /////////////// static PyObject *__Pyx_dict_call_to_get_iterable(PyObject* iterable, PyObject* method_name); /* proto */ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t orig_length, Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict); /////////////// dict_iter_common /////////////// //@requires: ObjectHandling.c::UnpackTuple2 //@requires: ObjectHandling.c::IterFinish //@requires: ObjectHandling.c::PyObjectCallMethod0 static PyObject *__Pyx_dict_call_to_get_iterable(PyObject* iterable, PyObject* method_name) { PyObject* iter; iterable = __Pyx_PyObject_CallMethod0(iterable, method_name); if (!iterable) return NULL; #if !CYTHON_AVOID_BORROWED_REFS if (PyTuple_CheckExact(iterable) || PyList_CheckExact(iterable)) return iterable; #endif iter = PyObject_GetIter(iterable); Py_DECREF(iterable); return iter; } #if !CYTHON_AVOID_BORROWED_REFS static CYTHON_INLINE int __Pyx_dict_iter_next_source_is_dict( PyObject* iter_obj, CYTHON_NCP_UNUSED Py_ssize_t orig_length, CYTHON_NCP_UNUSED Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue, PyObject** pitem) { PyObject *key, *value; if (unlikely(orig_length != PyDict_Size(iter_obj))) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); return -1; } if (unlikely(!PyDict_Next(iter_obj, ppos, &key, &value))) { return 0; } if (pitem) { PyObject* tuple = PyTuple_New(2); if (unlikely(!tuple)) { return -1; } 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)) { // decref value; PyTuple_SetItem decrefs key on failure Py_DECREF(value); Py_DECREF(tuple); return -1; } if (unlikely(PyTuple_SetItem(tuple, 1, value) < 0)) { // PyTuple_SetItem decrefs value on failure Py_DECREF(tuple); return -1; } #endif *pitem = tuple; } else { if (pkey) { Py_INCREF(key); *pkey = key; } if (pvalue) { Py_INCREF(value); *pvalue = value; } } return 1; } #endif static CYTHON_INLINE int __Pyx_dict_iter_next( PyObject* iter_obj, CYTHON_NCP_UNUSED Py_ssize_t orig_length, CYTHON_NCP_UNUSED Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue, PyObject** pitem, int source_is_dict) { PyObject* next_item; #if !CYTHON_AVOID_BORROWED_REFS if (source_is_dict) { int result; #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API Py_BEGIN_CRITICAL_SECTION(iter_obj); #endif result = __Pyx_dict_iter_next_source_is_dict(iter_obj, orig_length, ppos, pkey, pvalue, pitem); #if PY_VERSION_HEX >= 0x030d0000 && !CYTHON_COMPILING_IN_LIMITED_API Py_END_CRITICAL_SECTION(); #endif return result; } else if (PyTuple_CheckExact(iter_obj)) { Py_ssize_t pos = *ppos; Py_ssize_t tuple_size = __Pyx_PyTuple_GET_SIZE(iter_obj); #if !CYTHON_ASSUME_SAFE_SIZE if (unlikely(tuple_size < 0)) return -1; #endif if (unlikely(pos >= tuple_size)) return 0; *ppos = pos + 1; #if CYTHON_ASSUME_SAFE_MACROS next_item = PyTuple_GET_ITEM(iter_obj, pos); #else next_item = PyTuple_GetItem(iter_obj, pos); if (unlikely(!next_item)) return -1; #endif Py_INCREF(next_item); } else if (PyList_CheckExact(iter_obj)) { Py_ssize_t pos = *ppos; Py_ssize_t list_size = __Pyx_PyList_GET_SIZE(iter_obj); #if !CYTHON_ASSUME_SAFE_SIZE if (unlikely(list_size < 0)) return -1; #endif if (unlikely(pos >= list_size)) return 0; *ppos = pos + 1; next_item = __Pyx_PyList_GET_ITEM_REF(iter_obj, pos, __Pyx_ReferenceSharing_OwnStrongReference); if (unlikely(!next_item)) return -1; } else #endif { next_item = PyIter_Next(iter_obj); if (unlikely(!next_item)) { return __Pyx_IterFinish(); } } if (pitem) { *pitem = next_item; } else if (pkey && pvalue) { if (__Pyx_unpack_tuple2(next_item, pkey, pvalue, source_is_dict, source_is_dict, 1)) return -1; } else if (pkey) { *pkey = next_item; } else { *pvalue = next_item; } return 1; } /////////////// dict_iter_legacy.proto ////////////// // "legacy" handles old-style iter* methods static CYTHON_INLINE PyObject* __Pyx_dict_iterator_legacy(PyObject* dict, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_is_dict); /////////////// dict_iter_legacy ////////////////// //@requires: dict_iter_common #if CYTHON_AVOID_BORROWED_REFS #include #endif static CYTHON_INLINE PyObject* __Pyx_dict_iterator_legacy(PyObject* iterable, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_source_is_dict) { int owned_method_name = 0; // Don't include frozendict. is_dict = is_dict || likely(PyDict_CheckExact(iterable)); *p_source_is_dict = is_dict; if (is_dict) { #if !CYTHON_AVOID_BORROWED_REFS *p_orig_length = PyDict_Size(iterable); Py_INCREF(iterable); return iterable; #else // On PyPy3/GraalPy, we need to translate manually the method name. // This logic is not needed on CPython thanks to the fast case above. if (method_name) { method_name = PyUnicode_Substring(method_name, 4, 10); // longest is "itervalues" (len=10) if (unlikely(!method_name)) return NULL; owned_method_name = 1; } #endif } *p_orig_length = 0; if (method_name) { iterable = __Pyx_dict_call_to_get_iterable(iterable, method_name); if (owned_method_name) { Py_DECREF(method_name); } return iterable; } else { return PyObject_GetIter(iterable); } } /////////////// dict_iter.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* dict, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_is_dict); /////////////// dict_iter /////////////// //@requires: Builtins.c::PyFrozenDict //@requires: dict_iter_common static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_dict, PyObject* method_name, Py_ssize_t* p_orig_length, int* p_source_is_dict) { is_dict = is_dict || likely(__Pyx_PyAnyDict_CheckExact(iterable)); *p_source_is_dict = is_dict; #if !CYTHON_AVOID_BORROWED_REFS if (is_dict) { *p_orig_length = PyDict_Size(iterable); Py_INCREF(iterable); return iterable; } #endif *p_orig_length = 0; if (method_name) { return __Pyx_dict_call_to_get_iterable(iterable, method_name); } else { return PyObject_GetIter(iterable); } } /////////////// set_iter.proto /////////////// static CYTHON_INLINE PyObject* __Pyx_set_iterator(PyObject* iterable, int is_set, Py_ssize_t* p_orig_length, int* p_source_is_set); /*proto*/ static CYTHON_INLINE int __Pyx_set_iter_next( PyObject* iter_obj, Py_ssize_t orig_length, Py_ssize_t* ppos, PyObject **value, int source_is_set); /*proto*/ /////////////// set_iter /////////////// //@requires: ObjectHandling.c::IterFinish static CYTHON_INLINE PyObject* __Pyx_set_iterator(PyObject* iterable, int is_set, Py_ssize_t* p_orig_length, int* p_source_is_set) { #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 is_set = is_set || likely(PySet_CheckExact(iterable) || PyFrozenSet_CheckExact(iterable)); *p_source_is_set = is_set; if (likely(is_set)) { *p_orig_length = PySet_Size(iterable); Py_INCREF(iterable); return iterable; } #else CYTHON_UNUSED_VAR(is_set); *p_source_is_set = 0; #endif *p_orig_length = 0; return PyObject_GetIter(iterable); } static CYTHON_INLINE int __Pyx_set_iter_next( PyObject* iter_obj, Py_ssize_t orig_length, Py_ssize_t* ppos, PyObject **value, int source_is_set) { if (!CYTHON_COMPILING_IN_CPYTHON || PY_VERSION_HEX >= 0x030d0000 || unlikely(!source_is_set)) { *value = PyIter_Next(iter_obj); if (unlikely(!*value)) { return __Pyx_IterFinish(); } CYTHON_UNUSED_VAR(orig_length); CYTHON_UNUSED_VAR(ppos); return 1; } #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 if (unlikely(PySet_GET_SIZE(iter_obj) != orig_length)) { PyErr_SetString( PyExc_RuntimeError, "set changed size during iteration"); return -1; } { Py_hash_t hash; int ret = _PySet_NextEntry(iter_obj, ppos, value, &hash); // CPython does not raise errors here, only if !isinstance(iter_obj, set/frozenset) assert (ret != -1); if (likely(ret)) { Py_INCREF(*value); return 1; } } #endif return 0; } /////////////// py_set_discard_unhashable /////////////// //@requires: Builtins.c::pyfrozenset_new static int __Pyx_PySet_DiscardUnhashable(PyObject *set, PyObject *key) { PyObject *tmpkey; int rv; if (likely(!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))) return -1; PyErr_Clear(); tmpkey = __Pyx_PyFrozenSet_New(key); if (tmpkey == NULL) return -1; rv = PySet_Discard(set, tmpkey); Py_DECREF(tmpkey); return rv; } /////////////// py_set_discard.proto /////////////// static CYTHON_INLINE int __Pyx_PySet_Discard(PyObject *set, PyObject *key); /*proto*/ /////////////// py_set_discard /////////////// //@requires: py_set_discard_unhashable static CYTHON_INLINE int __Pyx_PySet_Discard(PyObject *set, PyObject *key) { int found = PySet_Discard(set, key); // Convert *key* to frozenset if necessary if (unlikely(found < 0)) { found = __Pyx_PySet_DiscardUnhashable(set, key); } // note: returns -1 on error, 0 (not found) or 1 (found) otherwise => error check for -1 or < 0 works return found; } /////////////// py_set_remove.proto /////////////// static CYTHON_INLINE int __Pyx_PySet_Remove(PyObject *set, PyObject *key); /*proto*/ /////////////// py_set_remove /////////////// //@requires: py_set_discard_unhashable static int __Pyx_PySet_RemoveNotFound(PyObject *set, PyObject *key, int found) { // Convert *key* to frozenset if necessary if (unlikely(found < 0)) { found = __Pyx_PySet_DiscardUnhashable(set, key); } if (likely(found == 0)) { // Not found PyObject *tup; tup = PyTuple_Pack(1, key); if (!tup) return -1; PyErr_SetObject(PyExc_KeyError, tup); Py_DECREF(tup); return -1; } // note: returns -1 on error, 0 (not found) or 1 (found) otherwise => error check for -1 or < 0 works return found; } static CYTHON_INLINE int __Pyx_PySet_Remove(PyObject *set, PyObject *key) { int found = PySet_Discard(set, key); if (unlikely(found != 1)) { // note: returns -1 on error, 0 (not found) or 1 (found) otherwise => error check for -1 or < 0 works return __Pyx_PySet_RemoveNotFound(set, key, found); } return 0; } /////////////// unicode_iter.proto /////////////// static CYTHON_INLINE int __Pyx_init_unicode_iteration( PyObject* ustring, Py_ssize_t *length, void** data, int *kind); /* proto */ /////////////// unicode_iter /////////////// static CYTHON_INLINE int __Pyx_init_unicode_iteration( PyObject* ustring, Py_ssize_t *length, void** data, int *kind) { #if CYTHON_COMPILING_IN_LIMITED_API // In the limited API we just point data to the unicode object *kind = 0; *length = PyUnicode_GetLength(ustring); *data = (void*)ustring; #else if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return -1; *kind = PyUnicode_KIND(ustring); *length = PyUnicode_GET_LENGTH(ustring); *data = PyUnicode_DATA(ustring); #endif return 0; } /////////////// pyobject_as_double.proto /////////////// static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */ #if CYTHON_COMPILING_IN_PYPY #define __Pyx_PyObject_AsDouble(obj) \ (likely(PyFloat_CheckExact(obj)) ? PyFloat_AS_DOUBLE(obj) : \ likely(PyLong_CheckExact(obj)) ? \ PyFloat_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj)) #else #define __Pyx_PyObject_AsDouble(obj) \ ((likely(PyFloat_CheckExact(obj))) ? __Pyx_PyFloat_AS_DOUBLE(obj) : \ likely(PyLong_CheckExact(obj)) ? \ PyLong_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj)) #endif /////////////// pyobject_as_double /////////////// //@requires: pybytes_as_double //@requires: pyunicode_as_double //@requires: ObjectHandling.c::PyObjectCallOneArg //@requires: ObjectHandling.c::RaiseErrorWithObjectType static double __Pyx__PyObject_AsDouble(PyObject* obj) { if (PyUnicode_CheckExact(obj)) { return __Pyx_PyUnicode_AsDouble(obj); } else if (PyBytes_CheckExact(obj)) { return __Pyx_PyBytes_AsDouble(obj); } else if (PyByteArray_CheckExact(obj)) { return __Pyx_PyByteArray_AsDouble(obj); } else { PyObject* float_value; #if !CYTHON_USE_TYPE_SLOTS float_value = PyNumber_Float(obj); if ((0)) goto bad; // avoid "unused" warnings (void)__Pyx_PyObject_CallOneArg; #else PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number; if (likely(nb) && likely(nb->nb_float)) { float_value = nb->nb_float(obj); if (likely(float_value) && unlikely(!PyFloat_Check(float_value))) { __Pyx_RaiseTypeErrorWithObjectType( "__float__ returned non-float (type " __Pyx_FMT_TYPENAME ")", float_value); Py_DECREF(float_value); goto bad; } } else { float_value = __Pyx_PyObject_CallOneArg((PyObject*)&PyFloat_Type, obj); } #endif if (likely(float_value)) { double value = __Pyx_PyFloat_AS_DOUBLE(float_value); Py_DECREF(float_value); return value; } } bad: return (double)-1; } /////////////// pyunicode_as_double.proto /////////////// static CYTHON_INLINE double __Pyx_PyUnicode_AsDouble(PyObject *obj);/*proto*/ /////////////// pyunicode_as_double.proto /////////////// //@requires: pybytes_as_double #if !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS static const char* __Pyx__PyUnicode_AsDouble_Copy(const void* data, const int kind, char* buffer, Py_ssize_t start, Py_ssize_t end) { int last_was_punctuation; Py_ssize_t i; // number must not start with punctuation last_was_punctuation = 1; for (i=start; i <= end; i++) { Py_UCS4 chr = PyUnicode_READ(kind, data, i); int is_punctuation = (chr == '_') | (chr == '.'); *buffer = (char)chr; // reject sequences of '_' and '.' buffer += (chr != '_'); if (unlikely(chr > 127)) goto parse_failure; if (unlikely(last_was_punctuation & is_punctuation)) goto parse_failure; last_was_punctuation = is_punctuation; } if (unlikely(last_was_punctuation)) goto parse_failure; *buffer = '\0'; return buffer; parse_failure: return NULL; } static double __Pyx__PyUnicode_AsDouble_inf_nan(const void* data, int kind, Py_ssize_t start, Py_ssize_t length) { int matches = 1; Py_UCS4 chr; Py_UCS4 sign = PyUnicode_READ(kind, data, start); int is_signed = (sign == '-') | (sign == '+'); start += is_signed; length -= is_signed; switch (PyUnicode_READ(kind, data, start)) { #ifdef Py_NAN case 'n': case 'N': if (unlikely(length != 3)) goto parse_failure; chr = PyUnicode_READ(kind, data, start+1); matches &= (chr == 'a') | (chr == 'A'); chr = PyUnicode_READ(kind, data, start+2); matches &= (chr == 'n') | (chr == 'N'); if (unlikely(!matches)) goto parse_failure; return (sign == '-') ? -Py_NAN : Py_NAN; #endif case 'i': case 'I': if (unlikely(length < 3)) goto parse_failure; chr = PyUnicode_READ(kind, data, start+1); matches &= (chr == 'n') | (chr == 'N'); chr = PyUnicode_READ(kind, data, start+2); matches &= (chr == 'f') | (chr == 'F'); if (likely(length == 3 && matches)) return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; if (unlikely(length != 8)) goto parse_failure; chr = PyUnicode_READ(kind, data, start+3); matches &= (chr == 'i') | (chr == 'I'); chr = PyUnicode_READ(kind, data, start+4); matches &= (chr == 'n') | (chr == 'N'); chr = PyUnicode_READ(kind, data, start+5); matches &= (chr == 'i') | (chr == 'I'); chr = PyUnicode_READ(kind, data, start+6); matches &= (chr == 't') | (chr == 'T'); chr = PyUnicode_READ(kind, data, start+7); matches &= (chr == 'y') | (chr == 'Y'); if (unlikely(!matches)) goto parse_failure; return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: goto parse_failure; } return 0.0; parse_failure: return -1.0; } static double __Pyx_PyUnicode_AsDouble_WithSpaces(PyObject *obj) { double value; const char *last; char *end; int valid_parse; Py_ssize_t start, length = PyUnicode_GET_LENGTH(obj); const int kind = PyUnicode_KIND(obj); const void* data = PyUnicode_DATA(obj); // strip spaces at start and end start = 0; while (Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, start))) start++; while (start < length - 1 && Py_UNICODE_ISSPACE(PyUnicode_READ(kind, data, length - 1))) length--; length -= start; if (unlikely(length <= 0)) goto fallback; // parse NaN / inf value = __Pyx__PyUnicode_AsDouble_inf_nan(data, kind, start, length); if (value != 0.0) { if (unlikely(value == -1.0)) goto fallback; return value; } if (length < 40) { char number[40]; last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); if (unlikely(!last)) goto fallback; value = PyOS_string_to_double(number, &end, NULL); valid_parse = (end == last); } else { char *number = (char*) PyMem_Malloc(((size_t) length + 1) * sizeof(char)); if (unlikely(!number)) goto fallback; last = __Pyx__PyUnicode_AsDouble_Copy(data, kind, number, start, start + length); if (unlikely(!last)) { PyMem_Free(number); goto fallback; } value = PyOS_string_to_double(number, &end, NULL); valid_parse = (end == last); PyMem_Free(number); } if (likely(valid_parse) || (value == (double)-1 && PyErr_Occurred())) { return value; } fallback: return __Pyx_SlowPyString_AsDouble(obj); } #endif static CYTHON_INLINE double __Pyx_PyUnicode_AsDouble(PyObject *obj) { // Currently not optimised for Py2.7. #if !CYTHON_COMPILING_IN_PYPY && CYTHON_ASSUME_SAFE_MACROS if (unlikely(__Pyx_PyUnicode_READY(obj) == -1)) return (double)-1; if (likely(PyUnicode_IS_ASCII(obj))) { const char *s; Py_ssize_t length; s = PyUnicode_AsUTF8AndSize(obj, &length); return __Pyx__PyBytes_AsDouble(obj, s, length); } return __Pyx_PyUnicode_AsDouble_WithSpaces(obj); #else return __Pyx_SlowPyString_AsDouble(obj); #endif } /////////////// pybytes_as_double.proto /////////////// static double __Pyx_SlowPyString_AsDouble(PyObject *obj);/*proto*/ static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length);/*proto*/ static CYTHON_INLINE double __Pyx_PyBytes_AsDouble(PyObject *obj) { char* as_c_string; Py_ssize_t size; #if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE as_c_string = PyBytes_AS_STRING(obj); size = PyBytes_GET_SIZE(obj); #else if (PyBytes_AsStringAndSize(obj, &as_c_string, &size) < 0) { return (double)-1; } #endif return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); } static CYTHON_INLINE double __Pyx_PyByteArray_AsDouble(PyObject *obj) { char* as_c_string; Py_ssize_t size; #if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE as_c_string = PyByteArray_AS_STRING(obj); size = PyByteArray_GET_SIZE(obj); #else as_c_string = PyByteArray_AsString(obj); if (as_c_string == NULL) { return (double)-1; } size = PyByteArray_Size(obj); #endif return __Pyx__PyBytes_AsDouble(obj, as_c_string, size); } /////////////// pybytes_as_double /////////////// static double __Pyx_SlowPyString_AsDouble(PyObject *obj) { PyObject *float_value = PyFloat_FromString(obj); if (likely(float_value)) { double value = __Pyx_PyFloat_AS_DOUBLE(float_value); Py_DECREF(float_value); return value; } return (double)-1; } static const char* __Pyx__PyBytes_AsDouble_Copy(const char* start, char* buffer, Py_ssize_t length) { // number must not start with punctuation int last_was_punctuation = 1; int parse_error_found = 0; Py_ssize_t i; for (i=0; i < length; i++) { char chr = start[i]; int is_punctuation = (chr == '_') | (chr == '.') | (chr == 'e') | (chr == 'E'); *buffer = chr; buffer += (chr != '_'); // reject sequences of punctuation, e.g. '_.' parse_error_found |= last_was_punctuation & is_punctuation; last_was_punctuation = is_punctuation; } // number must not end with punctuation parse_error_found |= last_was_punctuation; *buffer = '\0'; return unlikely(parse_error_found) ? NULL : buffer; } static double __Pyx__PyBytes_AsDouble_inf_nan(const char* start, Py_ssize_t length) { int matches = 1; char sign = start[0]; int is_signed = (sign == '+') | (sign == '-'); start += is_signed; length -= is_signed; switch (start[0]) { #ifdef Py_NAN case 'n': case 'N': if (unlikely(length != 3)) goto parse_failure; matches &= (start[1] == 'a' || start[1] == 'A'); matches &= (start[2] == 'n' || start[2] == 'N'); if (unlikely(!matches)) goto parse_failure; return (sign == '-') ? -Py_NAN : Py_NAN; #endif case 'i': case 'I': if (unlikely(length < 3)) goto parse_failure; matches &= (start[1] == 'n' || start[1] == 'N'); matches &= (start[2] == 'f' || start[2] == 'F'); if (likely(length == 3 && matches)) return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; if (unlikely(length != 8)) goto parse_failure; matches &= (start[3] == 'i' || start[3] == 'I'); matches &= (start[4] == 'n' || start[4] == 'N'); matches &= (start[5] == 'i' || start[5] == 'I'); matches &= (start[6] == 't' || start[6] == 'T'); matches &= (start[7] == 'y' || start[7] == 'Y'); if (unlikely(!matches)) goto parse_failure; return (sign == '-') ? -Py_HUGE_VAL : Py_HUGE_VAL; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: goto parse_failure; } return 0.0; parse_failure: return -1.0; } static CYTHON_INLINE int __Pyx__PyBytes_AsDouble_IsSpace(char ch) { // see Py_ISSPACE() in CPython // https://github.com/python/cpython/blob/master/Python/pyctype.c return (ch == 0x20) | !((ch < 0x9) | (ch > 0xd)); } CYTHON_UNUSED static double __Pyx__PyBytes_AsDouble(PyObject *obj, const char* start, Py_ssize_t length) { double value; Py_ssize_t i, digits; const char *last = start + length; char *end; int valid_parse; // strip spaces at start and end while (__Pyx__PyBytes_AsDouble_IsSpace(*start)) start++; while (start < last - 1 && __Pyx__PyBytes_AsDouble_IsSpace(last[-1])) last--; length = last - start; if (unlikely(length <= 0)) goto fallback; // parse NaN / inf value = __Pyx__PyBytes_AsDouble_inf_nan(start, length); if (value != 0.0) { if (unlikely(value == -1.0)) goto fallback; return value; } // look for underscores digits = 0; for (i=0; i < length; digits += start[i++] != '_'); if (likely(digits == length)) { value = PyOS_string_to_double(start, &end, NULL); valid_parse = (end == last); } else if (digits < 40) { char number[40]; last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); if (unlikely(!last)) goto fallback; value = PyOS_string_to_double(number, &end, NULL); valid_parse = (end == last); } else { char *number = (char*) PyMem_Malloc(((size_t) digits + 1) * sizeof(char)); if (unlikely(!number)) goto fallback; last = __Pyx__PyBytes_AsDouble_Copy(start, number, length); if (unlikely(!last)) { PyMem_Free(number); goto fallback; } value = PyOS_string_to_double(number, &end, NULL); valid_parse = (end == last); PyMem_Free(number); } if (likely(valid_parse) || (value == (double)-1 && PyErr_Occurred())) { return value; } fallback: return __Pyx_SlowPyString_AsDouble(obj); } /////////////// PyNumberPow2.proto /////////////// #define __Pyx_PyNumber_InPlacePowerOf2(a, b, c) __Pyx__PyNumber_PowerOf2(a, b, c, 1) #define __Pyx_PyNumber_PowerOf2(a, b, c) __Pyx__PyNumber_PowerOf2(a, b, c, 0) static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject *none, int inplace); /*proto*/ /////////////// PyNumberPow2 /////////////// //@requires: Exceptions.c::IgnoreException static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject *none, int inplace) { // in CPython, 1<= 0)) { if ((size_t)shiftby <= sizeof(long) * 8 - 2) { long value = 1L << shiftby; return PyLong_FromLong(value); } else if ((size_t)shiftby <= sizeof(unsigned PY_LONG_LONG) * 8 - 1) { unsigned PY_LONG_LONG value = ((unsigned PY_LONG_LONG)1) << shiftby; return PyLong_FromUnsignedLongLong(value); } else { PyObject *result, *one = PyLong_FromLong(1L); if (unlikely(!one)) return NULL; result = PyNumber_Lshift(one, exp); Py_DECREF(one); return result; } } else if (shiftby == -1) { PyObject *err = PyErr_Occurred(); if (err && !__Pyx_IgnoreGivenException(err, PyExc_Exception)) { return NULL; // BaseException } } fallback: #endif return (inplace ? PyNumber_InPlacePower : PyNumber_Power)(two, exp, none); } /////////////// PyNumberBinop.proto /////////////// #if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_GRAAL || CYTHON_COMPILING_IN_LIMITED_API #define __Pyx_{{op_name}}_{{type1}}_{{type2}}(op1, op2) {{op_name}}(op1, op2) #define __Pyx_{{inplace_op_name}}_{{type1}}_{{type2}}(op1, op2) {{inplace_op_name}}(op1, op2) #else #define __Pyx_{{op_name}}_{{type1}}_{{type2}}(op1, op2) __Pyx__{{op_name}}_{{type1}}_{{type2}}(op1, op2, 0) #define __Pyx_{{inplace_op_name}}_{{type1}}_{{type2}}(op1, op2) __Pyx__{{op_name}}_{{type1}}_{{type2}}(op1, op2, 1) static CYTHON_INLINE PyObject* __Pyx__{{op_name}}_{{type1}}_{{type2}}(PyObject *op1, PyObject *op2, int inplace); /*proto*/ #endif /////////////// PyNumberBinop /////////////// //@requires: ObjectHandling.c::RaiseErrorWithObjectTypes #if !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_GRAAL || CYTHON_COMPILING_IN_LIMITED_API) {{py: assert type1 in ('object', 'int', 'float'), type1 }} {{py: assert type2 in ('object', 'int', 'float'), type2 }} {{py: slot_name = {'+': 'add', '-': 'subtract', '*': 'multiply', '^': 'xor', '&': 'and', '|': 'or'}[c_op] }} {{py: def is_type(operand, expected, type1=type1, type2=type2): assert operand in ('op1', 'op2'), operand assert expected in ('int', 'float'), type type = type1 if operand == 'op1' else type2 if type == expected: check = f"likely({operand} != Py_None)" else: function = "PyFloat_CheckExact" if expected == 'float' else 'PyLong_CheckExact' check = f"{function}({operand})" other_type = type2 if operand == 'op1' else type1 if other_type == expected: check = f"likely({check})" return check }} {{if c_op in '+-*' or type1 != 'float'}} #if CYTHON_USE_TYPE_SLOTS || __PYX_LIMITED_VERSION_HEX >= 0x030A0000 #ifndef __Pyx_DEFINED_BinopTypeError #define __Pyx_DEFINED_BinopTypeError static void __Pyx_BinopTypeError(PyObject *op1, PyObject *op2, const char* op, int inplace) { // op1 is either 'int' or 'float', op2 is unknown. // op has either 1 or 2 characters, ending with NUL. char opname[4] = {op[0], op[1], 0, 0}; if (inplace) { opname[op[1] ? 2 : 1] = '='; } __Pyx_RaiseErrorWithObjectTypes1( PyExc_TypeError, "unsupported operand type(s) for %.3s: '" __Pyx_FMT_TYPENAME "' and '" __Pyx_FMT_TYPENAME "'", opname, op1, op2); } #endif #endif {{endif}} {{if c_op in '+-*'}} {{if type1 in ('object', 'float')}} #ifndef __Pyx_DEFINED_{{op_name}}_xfloat_{{type2}} #define __Pyx_DEFINED_{{op_name}}_xfloat_{{type2}} static PyObject* __Pyx_{{op_name}}_xfloat_{{type2}}(PyObject *op1, PyObject *op2, int inplace) { {{if type2 in ('object', 'int')}} if ({{is_type('op2', 'int')}}) { double int_op2; #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsCompact(op2)) { Py_ssize_t compact_op2 = __Pyx_PyLong_CompactValue(op2); {{if c_op in '+-'}} if (compact_op2 == 0) return __Pyx_NewRef(op1); {{endif}} int_op2 = (double) compact_op2; } else #endif { int_op2 = PyLong_AsDouble(op2); if (unlikely((int_op2 == -1.) && PyErr_Occurred())) return NULL; {{if c_op in '+-'}} #if !CYTHON_USE_PYLONG_INTERNALS if (int_op2 == 0.) return __Pyx_NewRef(op1); #endif {{endif}} } double float_op1 = __Pyx_PyFloat_AS_DOUBLE(op1); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely((float_op1 == -1.) && PyErr_Occurred())) return NULL; #endif {{if c_op == '*'}} // "0 * op2" could be handled before extracting op2, but that has the potential // to fail for very large numbers in op2 and we'd like to keep that error. if (float_op1 == 0.) return __Pyx_NewRef(op1); {{endif}} return PyFloat_FromDouble(float_op1 {{c_op}} int_op2); } {{endif}} {{if type2 == 'object'}} if (PyLong_Check(op2)) { // Pass PyLong subclasses to PyFloat-op1. binaryfunc slot_func = __Pyx_PyType_GetSubSlot(&PyFloat_Type, tp_as_number, nb_{{slot_name}}, binaryfunc); if (likely(slot_func)) { return slot_func(op1, op2); } } {{endif}} // PyFloat-op1 only handles exact PyFloat/PyLong as op2, everything else is left to op2. // PyLong-op2 is handled above, so we can always pass on to op2 here. // Avoid running into non-heap-type problems in Py<3.10 Limited API. #if CYTHON_USE_TYPE_SLOTS || __PYX_LIMITED_VERSION_HEX >= 0x030A0000 { PyTypeObject *type_op2 = Py_TYPE(op2); // Reverse operation => ignore 'InPlace' operator since it applies to op1, not op2. binaryfunc slot_func = __Pyx_PyType_GetSubSlot(type_op2, tp_as_number, nb_{{slot_name}}, binaryfunc); if (likely(slot_func)) { PyObject *result = slot_func(op1, op2); if (likely(result != Py_NotImplemented)) { return result; } Py_DECREF(result); } // No "sq_concat" since Python doesn't try it on op2 and 'float' definitely doesn't have it. __Pyx_BinopTypeError(op1, op2, "{{c_op}}", inplace); return NULL; } #else return (inplace) ? {{inplace_op_name}}(op1, op2) : {{op_name}}(op1, op2); #endif } #endif {{endif}} // c_op in '+-*' {{endif}} {{if type1 in ('object', 'int')}} #ifndef __Pyx_DEFINED_{{op_name}}_xint_{{type2}} #define __Pyx_DEFINED_{{op_name}}_xint_{{type2}} static PyObject* __Pyx_{{op_name}}_xint_{{type2}}(PyObject *op1, PyObject *op2, int inplace) { {{if type2 in ('object', 'float') and c_op in '+-*'}} if ({{is_type('op2', 'float')}}) { double int_op1; #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsCompact(op1)) { Py_ssize_t compact_op1 = __Pyx_PyLong_CompactValue(op1); {{if c_op == '+'}} if (compact_op1 == 0) return __Pyx_NewRef(op2); {{endif}} int_op1 = (double) compact_op1; } else #endif { int_op1 = PyLong_AsDouble(op1); if (unlikely((int_op1 == -1.) && PyErr_Occurred())) return NULL; {{if c_op == '+'}} #if !CYTHON_USE_PYLONG_INTERNALS if (int_op1 == 0.) return __Pyx_NewRef(op2); #endif {{endif}} } double float_op2 = __Pyx_PyFloat_AS_DOUBLE(op2); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely((float_op2 == -1.) && PyErr_Occurred())) return NULL; #endif return PyFloat_FromDouble(int_op1 {{c_op}} float_op2); } {{endif}} // PyLong-op1 only handles exact PyLong as op2, everything else is left to op2. // Thus, we can always pass on to op2 here. // Avoid running into non-heap-type problems in Py<3.10 Limited API. #if CYTHON_USE_TYPE_SLOTS || __PYX_LIMITED_VERSION_HEX >= 0x030A0000 { PyTypeObject *type_op2 = Py_TYPE(op2); // Reverse operation => ignore 'InPlace' operator since it applies to op1, not op2. binaryfunc slot_func = __Pyx_PyType_GetSubSlot(type_op2, tp_as_number, nb_{{slot_name}}, binaryfunc); if (likely(slot_func)) { PyObject *result = slot_func(op1, op2); if (likely(result != Py_NotImplemented)) { return result; } Py_DECREF(result); } // No "sq_concat" since Python doesn't try it on op2 and 'int' definitely doesn't have it. {{if c_op == '*'}} ssizeargfunc repeat_func = __Pyx_PyType_GetSubSlot(type_op2, tp_as_sequence, sq_repeat, ssizeargfunc); if (likely(repeat_func)) { Py_ssize_t count; #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsCompact(op1)) { count = __Pyx_PyLong_CompactValue(op1); } else #endif { count = PyLong_AsSsize_t(op1); if (unlikely((count == -1) && PyErr_Occurred())) return NULL; } return repeat_func(op2, count); } {{endif}} __Pyx_BinopTypeError(op1, op2, "{{c_op}}", inplace); return NULL; } #else return (inplace) ? {{inplace_op_name}}(op1, op2) : {{op_name}}(op1, op2); #endif } #endif {{endif}} static CYTHON_INLINE PyObject* __Pyx__{{op_name}}_{{type1}}_{{type2}}(PyObject *op1, PyObject *op2, int inplace) { {{if type1 in ('object', 'float') and c_op in '+-*'}} if ({{is_type('op1', 'float')}}) { {{if type2 in ('object', 'float')}} if ({{is_type('op2', 'float')}}) { double float_op2 = __Pyx_PyFloat_AS_DOUBLE(op2); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely((float_op2 == -1.) && PyErr_Occurred())) return NULL; #endif double float_op1 = __Pyx_PyFloat_AS_DOUBLE(op1); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely((float_op1 == -1.) && PyErr_Occurred())) return NULL; #endif return PyFloat_FromDouble(float_op1 {{c_op}} float_op2); } {{endif}} return __Pyx_{{op_name}}_xfloat_{{type2}}(op1, op2, inplace); } {{endif}} {{if type1 in ('object', 'int')}} if ({{is_type('op1', 'int')}}) { {{if type2 in ('object', 'int')}} if ({{is_type('op2', 'int')}}) { #if CYTHON_USE_PYLONG_INTERNALS {{if c_op == '*'}} if (__Pyx_PyLong_IsCompact(op1)) { long long int_op1 = (long long) __Pyx_PyLong_CompactValue(op1); if (int_op1 == 0) return __Pyx_NewRef(op1); if (__Pyx_PyLong_IsCompact(op2)) { long long int_op2 = (long long) __Pyx_PyLong_CompactValue(op2); if (int_op2 == 0) return __Pyx_NewRef(op2); return PyLong_FromLongLong(int_op1 {{c_op}} int_op2); } } {{else}} if (__Pyx_PyLong_IsCompact(op1)) { Py_ssize_t int_op1 = __Pyx_PyLong_CompactValue(op1); {{if c_op in '+|^'}} if (int_op1 == 0) return __Pyx_NewRef(op2); {{elif c_op == '&'}} if (int_op1 == 0) return __Pyx_NewRef(op1); {{endif}} if (__Pyx_PyLong_IsCompact(op2)) { Py_ssize_t int_op2 = __Pyx_PyLong_CompactValue(op2); {{if c_op in '+-|^'}} if (int_op2 == 0) return __Pyx_NewRef(op1); {{elif c_op == '&'}} if (int_op2 == 0) return __Pyx_NewRef(op2); {{endif}} return PyLong_FromSsize_t(int_op1 {{c_op}} int_op2); } } {{endif}} // op1 is not compact, but op2 might still hit the special case for '0': // identity for '+-|^' -> reuse op1 // zero for '*&' -> reuse op2 else if (__Pyx_PyLong_IsZero(op2)) return __Pyx_NewRef({{if c_op in '+-|^'}}op1{{else}}op2{{endif}}); #endif binaryfunc slot_func = __Pyx_PyType_GetSubSlot(&PyLong_Type, tp_as_number, nb_{{slot_name}}, binaryfunc); if (likely(slot_func)) { return slot_func(op1, op2); } } {{endif}} return __Pyx_{{op_name}}_xint_{{type2}}(op1, op2, inplace); } {{endif}} return (inplace) ? {{inplace_op_name}}(op1, op2) : {{op_name}}(op1, op2); } // !(PyPy/Graal/LimitedAPI) #endif /////////////// UnicodeEquals.proto /////////////// //@requires: PyObjectCompare{"return_obj": 0, "op": "Eq", "c_op": "==", "type1": "str", "type2": "str"} #define __Pyx_PyUnicode_Equals(s1, s2) __Pyx_PyObject_CompareBoolEq_str_str(s1, s2, Py_EQ) /////////////// PyObjectCompare.proto /////////////// {{py: c_ret_type = 'PyObject*' if return_obj else 'int'}} static CYTHON_INLINE {{c_ret_type}} __Pyx_PyObject_Compare{{'' if return_obj else 'Bool'}}{{op}}_{{type1}}_{{type2}}(PyObject *op1, PyObject *op2, int pyop); /*proto*/ /////////////// PyObjectCompare /////////////// //@requires: StringTools.c::IncludeStringH {{py: c_ret_type = 'PyObject*' if return_obj else 'int'}} {{py: func_suffix = f"{'' if return_obj else 'Bool'}{op}"}} {{py: return_true = 'goto __pyx_return_true'}} {{py: return_false = 'goto __pyx_return_false'}} {{py: return_error = "return NULL" if return_obj else "return -1"}} {{py: c_op_reversed = {'==': '==', '!=': '!=', '<': '>=', '<=': '>', '>=': '<', '>': '<='}[c_op] }} {{py: check_functions = { 'float': "PyFloat_CheckExact", 'int': 'PyLong_CheckExact', 'str': 'PyUnicode_CheckExact', 'bytes': 'PyBytes_CheckExact', 'bytearray': 'PyByteArray_CheckExact', } }} {{py: def is_type(operand, expected, type1=type1, type2=type2, check_functions=check_functions): assert operand in ('op1', 'op2'), operand assert expected in check_functions, expected type = type1 if operand == 'op1' else type2 if type == expected: check = f"likely({operand} != Py_None)" else: function = check_functions[expected] check = f"{function}({operand})" other_type = type2 if operand == 'op1' else type1 if other_type == expected: check = f"likely({check})" return check }} // str comparisons {{if type1 in ('object', 'str') and type2 in ('object', 'str')}} #ifndef __Pyx_DEFINED_PyObject_CompareStrStr{{func_suffix}} #define __Pyx_DEFINED_PyObject_CompareStrStr{{func_suffix}} static CYTHON_INLINE {{c_ret_type}} __Pyx_PyObject_CompareStrStr{{func_suffix}}(PyObject* s1, PyObject* s2) { {{if op in 'EqNe'}} #if __PYX_LIMITED_VERSION_HEX >= 0x030e0000 int result = PyUnicode_Equal(s1, s2); #if !CYTHON_COMPILING_IN_CPYTHON // Cannot fail in CPython, but might in others. if (unlikely(result == -1)) {{return_error}}; #endif if (result {{c_op}} 0) {{return_false}}; else {{return_true}}; #else {{endif}} int result = PyUnicode_Compare(s1, s2); if (unlikely((result == -1) && PyErr_Occurred())) {{return_error}}; if (result {{c_op}} 0) {{return_true}}; else {{return_false}}; {{if op in 'EqNe'}} #endif {{endif}} __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } #endif // end of str comparisons {{endif}} // bytes/bytearray comparisons {{for s1_type in ('bytes', 'bytearray')}} {{for s2_type in ('bytes', 'bytearray')}} {{if type1 in ('object', s1_type) and type2 in ('object', s2_type)}} {{py: s1_prefix = "PyBytes" if s1_type == 'bytes' else "PyByteArray"}} {{py: s2_prefix = "PyBytes" if s2_type == 'bytes' else "PyByteArray"}} #if !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_GRAAL) #ifndef __Pyx_DEFINED_PyObject_Compare{{s1_prefix}}{{s2_prefix}}{{func_suffix}} #define __Pyx_DEFINED_PyObject_Compare{{s1_prefix}}{{s2_prefix}}{{func_suffix}} {{if op in 'EqNe'}} static CYTHON_INLINE {{c_ret_type}} __Pyx_PyObject_Compare{{s1_prefix}}{{s2_prefix}}{{func_suffix}}(PyObject* s1, PyObject* s2) { #if CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS const char *ps1, *ps2; Py_ssize_t length = {{s1_prefix}}_GET_SIZE(s1); if (length != {{s2_prefix}}_GET_SIZE(s2)) {{return_false if op == 'Eq' else return_true}}; ps1 = {{s1_prefix}}_AS_STRING(s1); ps2 = {{s2_prefix}}_AS_STRING(s2); #else char *ps1, *ps2; Py_ssize_t length, length2; {{if s1_type == 'bytes'}} if (unlikely(PyBytes_AsStringAndSize(s1, &ps1, &length) == -1)) {{return_error}}; {{else}} ps1 = __Pyx_PyByteArray_AsString(s1); if (unlikely(!ps1)) {{return_error}}; length = __Pyx_PyByteArray_GET_SIZE(s1); if (unlikely(length == -1)) {{return_error}}; {{endif}} {{if s2_type == 'bytes'}} if (unlikely(PyBytes_AsStringAndSize(s2, &ps2, &length2) == -1)) {{return_error}}; {{else}} ps2 = __Pyx_PyByteArray_AsString(s2); if (unlikely(!ps2)) {{return_error}}; length2 = __Pyx_PyByteArray_GET_SIZE(s2); if (unlikely(length2 == -1)) {{return_error}}; {{endif}} if (length != length2) {{return_false if op == 'Eq' else return_true}}; #endif // len(s1) == len(s2) {{if s1_type == 'bytearray'}} if (length == 0) {{return_true if op == 'Eq' else return_false}}; {{else}} // bytes: length >= 1 (empty bytes is singleton, and "s1 is not s2") {{endif}} if (ps1[0] != ps2[0]) {{return_false if op == 'Eq' else return_true}}; if (length == 1) {{return_true if op == 'Eq' else return_false}}; { int cmp; {{if s1_type == 'bytes' and s2_type == 'bytes'}} #if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) Py_hash_t hash1 = ((PyBytesObject*)s1)->ob_shash; Py_hash_t hash2 = ((PyBytesObject*)s2)->ob_shash; if (hash1 != hash2 && hash1 != -1 && hash2 != -1) {{return_false if op == 'Eq' else return_true}}; #endif {{endif}} cmp = memcmp(ps1, ps2, (size_t)length); if (cmp {{c_op}} 0) {{return_true}}; else {{return_false}}; } __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } {{else}} // !EqNe static CYTHON_INLINE {{c_ret_type}} __Pyx_PyObject_Compare{{s1_prefix}}{{s2_prefix}}{{func_suffix}}(PyObject* s1, PyObject* s2) { Py_ssize_t cmp; Py_ssize_t length1, length2, short_length; #if CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS const char *ps1, *ps2; length1 = __Pyx_{{s1_prefix}}_GET_SIZE(s1); length2 = __Pyx_{{s2_prefix}}_GET_SIZE(s2); short_length = (length1 < length2) ? length1 : length2; if (short_length == 0) { if (length1 == 0) {{return_true if op in 'LtLe' else return_false}}; else {{return_false if op in 'LtLe' else return_true}}; } ps1 = {{s1_prefix}}_AS_STRING(s1); ps2 = {{s2_prefix}}_AS_STRING(s2); #else char *ps1, *ps2; {{if s1_type == 'bytes'}} if (unlikely(PyBytes_AsStringAndSize(s1, &ps1, &length1) == -1)) {{return_error}}; {{else}} ps1 = __Pyx_PyByteArray_AsString(s1); if (unlikely(!ps1)) {{return_error}}; length1 = __Pyx_PyByteArray_GET_SIZE(s1); if (unlikely(length1 == -1)) {{return_error}}; {{endif}} {{if s2_type == 'bytes'}} if (unlikely(PyBytes_AsStringAndSize(s2, &ps2, &length2) == -1)) {{return_error}}; {{else}} ps2 = __Pyx_PyByteArray_AsString(s2); if (unlikely(!ps2)) {{return_error}}; length2 = __Pyx_PyByteArray_GET_SIZE(s2); if (unlikely(length2 == -1)) {{return_error}}; {{endif}} short_length = (length1 < length2) ? length1 : length2; if (short_length == 0) { if (length1 == 0) {{return_true if op in 'LtLe' else return_false}}; else {{return_false if op in 'LtLe' else return_true}}; } #endif cmp = (Py_ssize_t) ((const unsigned char*) ps1)[0] - (Py_ssize_t) ((const unsigned char*) ps2)[0]; if (cmp == 0 && short_length > 1) { cmp = memcmp(ps1, ps2, (size_t)short_length); } if (cmp == 0) cmp = (length1 - length2); if (cmp {{c_op}} 0) {{return_true}}; else {{return_false}}; __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } {{endif}} // End of bytes/bytearray comparisons. #endif #endif {{endif}} {{endfor}} {{endfor}} // float/int comparisons {{if type1 in ('object', 'float') and type2 in ('object', 'int')}} // Less likely, non-inlined comparison of float and int. #ifndef __Pyx_DEFINED_PyObject_CompareFloatInt{{func_suffix}} #define __Pyx_DEFINED_PyObject_CompareFloatInt{{func_suffix}} static {{c_ret_type}} __Pyx_PyObject_CompareFloatInt{{func_suffix}}(PyObject *op1, PyObject *op2) { double float_op1 = __Pyx_PyFloat_AS_DOUBLE(op1); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely(float_op1 == -1. && PyErr_Occurred())) {{return_error}}; #endif #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsCompact(op2)) { Py_ssize_t iop2 = __Pyx_PyLong_CompactValue(op2); if (float_op1 {{c_op}} ((double)iop2)) {{return_true}}; else {{return_false}}; } if (unlikely(!isfinite(float_op1))) { // CPython just compares inf/nan to 0.0 if (float_op1 {{c_op}} 0.0) {{return_true}}; else {{return_false}}; } else { // op2 != 0 (which would be compact) int sign2 = __Pyx_PyLong_Sign(op2); if (float_op1 >= 0.) { if (sign2 < 0) {{return_true if op in 'NeGeGt' else return_false}}; // same sign - is float value compact while PyLong is not? if (float_op1 < (double) (1L << PyLong_SHIFT)) {{return_true if op in 'NeLeLt' else return_false}}; } else { if (sign2 > 0) {{return_true if op in 'NeLeLt' else return_false}}; // same sign - is float value compact while PyLong is not? if (float_op1 > -(double) (1L << PyLong_SHIFT)) {{return_false if op in 'EqLeLt' else return_true}}; } } #else if (unlikely(!isfinite(float_op1))) { // CPython just compares inf/nan to 0.0 if (float_op1 {{c_op}} 0.0) {{return_true}}; else {{return_false}}; } else { int overflow2; // We know that we have an exact PyLong value, so we assume no exceptions. long iop2 = PyLong_AsLongAndOverflow(op2, &overflow2); if (likely(!overflow2)) { if ((long long) iop2 >= (1LL << 53)) { overflow2 = 1; } else if ((long long) iop2 <= - (1LL << 53)) { overflow2 = -1; } else { if (float_op1 {{c_op}} ((double) iop2)) {{return_true}}; else {{return_false}}; } } if (overflow2 > 0) { if (float_op1 < ((double) (1LL << 53))) {{return_true if op in 'NeLeLt' else return_false}}; } else { if (float_op1 > - ((double) (1LL << 53))) {{return_true if op in 'NeGeGt' else return_false}}; } } #endif return {{'PyObject_RichCompare' if return_obj else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } #endif {{endif}} {{if type1 in ('object', 'int') and type2 in ('object', 'float')}} // Less likely, non-inlined comparison of int and float. #ifndef __Pyx_DEFINED_PyObject_CompareIntFloat{{func_suffix}} #define __Pyx_DEFINED_PyObject_CompareIntFloat{{func_suffix}} static {{c_ret_type}} __Pyx_PyObject_CompareIntFloat{{func_suffix}}(PyObject *op1, PyObject *op2) { double float_op2 = __Pyx_PyFloat_AS_DOUBLE(op2); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely(float_op2 == -1. && PyErr_Occurred())) {{return_error}}; #endif #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsCompact(op1)) { Py_ssize_t iop1 = __Pyx_PyLong_CompactValue(op1); if (((double)iop1) {{c_op}} float_op2) {{return_true}}; else {{return_false}}; } if (unlikely(!isfinite(float_op2))) { // CPython just compares inf/nan to 0.0 if (0.0 {{c_op}} float_op2) {{return_true}}; else {{return_false}}; } else { // op1 != 0 (which would be compact) int sign1 = __Pyx_PyLong_Sign(op1); if (float_op2 >= 0.) { if (sign1 < 0) {{return_true if op in 'NeLeLt' else return_false}}; // same sign - is float value compact while PyLong is not? if (float_op2 < (double) (1L << PyLong_SHIFT)) {{return_true if op in 'NeGeGt' else return_false}}; } else { if (sign1 > 0) {{return_true if op in 'NeGeGt' else return_false}}; // same sign - is float value compact while PyLong is not? if (float_op2 > -(double) (1L << PyLong_SHIFT)) {{return_false if op in 'EqGeGt' else return_true}}; } } #else if (unlikely(!isfinite(float_op2))) { // CPython just compares inf/nan to 0.0 if (0.0 {{c_op}} float_op2) {{return_true}}; else {{return_false}}; } else { int overflow1; // We know that we have an exact PyLong value, so we assume no exceptions. long iop1 = PyLong_AsLongAndOverflow(op1, &overflow1); if (likely(!overflow1)) { if ((long long) iop1 >= (1LL << 53)) { overflow1 = 1; } else if ((long long) iop1 <= - (1LL << 53)) { overflow1 = -1; } else { if (((double) iop1) {{c_op}} float_op2) {{return_true}}; else {{return_false}}; } } if (overflow1 < 0) { if (float_op2 > ((double) (1LL << 53))) {{return_true if op in 'NeLeLt' else return_false}}; } else { if (float_op2 < - ((double) (1LL << 53))) {{return_true if op in 'NeGeGt' else return_false}}; } } #endif return {{'PyObject_RichCompare' if return_obj else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } #endif {{endif}} {{if type1 in ('object', 'int') and type2 in ('object', 'int')}} {{py: from Cython.Utility import pylong_join }} #ifndef __Pyx_DEFINED_PyObject_CompareIntInt{{func_suffix}} #define __Pyx_DEFINED_PyObject_CompareIntInt{{func_suffix}} static {{c_ret_type}} __Pyx_PyObject_CompareIntInt{{func_suffix}}(PyObject *op1, PyObject *op2) { #if CYTHON_USE_PYLONG_INTERNALS Py_ssize_t cmp = __Pyx_PyLong_CompareSignAndSize(op1, op2); if (cmp == 0) { Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); if (size > 0) { const digit* digits1 = __Pyx_PyLong_Digits(op1); const digit* digits2 = __Pyx_PyLong_Digits(op2); if (size == 1) { cmp = (Py_ssize_t) digits1[0] - (Py_ssize_t) digits2[0]; } else if ((size == 2) && (8 * sizeof(Py_ssize_t) >= 2 * PyLong_SHIFT)) { cmp = (Py_ssize_t) {{pylong_join(2, 'digits1', 'size_t')}} - (Py_ssize_t) {{pylong_join(2, 'digits2', 'size_t')}}; } else { for (Py_ssize_t i=size-1; i >= 0 && !cmp; --i) { cmp = (Py_ssize_t) digits1[i] - (Py_ssize_t) digits2[i]; } } } if (cmp == 0) {{return_true if op in 'EqLeGe' else return_false}}; if (__Pyx_PyLong_IsNeg(op1)) cmp = -cmp; } {{if op == 'Eq'}} {{return_false}}; {{elif op == 'Ne'}} {{return_true}}; {{else}} if (cmp < 0) {{return_true if op in 'LeLt' else return_false}}; else {{return_false if op in 'LeLt' else return_true}}; {{endif}} #else int overflow1, overflow2; // We know that we have two exact PyLong values, so we assume no exceptions. long long iop1 = PyLong_AsLongLongAndOverflow(op1, &overflow1); long long iop2 = PyLong_AsLongLongAndOverflow(op2, &overflow2); if (likely(!(overflow1 | overflow2))) { if (iop1 {{c_op}} iop2) {{return_true}}; else {{return_false}}; } else if (overflow1 != overflow2) { if (overflow1 {{c_op}} overflow2) {{return_true}}; else {{return_false}}; } else { return {{'PyObject_RichCompare' if return_obj else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); } #endif __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } #endif // end of float/int comparisons {{endif}} // main comparison function static CYTHON_INLINE {{c_ret_type}} __Pyx_PyObject_Compare{{func_suffix}}_{{type1}}_{{type2}}(PyObject *op1, PyObject *op2, int pyop) { CYTHON_UNUSED_VAR(pyop); {{if type1 != 'object'}} // For concrete types, the whole rest simplifies a lot if we handle None up front. if (unlikely(op1 == Py_None)) { {{if op == 'Eq'}} if (op2 == Py_None) {{return_true}}; else {{if type2 != 'object'}}{{return_false}}{{else}}goto __pyx_richcmp{{endif}}; {{elif op == 'Ne'}} if (op2 == Py_None) {{return_false}}; else {{if type2 != 'object'}}{{return_true}}{{else}}goto __pyx_richcmp{{endif}}; {{else}} goto __pyx_richcmp; {{endif}} } {{endif}} {{if type2 != 'object'}} if (unlikely(op2 == Py_None)) { {{if op == 'Eq'}} if (op1 == Py_None) {{return_true}}; else {{if type1 != 'object'}}{{return_false}}{{else}}goto __pyx_richcmp{{endif}}; {{elif op == 'Ne'}} if (op1 == Py_None) {{return_false}}; else {{if type1 != 'object'}}{{return_true}}{{else}}goto __pyx_richcmp{{endif}}; {{else}} goto __pyx_richcmp; {{endif}} } {{endif}} {{if (type1 == 'int' or type2 == 'int') and (type1 != 'float' and type2 != 'float')}} if (op1 == op2) {{return_true if op in 'EqLeGe' else return_false}}; {{endif}} {{if type1 in ('object', 'float')}} if ({{is_type('op1', 'float')}}) { {{if type2 in ('object', 'float')}} if ({{is_type('op2', 'float')}}) { double float_op1 = __Pyx_PyFloat_AS_DOUBLE(op1); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely(float_op1 == -1. && PyErr_Occurred())) {{return_error}}; #endif double float_op2 = __Pyx_PyFloat_AS_DOUBLE(op2); #if !CYTHON_ASSUME_SAFE_MACROS if (unlikely(float_op2 == -1. && PyErr_Occurred())) {{return_error}}; #endif if (float_op1 {{c_op}} float_op2) {{return_true}}; else {{return_false}}; } {{endif}} {{if type2 in ('object', 'int')}} if ({{is_type('op2', 'int')}}) { return __Pyx_PyObject_CompareFloatInt{{func_suffix}}(op1, op2); } {{endif}} goto __pyx_richcmp; } {{endif}} {{if type1 in ('object', 'int')}} if ({{is_type('op1', 'int')}}) { if (op1 == op2) {{return_true if op in 'EqLeGe' else return_false}}; {{if type2 in ('object', 'int')}} if ({{is_type('op2', 'int')}}) { return __Pyx_PyObject_CompareIntInt{{func_suffix}}(op1, op2); } {{endif}} {{if type2 in ('object', 'float')}} if ({{is_type('op2', 'float')}}) { return __Pyx_PyObject_CompareIntFloat{{func_suffix}}(op1, op2); } {{endif}} goto __pyx_richcmp; } {{endif}} {{for string_type in ('str', 'bytes', 'bytearray')}} {{if type1 in ('object', string_type) and type2 in ('object', string_type)}} {{if string_type != 'str'}}#if !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_GRAAL){{endif}} if ({{is_type('op1', string_type)}}) { // Catch interned and identical strings as well as the empty string. if (op1 == op2) {{return_true if op in 'EqLeGe' else return_false}}; if ({{is_type('op2', string_type)}}) { {{if string_type == 'bytes'}} return __Pyx_PyObject_ComparePyBytesPyBytes{{func_suffix}}(op1, op2); {{elif string_type == 'bytearray'}} return __Pyx_PyObject_ComparePyByteArrayPyByteArray{{func_suffix}}(op1, op2); {{else}} return __Pyx_PyObject_CompareStrStr{{func_suffix}}(op1, op2); {{endif}} } {{if string_type == 'bytes' and type2 in ('object', 'bytearray')}} if ({{is_type('op2', 'bytearray')}}) { return __Pyx_PyObject_ComparePyBytesPyByteArray{{func_suffix}}(op1, op2); } {{elif string_type == 'bytearray' and type2 in ('object', 'bytes')}} if ({{is_type('op2', 'bytes')}}) { return __Pyx_PyObject_ComparePyByteArrayPyBytes{{func_suffix}}(op1, op2); } {{endif}} goto __pyx_richcmp; } {{if string_type != 'str'}}#endif{{endif}} {{endif}} {{endfor}} // avoid unused labels if ((0)) goto __pyx_richcmp; if ((0)) {{return_true}}; if ((0)) {{return_false}}; __pyx_richcmp: return {{'PyObject_RichCompare' if return_obj else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); __pyx_return_true: {{'Py_RETURN_TRUE' if return_obj else 'return 1'}}; __pyx_return_false: {{'Py_RETURN_FALSE' if return_obj else 'return 0'}}; } /////////////// PyLongCompare.proto /////////////// {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} static CYTHON_INLINE {{c_ret_type}} __Pyx_PyLong_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, long inplace); /*proto*/ /////////////// PyLongCompare /////////////// {{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }} {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} {{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}} {{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}} {{py: slot_name = op.lower() }} {{py: c_op = {'Eq': '==', 'Ne': '!='}[op] }} {{py: return_compare = ( (lambda a,b,c_op, return_true=return_true, return_false=return_false: "if ({a} {c_op} {b}) {return_true}; else {return_false};".format( a=a, b=b, c_op=c_op, return_true=return_true, return_false=return_false)) if ret_type.is_pyobject else (lambda a,b,c_op: "return ({a} {c_op} {b});".format(a=a, b=b, c_op=c_op)) ) }} static CYTHON_INLINE {{c_ret_type}} __Pyx_PyLong_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, long inplace) { CYTHON_MAYBE_UNUSED_VAR(intval); CYTHON_UNUSED_VAR(inplace); if (op1 == op2) { {{return_true if op == 'Eq' else return_false}}; } #if CYTHON_USE_PYLONG_INTERNALS if (likely(PyLong_CheckExact({{pyval}}))) { int unequal; unsigned long uintval; Py_ssize_t size = __Pyx_PyLong_DigitCount({{pyval}}); const digit* digits = __Pyx_PyLong_Digits({{pyval}}); if (intval == 0) { {{return_compare('__Pyx_PyLong_IsZero(%s)' % pyval, '1', c_op)}} } else if (intval < 0) { if (__Pyx_PyLong_IsNonNeg({{pyval}})) {{return_false if op == 'Eq' else return_true}}; // both are negative => can use absolute values now. intval = -intval; } else { // > 0 => Py_SIZE(pyval) > 0 if (__Pyx_PyLong_IsNeg({{pyval}})) {{return_false if op == 'Eq' else return_true}}; } // After checking that the sign is the same (and excluding 0), now compare the absolute values. // When inlining, the C compiler should select exactly one line from this unrolled loop. uintval = (unsigned long) intval; {{for _size in range(4, 0, -1)}} #if PyLong_SHIFT * {{_size}} < SIZEOF_LONG*8 if (uintval >> (PyLong_SHIFT * {{_size}})) { // The C integer value is between (PyLong_BASE ** _size) and MIN(PyLong_BASE ** _size, LONG_MAX). unequal = (size != {{_size+1}}) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) {{for _i in range(1, _size+1)}} | (digits[{{_i}}] != ((uintval >> ({{_i}} * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)){{endfor}}; } else #endif {{endfor}} unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); {{return_compare('unequal', '0', c_op)}} } #endif if (PyFloat_CheckExact({{pyval}})) { const long {{'a' if order == 'CObj' else 'b'}} = intval; double {{ival}} = __Pyx_PyFloat_AS_DOUBLE({{pyval}}); {{return_compare('(double)a', '(double)b', c_op)}} } return {{'PyObject_RichCompare' if ret_type.is_pyobject else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); } /////////////// PyLongBinop.proto /////////////// {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} #if !CYTHON_COMPILING_IN_PYPY static CYTHON_INLINE {{c_ret_type}} __Pyx_PyLong_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); /*proto*/ #else #define __Pyx_PyLong_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(op1, op2, intval, inplace, zerodivision_check) \ {{if op in ('Eq', 'Ne')}}{{'PyObject_RichCompare' if ret_type.is_pyobject else 'PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}) {{else}}(inplace ? PyNumber_InPlace{{op}}(op1, op2) : PyNumber_{{op}}(op1, op2)) {{endif}} #endif /////////////// PyLongBinop /////////////// #if !CYTHON_COMPILING_IN_PYPY {{py: from Cython.Utility import pylong_join }} {{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }} {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} {{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}} {{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}} {{py: slot_name = {'TrueDivide': 'true_divide', 'FloorDivide': 'floor_divide'}.get(op, op.lower()) }} {{py: cfunc_name = f"__Pyx_PyLong_{'' if ret_type.is_pyobject else 'Bool'}{op}{order}" }} {{py: c_op = { 'Add': '+', 'Subtract': '-', 'Multiply': '*', 'Remainder': '%', 'TrueDivide': '/', 'FloorDivide': '/', 'Or': '|', 'Xor': '^', 'And': '&', 'Rshift': '>>', 'Lshift': '<<', 'Eq': '==', 'Ne': '!=', }[op] }} {{py: def zerodiv_check(operand, optype='integer', _is_mod=op == 'Remainder', _needs_check=(order == 'CObj' and c_op in '%/')): return ((( 'if (unlikely(zerodivision_check && ((%s) == 0))) {' ' PyErr_SetString(PyExc_ZeroDivisionError, "%s division%s by zero");' ' return NULL;' '}') % (operand, optype, ' or modulo' if _is_mod else '') ) if _needs_check else '') }} static {{c_ret_type}} __Pyx_Fallback_{{cfunc_name}}(PyObject *op1, PyObject *op2, int inplace) { {{if op in ('Eq', 'Ne')}} CYTHON_UNUSED_VAR(inplace); return {{'PyObject_RichCompare' if ret_type.is_pyobject else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); {{else}} return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2); {{endif}} } #if CYTHON_USE_PYLONG_INTERNALS {{if op == 'Lshift'}} #if __clang__ || __GNUC__ // left-shift by more than the width of the number is undefined behaviour. // We do check it (and test that it gives the right answer though). __attribute__((no_sanitize("shift"))) #endif {{endif}} static {{c_ret_type}} __Pyx_Unpacked_{{cfunc_name}}(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { CYTHON_MAYBE_UNUSED_VAR(inplace); CYTHON_UNUSED_VAR(zerodivision_check); const long {{'a' if order == 'CObj' else 'b'}} = intval; long {{ival}}; {{if op not in ('Eq', 'Ne', 'TrueDivide')}} const PY_LONG_LONG ll{{'a' if order == 'CObj' else 'b'}} = intval; PY_LONG_LONG ll{{ival}}; {{endif}} {{if op == 'Rshift' or op == 'Lshift'}} // shifting negative numbers is technically implementation defined on C, and // C++ before C++20. Most implementation do the right thing though so // special case ones we know are good. #if (defined(__cplusplus) && __cplusplus >= 202002L) \ || (defined(__GNUC__) || (defined(__clang__))) && \ (defined(__arm__) || defined(__x86_64__) || defined(__i386__)) \ || (defined(_MSC_VER) && \ (defined(_M_ARM) || defined(_M_AMD64) || defined(_M_IX86))) const int negative_shift_works = 1; #else const int negative_shift_works = 0; #endif {{endif}} // special cases for 0: + - * % / // | ^ & >> << if (unlikely(__Pyx_PyLong_IsZero({{pyval}}))) { {{if order == 'CObj' and c_op in '%/'}} // division by zero! {{zerodiv_check('0')}} {{elif order == 'CObj' and c_op in '+-|^>><<'}} // x == x+0 == x-0 == x|0 == x^0 == x>>0 == x<<0 return __Pyx_NewRef(op1); {{elif order == 'CObj' and c_op in '*&'}} // 0 == x*0 == x&0 return __Pyx_NewRef(op2); {{elif order == 'ObjC' and c_op in '+|^'}} // x == 0+x == 0|x == 0^x return __Pyx_NewRef(op2); {{elif order == 'ObjC' and c_op == '-'}} // -x == 0-x return PyLong_FromLong(-intval); {{elif order == 'ObjC' and (c_op in '*%&>><<' or op == 'FloorDivide')}} // 0 == 0*x == 0%x == 0&x == 0>>x == 0< {{_size}} * PyLong_SHIFT{{if c_op == '*'}}+30{{endif}}{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) { {{ival}} = (long) {{pylong_join(_size, 'digits')}}; if (!is_positive) {{ival}} *= -1; goto calculate_long; {{if op != 'TrueDivide'}} } else if (size == {{_size}} && 8 * sizeof(PY_LONG_LONG) - 1 > {{_size}} * PyLong_SHIFT{{if c_op == '*'}}+30{{endif}}) { ll{{ival}} = (PY_LONG_LONG) {{pylong_join(_size, 'digits', 'unsigned PY_LONG_LONG')}}; if (!is_positive) ll{{ival}} *= -1; goto calculate_long_long; {{endif}} } else // size doesn't fit into a long or PY_LONG_LONG any more {{endfor}} {} {{if op in ('Eq', 'Ne')}} #if PyLong_SHIFT < 30 && PyLong_SHIFT != 15 // unusual setup - your fault return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}( PyLong_Type.tp_richcompare({{'op1, op2' if order == 'ObjC' else 'op2, op1'}}, Py_{{op.upper()}})); #else // too large for the long values we allow => definitely not equal {{return_false if op == 'Eq' else return_true}}; #endif {{else}} return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); {{endif}} } calculate_long: {{if op in ('Eq', 'Ne')}} if (a {{c_op}} b) { {{return_true}}; } else { {{return_false}}; } {{elif c_op == '*'}} // Multiplying a 'long' value with a <= 30 bits constant can give a 'long long' value. // Note that we constrain the bit count of the PyLong in the unpacking code above. CYTHON_UNUSED_VAR(a); CYTHON_UNUSED_VAR(b); ll{{ival}} = {{ival}}; goto calculate_long_long; {{elif c_op == '%'}} { // see CMath.c :: ModInt utility code long x = a % b; x += ((x != 0) & ((x ^ b) < 0)) * b; return PyLong_FromLong(x); } {{elif op == 'TrueDivide'}} if ((8 * sizeof(long) <= 53 || likely(labs({{ival}}) <= ((PY_LONG_LONG)1 << 53))) || __Pyx_PyLong_DigitCount({{pyval}}) <= 52 / PyLong_SHIFT) { return PyFloat_FromDouble((double)a / (double)b); } return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); {{elif op == 'FloorDivide'}} { long q, r; // see CMath.c :: DivInt utility code q = a / b; r = a - q*b; q -= ((r != 0) & ((r ^ b) < 0)); return PyLong_FromLong(q); } {{else}} {{if op == 'Rshift' or op == 'Lshift'}} if ((!negative_shift_works) && unlikely(a < 0)) goto fallback; {{endif}} { long x; {{if op == 'Rshift'}} if (unlikely(b >= (long) (sizeof(long)*8))) { x = (a < 0) ? -1 : 0; } else {{endif}} x = a {{c_op}} b; {{if op == 'Lshift'}} if (unlikely(!(b < (long) (sizeof(long)*8) && a == x >> b)) && a) { ll{{ival}} = {{ival}}; goto calculate_long_long; } {{endif}} return PyLong_FromLong(x); } {{endif}} {{if op != 'TrueDivide'}} calculate_long_long: {{if op == 'Eq'}} // One operand fits into a 30 bit 'long', the other doesn't => not equal. {{return_false}}; {{elif op == 'Ne'}} // One operand fits into a 30 bit 'long', the other doesn't => not equal. {{return_true}}; {{elif c_op == '%'}} { // see CMath.c :: ModInt utility code PY_LONG_LONG llx = lla % llb; llx += ((llx != 0) & ((llx ^ llb) < 0)) * llb; return PyLong_FromLongLong(llx); } {{elif op == 'FloorDivide'}} { PY_LONG_LONG q, r; // see CMath.c :: DivInt utility code q = lla / llb; r = lla - q*llb; q -= ((r != 0) & ((r ^ llb) < 0)); return PyLong_FromLongLong(q); } {{else}} {{if op == 'LShift' or op == 'Rshift'}} if ((!negative_shift_works) && unlikely(lla < 0)) goto fallback; {{endif}} { PY_LONG_LONG llx; {{if op == 'Rshift'}} if (unlikely(llb >= (long long) (sizeof(long long)*8))) { llx = (lla < 0) ? -1 : 0; } else {{endif}} llx = lla {{c_op}} llb; {{if op == 'Lshift'}} if (unlikely(lla != llx >> llb)) goto fallback; {{endif}} return PyLong_FromLongLong(llx); } {{endif}} {{if op == 'Lshift' or op == 'Rshift'}} fallback: return __Pyx_Fallback_{{cfunc_name}}(op1, op2, inplace); {{endif}} {{endif}}{{# if op != 'TrueDivide' #}} } #endif {{if c_op in '+-*' or op in ('TrueDivide', 'Eq', 'Ne')}} static {{c_ret_type}} __Pyx_Float_{{cfunc_name}}(PyObject *float_val, long intval, int zerodivision_check) { CYTHON_UNUSED_VAR(zerodivision_check); const long {{'a' if order == 'CObj' else 'b'}} = intval; double {{ival}} = __Pyx_PyFloat_AS_DOUBLE(float_val); {{if op in ('Eq', 'Ne')}} if ((double)a {{c_op}} (double)b) { {{return_true}}; } else { {{return_false}}; } {{else}} double result; {{zerodiv_check('b', 'float')}} result = ((double)a) {{c_op}} (double)b; return PyFloat_FromDouble(result); {{endif}} } {{endif}} static CYTHON_INLINE {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { CYTHON_MAYBE_UNUSED_VAR(intval); CYTHON_UNUSED_VAR(zerodivision_check); {{if op in ('Eq', 'Ne')}} if (op1 == op2) { {{return_true if op == 'Eq' else return_false}}; } {{endif}} #if CYTHON_USE_PYLONG_INTERNALS if (likely(PyLong_CheckExact({{pyval}}))) { return __Pyx_Unpacked_{{cfunc_name}}(op1, op2, intval, inplace, zerodivision_check); } #endif {{if c_op in '+-*' or op in ('TrueDivide', 'Eq', 'Ne')}} if (PyFloat_CheckExact({{pyval}})) { return __Pyx_Float_{{cfunc_name}}({{pyval}}, intval, zerodivision_check); } {{endif}} return __Pyx_Fallback_{{cfunc_name}}(op1, op2, inplace); } #endif /* !CYTHON_COMPILING_IN_PYPY */ /////////////// PyFloatBinop.proto /////////////// {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} #if !CYTHON_COMPILING_IN_PYPY static {{c_ret_type}} __Pyx_PyFloat_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, int inplace, int zerodivision_check); /*proto*/ #else #define __Pyx_PyFloat_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(op1, op2, floatval, inplace, zerodivision_check) \ {{if op in ('Eq', 'Ne')}}{{'PyObject_RichCompare' if ret_type.is_pyobject else 'PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}) {{elif op == 'Divide'}}((inplace ? __Pyx_PyNumber_InPlaceDivide(op1, op2) : __Pyx_PyNumber_Divide(op1, op2))) {{else}}(inplace ? PyNumber_InPlace{{op}}(op1, op2) : PyNumber_{{op}}(op1, op2)) {{endif}} #endif /////////////// PyFloatBinop /////////////// #if !CYTHON_COMPILING_IN_PYPY {{py: from Cython.Utility import pylong_join }} {{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} {{py: return_true = 'Py_RETURN_TRUE' if ret_type.is_pyobject else 'return 1'}} {{py: return_false = 'Py_RETURN_FALSE' if ret_type.is_pyobject else 'return 0'}} {{py: pyval, fval = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }} {{py: cfunc_name = '__Pyx_PyFloat_%s%s%s' % ('' if ret_type.is_pyobject else 'Bool', op, order) }} {{py: c_op = { 'Add': '+', 'Subtract': '-', 'TrueDivide': '/', 'Divide': '/', 'Remainder': '%', 'Eq': '==', 'Ne': '!=', }[op] }} {{py: def zerodiv_check(operand, _is_mod=op == 'Remainder', _needs_check=(order == 'CObj' and c_op in '%/')): return ((( 'if (unlikely(zerodivision_check && ((%s) == 0.0))) {' ' PyErr_SetString(PyExc_ZeroDivisionError, "float division%s by zero");' ' return NULL;' '}') % (operand, ' or modulo' if _is_mod else '') ) if _needs_check else '') }} static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, double floatval, int inplace, int zerodivision_check) { const double {{'a' if order == 'CObj' else 'b'}} = floatval; double {{fval}}; CYTHON_UNUSED_VAR(inplace); CYTHON_UNUSED_VAR(zerodivision_check); {{if op in ('Eq', 'Ne')}} if (op1 == op2) { {{return_true if op == 'Eq' else return_false}}; } {{endif}} if (likely(PyFloat_CheckExact({{pyval}}))) { {{fval}} = __Pyx_PyFloat_AS_DOUBLE({{pyval}}); {{zerodiv_check(fval)}} } else if (likely(PyLong_CheckExact({{pyval}}))) { #if CYTHON_USE_PYLONG_INTERNALS if (__Pyx_PyLong_IsZero({{pyval}})) { {{fval}} = 0.0; {{zerodiv_check(fval)}} goto digits_done; } else if (__Pyx_PyLong_IsCompact({{pyval}})) { {{fval}} = (double) __Pyx_PyLong_CompactValue({{pyval}}); goto digits_done; } else { const digit* digits = __Pyx_PyLong_Digits({{pyval}}); const Py_ssize_t size = __Pyx_PyLong_DigitCount({{pyval}}); {{for _size in (2, 3, 4)}} if (size <= {{_size}} && (8 * sizeof(unsigned long) > {{_size}} * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || ({{_size-1}} * PyLong_SHIFT < 53)))) { {{fval}} = (double) {{pylong_join(_size, 'digits')}}; // let CPython do its own float rounding from 2**53 on (max. consecutive integer in double float) if ((8 * sizeof(unsigned long) < 53) || ({{_size}} * PyLong_SHIFT < 53) || ({{fval}} < (double) ((PY_LONG_LONG)1 << 53))) { if (__Pyx_PyLong_IsNeg({{pyval}})) {{fval}} = -{{fval}}; goto digits_done; } } // Fall through if size doesn't fit safely into a double anymore. // It may not be obvious that this is a safe fall-through given the "fval < 2**53" // check above. However, the number of digits that CPython uses for a given PyLong // value is minimal, and together with the "(size-1) * SHIFT < 53" check above, // this should make it safe. {{endfor}} } #endif {{if op in ('Eq', 'Ne')}} { PyObject *res = #if CYTHON_USE_TYPE_SLOTS || __PYX_LIMITED_VERSION_HEX >= 0x030A0000 // PyType_GetSlot only works on non-heap types from Python 3.10 __Pyx_PyType_GetSlot((&PyFloat_Type), tp_richcompare, richcmpfunc) #else PyObject_RichCompare #endif ({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}}); return {{if ret_type.is_pyobject}}res{{else}}__Pyx_PyObject_IsTrueAndDecref(res){{endif}}; } {{else}} {{fval}} = PyLong_AsDouble({{pyval}}); if (unlikely({{fval}} == -1.0 && PyErr_Occurred())) return NULL; {{if zerodiv_check(fval)}} #if !CYTHON_USE_PYLONG_INTERNALS {{zerodiv_check(fval)}} #endif {{endif}} {{endif}} } else { {{if op in ('Eq', 'Ne')}} return {{'PyObject_RichCompare' if ret_type.is_pyobject else '__Pyx_PyObject_RichCompareBool'}}(op1, op2, Py_{{op.upper()}}); {{elif op == 'Divide'}} return (inplace ? __Pyx_PyNumber_InPlaceDivide(op1, op2) : __Pyx_PyNumber_Divide(op1, op2)); {{else}} return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2); {{endif}} } #if CYTHON_USE_PYLONG_INTERNALS digits_done:; #endif {{if op in ('Eq', 'Ne')}} if (a {{c_op}} b) { {{return_true}}; } else { {{return_false}}; } {{else}} double result; {{if c_op == '%'}} result = fmod(a, b); if (result) result += ((result < 0) ^ (b < 0)) * b; else result = copysign(0.0, b); {{else}} result = a {{c_op}} b; {{endif}} return PyFloat_FromDouble(result); {{endif}} } #endif