Spaces:
Build error
Build error
/* | |
* 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; | |
} | |
/////////////// ListAppend.proto /////////////// | |
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); | |
PyList_SET_ITEM(list, len, x); | |
__Pyx_SET_SIZE(list, len + 1); | |
return 0; | |
} | |
return PyList_Append(list, x); | |
} | |
/////////////// ListCompAppend.proto /////////////// | |
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); | |
PyList_SET_ITEM(list, len, x); | |
__Pyx_SET_SIZE(list, len + 1); | |
return 0; | |
} | |
return PyList_Append(list, x); | |
} | |
//////////////////// ListExtend.proto //////////////////// | |
static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { | |
PyObject* none = _PyList_Extend((PyListObject*)L, v); | |
if (unlikely(!none)) | |
return -1; | |
Py_DECREF(none); | |
return 0; | |
return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); | |
} | |
/////////////// pop.proto /////////////// | |
static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/ | |
static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L); /*proto*/ | |
/////////////// pop /////////////// | |
//@requires: ObjectHandling.c::PyObjectCallMethod0 | |
static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L) { | |
if (Py_TYPE(L) == &PySet_Type) { | |
return PySet_Pop(L); | |
} | |
return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop")); | |
} | |
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))) { | |
__Pyx_SET_SIZE(L, Py_SIZE(L) - 1); | |
return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); | |
} | |
return CALL_UNBOUND_METHOD(PyList_Type, "pop", L); | |
} | |
/////////////// 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*/ | |
static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t ix); /*proto*/ | |
/////////////// 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); | |
} | |
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); | |
__Pyx_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, PyInt_FromSsize_t(ix)); | |
} else { | |
return __Pyx__PyObject_PopIndex(L, py_ix); | |
} | |
} | |
/////////////// 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; | |
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)); | |
if (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key)) { | |
/* these presumably have safe hash functions */ | |
value = PyDict_GetItem(d, key); | |
if (unlikely(!value)) { | |
value = default_value; | |
} | |
Py_INCREF(value); | |
} | |
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; | |
} | |
/////////////// dict_setdefault.proto /////////////// | |
static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type); /*proto*/ | |
/////////////// dict_setdefault /////////////// | |
static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, | |
CYTHON_UNUSED int is_safe_type) { | |
PyObject* value; | |
// we keep the method call at the end to avoid "unused" C compiler warnings | |
if ((1)) { | |
value = PyDict_SetDefault(d, key, default_value); | |
if (unlikely(!value)) return NULL; | |
Py_INCREF(value); | |
if (is_safe_type == 1 || (is_safe_type == -1 && | |
/* the following builtins presumably have repeatably safe and fast hash functions */ | |
(PyUnicode_CheckExact(key) || PyString_CheckExact(key) || PyLong_CheckExact(key)))) { | |
value = PyDict_GetItemWithError(d, key); | |
if (unlikely(!value)) { | |
if (unlikely(PyErr_Occurred())) | |
return NULL; | |
if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) | |
return NULL; | |
value = default_value; | |
} | |
Py_INCREF(value); | |
(PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key) || PyLong_CheckExact(key)))) { | |
value = PyDict_GetItem(d, key); | |
if (unlikely(!value)) { | |
if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) | |
return NULL; | |
value = default_value; | |
} | |
Py_INCREF(value); | |
} else { | |
value = CALL_UNBOUND_METHOD(PyDict_Type, "setdefault", d, key, default_value); | |
} | |
return value; | |
} | |
/////////////// py_dict_clear.proto /////////////// | |
/////////////// 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 ((1)) { | |
return _PyDict_Pop(d, key, default_value); | |
} else | |
// avoid "function unused" warnings | |
if (default_value) { | |
return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key, default_value); | |
} else { | |
return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key); | |
} | |
} | |
/////////////// 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); | |
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 /////////////// | |
//@requires: ObjectHandling.c::UnpackTuple2 | |
//@requires: ObjectHandling.c::IterFinish | |
//@requires: ObjectHandling.c::PyObjectCallMethod0 | |
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(PyDict_CheckExact(iterable)); | |
*p_source_is_dict = is_dict; | |
if (is_dict) { | |
*p_orig_length = PyDict_Size(iterable); | |
Py_INCREF(iterable); | |
return iterable; | |
// On PyPy3, we need to translate manually a few method names. | |
// This logic is not needed on CPython thanks to the fast case above. | |
static PyObject *py_items = NULL, *py_keys = NULL, *py_values = NULL; | |
PyObject **pp = NULL; | |
if (method_name) { | |
const char *name = PyUnicode_AsUTF8(method_name); | |
if (strcmp(name, "iteritems") == 0) pp = &py_items; | |
else if (strcmp(name, "iterkeys") == 0) pp = &py_keys; | |
else if (strcmp(name, "itervalues") == 0) pp = &py_values; | |
if (pp) { | |
if (!*pp) { | |
*pp = PyUnicode_FromString(name + 4); | |
if (!*pp) | |
return NULL; | |
} | |
method_name = *pp; | |
} | |
} | |
} | |
*p_orig_length = 0; | |
if (method_name) { | |
PyObject* iter; | |
iterable = __Pyx_PyObject_CallMethod0(iterable, method_name); | |
if (!iterable) | |
return NULL; | |
if (PyTuple_CheckExact(iterable) || PyList_CheckExact(iterable)) | |
return iterable; | |
iter = PyObject_GetIter(iterable); | |
Py_DECREF(iterable); | |
return iter; | |
} | |
return PyObject_GetIter(iterable); | |
} | |
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 (source_is_dict) { | |
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); | |
PyTuple_SET_ITEM(tuple, 0, key); | |
PyTuple_SET_ITEM(tuple, 1, value); | |
*pitem = tuple; | |
} else { | |
if (pkey) { | |
Py_INCREF(key); | |
*pkey = key; | |
} | |
if (pvalue) { | |
Py_INCREF(value); | |
*pvalue = value; | |
} | |
} | |
return 1; | |
} else if (PyTuple_CheckExact(iter_obj)) { | |
Py_ssize_t pos = *ppos; | |
if (unlikely(pos >= PyTuple_GET_SIZE(iter_obj))) return 0; | |
*ppos = pos + 1; | |
next_item = PyTuple_GET_ITEM(iter_obj, pos); | |
Py_INCREF(next_item); | |
} else if (PyList_CheckExact(iter_obj)) { | |
Py_ssize_t pos = *ppos; | |
if (unlikely(pos >= PyList_GET_SIZE(iter_obj))) return 0; | |
*ppos = pos + 1; | |
next_item = PyList_GET_ITEM(iter_obj, pos); | |
Py_INCREF(next_item); | |
} else | |
{ | |
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; | |
} | |
/////////////// 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) { | |
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; | |
} | |
(void)is_set; | |
*p_source_is_set = 0; | |
*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 || unlikely(!source_is_set)) { | |
*value = PyIter_Next(iter_obj); | |
if (unlikely(!*value)) { | |
return __Pyx_IterFinish(); | |
} | |
(void)orig_length; | |
(void)ppos; | |
return 1; | |
} | |
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; | |
} | |
} | |
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 (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return -1; | |
*kind = PyUnicode_KIND(ustring); | |
*length = PyUnicode_GET_LENGTH(ustring); | |
*data = PyUnicode_DATA(ustring); | |
*kind = 0; | |
*length = PyUnicode_GET_SIZE(ustring); | |
*data = (void*)PyUnicode_AS_UNICODE(ustring); | |
return 0; | |
} | |
/////////////// pyobject_as_double.proto /////////////// | |
static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */ | |
/////////////// pyobject_as_double /////////////// | |
static double __Pyx__PyObject_AsDouble(PyObject* obj) { | |
PyObject* float_value; | |
float_value = PyNumber_Float(obj); if ((0)) goto bad; | |
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))) { | |
PyErr_Format(PyExc_TypeError, | |
"__float__ returned non-float (type %.200s)", | |
Py_TYPE(float_value)->tp_name); | |
Py_DECREF(float_value); | |
goto bad; | |
} | |
} else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) { | |
float_value = PyFloat_FromString(obj); | |
float_value = PyFloat_FromString(obj, 0); | |
} else { | |
PyObject* args = PyTuple_New(1); | |
if (unlikely(!args)) goto bad; | |
PyTuple_SET_ITEM(args, 0, obj); | |
float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0); | |
PyTuple_SET_ITEM(args, 0, 0); | |
Py_DECREF(args); | |
} | |
if (likely(float_value)) { | |
double value = PyFloat_AS_DOUBLE(float_value); | |
Py_DECREF(float_value); | |
return value; | |
} | |
bad: | |
return (double)-1; | |
} | |
/////////////// PyNumberPow2.proto /////////////// | |
static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject *none, int inplace); /*proto*/ | |
/////////////// PyNumberPow2 /////////////// | |
static PyObject* __Pyx__PyNumber_PowerOf2(PyObject *two, PyObject *exp, PyObject *none, int inplace) { | |
// in CPython, 1<<N is substantially faster than 2**N | |
// see http://bugs.python.org/issue21420 | |
Py_ssize_t shiftby; | |
if (likely(PyInt_CheckExact(exp))) { | |
shiftby = PyInt_AS_LONG(exp); | |
} else | |
if (likely(PyLong_CheckExact(exp))) { | |
const Py_ssize_t size = Py_SIZE(exp); | |
// tuned to optimise branch prediction | |
if (likely(size == 1)) { | |
shiftby = ((PyLongObject*)exp)->ob_digit[0]; | |
} else if (size == 0) { | |
return PyInt_FromLong(1L); | |
} else if (unlikely(size < 0)) { | |
goto fallback; | |
} else { | |
shiftby = PyLong_AsSsize_t(exp); | |
} | |
shiftby = PyLong_AsSsize_t(exp); | |
} else { | |
goto fallback; | |
} | |
if (likely(shiftby >= 0)) { | |
if ((size_t)shiftby <= sizeof(long) * 8 - 2) { | |
long value = 1L << shiftby; | |
return PyInt_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 = PyInt_FromLong(1L); | |
if (unlikely(!one)) return NULL; | |
result = PyNumber_Lshift(one, exp); | |
Py_DECREF(one); | |
return result; | |
} | |
} else if (shiftby == -1 && PyErr_Occurred()) { | |
PyErr_Clear(); | |
} | |
fallback: | |
return (inplace ? PyNumber_InPlacePower : PyNumber_Power)(two, exp, none); | |
} | |
/////////////// PyIntCompare.proto /////////////// | |
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} | |
static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, long inplace); /*proto*/ | |
/////////////// PyIntCompare /////////////// | |
{{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_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED long inplace) { | |
if (op1 == op2) { | |
{{return_true if op == 'Eq' else return_false}}; | |
} | |
if (likely(PyInt_CheckExact({{pyval}}))) { | |
const long {{'a' if order == 'CObj' else 'b'}} = intval; | |
long {{ival}} = PyInt_AS_LONG({{pyval}}); | |
{{return_compare('a', 'b', c_op)}} | |
} | |
if (likely(PyLong_CheckExact({{pyval}}))) { | |
int unequal; | |
unsigned long uintval; | |
Py_ssize_t size = Py_SIZE({{pyval}}); | |
const digit* digits = ((PyLongObject*){{pyval}})->ob_digit; | |
if (intval == 0) { | |
// == 0 => Py_SIZE(pyval) == 0 | |
{{return_compare('size', '0', c_op)}} | |
} else if (intval < 0) { | |
// < 0 => Py_SIZE(pyval) < 0 | |
if (size >= 0) | |
{{return_false if op == 'Eq' else return_true}}; | |
// both are negative => can use absolute values now. | |
intval = -intval; | |
size = -size; | |
} else { | |
// > 0 => Py_SIZE(pyval) > 0 | |
if (size <= 0) | |
{{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 (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 | |
{{endfor}} | |
unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); | |
{{return_compare('unequal', '0', c_op)}} | |
} | |
if (PyFloat_CheckExact({{pyval}})) { | |
const long {{'a' if order == 'CObj' else 'b'}} = intval; | |
double {{ival}} = PyFloat_AS_DOUBLE({{pyval}}); | |
{{return_compare('(double)a', '(double)b', c_op)}} | |
} | |
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}( | |
PyObject_RichCompare(op1, op2, Py_{{op.upper()}})); | |
} | |
/////////////// PyIntBinop.proto /////////////// | |
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} | |
static {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); /*proto*/ | |
CYTHON_FALLTHROUGH; | |
{{endfor}} | |
{{endfor}} | |
{{if op in ('Eq', 'Ne')}} | |
// unusual setup - your fault | |
default: 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()}})); | |
// too large for the long values we allow => definitely not equal | |
default: {{return_false if op == 'Eq' else return_true}}; | |
{{else}} | |
default: return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); | |
{{endif}} | |
} | |
} | |
{{if op in ('Eq', 'Ne')}} | |
if (a {{c_op}} b) { | |
{{return_true}}; | |
} else { | |
{{return_false}}; | |
} | |
{{else}} | |
{{if c_op == '%'}} | |
{{zerodiv_check('b')}} | |
// see ExprNodes.py :: mod_int_utility_code | |
x = a % b; | |
x += ((x != 0) & ((x ^ b) < 0)) * b; | |
{{elif op == 'TrueDivide'}} | |
{{zerodiv_check('b')}} | |
if ((8 * sizeof(long) <= 53 || likely(labs({{ival}}) <= ((PY_LONG_LONG)1 << 53))) | |
|| __Pyx_sst_abs(size) <= 52 / PyLong_SHIFT) { | |
return PyFloat_FromDouble((double)a / (double)b); | |
} | |
return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2); | |
{{elif op == 'FloorDivide'}} | |
{{zerodiv_check('b')}} | |
{ | |
long q, r; | |
// see ExprNodes.py :: div_int_utility_code | |
q = a / b; | |
r = a - q*b; | |
q -= ((r != 0) & ((r ^ b) < 0)); | |
x = q; | |
} | |
{{else}} | |
x = a {{c_op}} b; | |
{{if op == 'Lshift'}} | |
if (unlikely(!(b < (long) (sizeof(long)*8) && a == x >> b)) && a) { | |
ll{{ival}} = {{ival}}; | |
goto long_long; | |
} | |
if (likely(b < (long) (sizeof(long)*8) && a == x >> b) || !a) /* execute return statement below */ | |
{{endif}} | |
{{endif}} | |
return PyLong_FromLong(x); | |
{{if op != 'TrueDivide'}} | |
long_long: | |
{{if c_op == '%'}} | |
// see ExprNodes.py :: mod_int_utility_code | |
llx = lla % llb; | |
llx += ((llx != 0) & ((llx ^ llb) < 0)) * llb; | |
{{elif op == 'FloorDivide'}} | |
{ | |
PY_LONG_LONG q, r; | |
// see ExprNodes.py :: div_int_utility_code | |
q = lla / llb; | |
r = lla - q*llb; | |
q -= ((r != 0) & ((r ^ llb) < 0)); | |
llx = q; | |
} | |
{{else}} | |
llx = lla {{c_op}} llb; | |
{{if op == 'Lshift'}} | |
if (likely(lla == llx >> llb)) /* then execute 'return' below */ | |
{{endif}} | |
{{endif}} | |
return PyLong_FromLongLong(llx); | |
{{endif}}{{ | |
{{endif}}{{ | |
} | |
{{if c_op in '+-' or op in ('TrueDivide', 'Eq', 'Ne')}} | |
if (PyFloat_CheckExact({{pyval}})) { | |
const long {{'a' if order == 'CObj' else 'b'}} = intval; | |
double {{ival}} = PyFloat_AS_DOUBLE({{pyval}}); | |
{{if op in ('Eq', 'Ne')}} | |
if ((double)a {{c_op}} (double)b) { | |
{{return_true}}; | |
} else { | |
{{return_false}}; | |
} | |
{{else}} | |
double result; | |
{{if op == 'TrueDivide'}} | |
if (unlikely(zerodivision_check && b == 0)) { | |
PyErr_SetString(PyExc_ZeroDivisionError, "float division by zero"); | |
return NULL; | |
} | |
{{endif}} | |
// copied from floatobject.c in Py3.5: | |
PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL) | |
result = ((double)a) {{c_op}} (double)b; | |
PyFPE_END_PROTECT(result) | |
return PyFloat_FromDouble(result); | |
{{endif}} | |
} | |
{{endif}} | |
{{if op in ('Eq', 'Ne')}} | |
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}( | |
PyObject_RichCompare(op1, op2, Py_{{op.upper()}})); | |
{{else}} | |
return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2); | |
{{endif}} | |
} | |
/////////////// PyFloatBinop.proto /////////////// | |
{{py: c_ret_type = 'PyObject*' if ret_type.is_pyobject else 'int'}} | |
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*/ | |
// 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. | |
CYTHON_FALLTHROUGH; | |
{{endfor}} | |
default: | |
{ | |
{{if op in ('Eq', 'Ne')}} | |
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}( | |
PyFloat_Type.tp_richcompare({{'op1, op2' if order == 'CObj' else 'op2, op1'}}, Py_{{op.upper()}})); | |
{{else}} | |
{{fval}} = PyLong_AsDouble({{pyval}}); | |
if (unlikely({{fval}} == -1.0 && PyErr_Occurred())) return NULL; | |
{{if order == 'CObj' and c_op in '%/'}}{{zerodiv_check(fval)}}{{endif}} | |
{{endif}} | |
} | |
} else { | |
{{if op in ('Eq', 'Ne')}} | |
return {{'' if ret_type.is_pyobject else '__Pyx_PyObject_IsTrueAndDecref'}}( | |
PyObject_RichCompare(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 op in ('Eq', 'Ne')}} | |
if (a {{c_op}} b) { | |
{{return_true}}; | |
} else { | |
{{return_false}}; | |
} | |
{{else}} | |
// copied from floatobject.c in Py3.5: | |
{{if order == 'CObj' and c_op in '%/'}}{{zerodiv_check('b')}}{{endif}} | |
PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL) | |
{{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}} | |
PyFPE_END_PROTECT(result) | |
return PyFloat_FromDouble(result); | |
{{endif}} | |
} | |