/*
 * 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 ///////////////

#if CYTHON_COMPILING_IN_CPYTHON
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);
        Py_SIZE(list) = len+1;
        return 0;
    }
    return PyList_Append(list, x);
}
#else
#define __Pyx_PyList_Append(L,x) PyList_Append(L,x)
#endif

/////////////// ListCompAppend.proto ///////////////

#if CYTHON_COMPILING_IN_CPYTHON
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);
        Py_SIZE(list) = len+1;
        return 0;
    }
    return PyList_Append(list, x);
}
#else
#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x)
#endif

//////////////////// ListExtend.proto ////////////////////

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
}

/////////////// pop.proto ///////////////

static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/

#if CYTHON_COMPILING_IN_CPYTHON
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 CYTHON_COMPILING_IN_CPYTHON
    if (Py_TYPE(L) == &PySet_Type) {
        return PySet_Pop(L);
    }
#endif
    return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop"));
}

#if CYTHON_COMPILING_IN_CPYTHON
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_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_COMPILING_IN_CPYTHON
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_COMPILING_IN_CPYTHON
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(0 <= cix && cix < size)) {
            PyObject* v = PyList_GET_ITEM(L, cix);
            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);
    }
}
#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 PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
    value = PyDict_GetItemWithError(d, key);
    if (unlikely(!value)) {
        if (unlikely(PyErr_Occurred()))
            return NULL;
        value = default_value;
    }
    Py_INCREF(value);
#else
    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)
            default_value = NULL;
        value = PyObject_CallMethodObjArgs(
            d, PYIDENT("get"), key, default_value, NULL);
    }
#endif
    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 ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod2

static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value,
                                                       CYTHON_UNUSED int is_safe_type) {
    PyObject* value;
#if PY_VERSION_HEX >= 0x030400A0
    // 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);
#else
    if (is_safe_type == 1 || (is_safe_type == -1 &&
        /* the following builtins presumably have repeatably safe and fast hash functions */
#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
            (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);
#else
            (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);
#endif
#endif
    } else {
        value = __Pyx_PyObject_CallMethod2(d, PYIDENT("setdefault"), key, default_value);
    }
    return value;
}


/////////////// py_dict_clear.proto ///////////////

#define __Pyx_PyDict_Clear(d) (PyDict_Clear(d), 0)

/////////////// 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 !CYTHON_COMPILING_IN_PYPY
    if (is_dict) {
        *p_orig_length = PyDict_Size(iterable);
        Py_INCREF(iterable);
        return iterable;
    }
#endif
    *p_orig_length = 0;
    if (method_name) {
        PyObject* iter;
        iterable = __Pyx_PyObject_CallMethod0(iterable, method_name);
        if (!iterable)
            return NULL;
#if !CYTHON_COMPILING_IN_PYPY
        if (PyTuple_CheckExact(iterable) || PyList_CheckExact(iterable))
            return iterable;
#endif
        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 !CYTHON_COMPILING_IN_PYPY
    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
#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;
}


/////////////// 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_PEP393_ENABLED
    if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return -1;
    *kind   = PyUnicode_KIND(ustring);
    *length = PyUnicode_GET_LENGTH(ustring);
    *data   = PyUnicode_DATA(ustring);
#else
    *kind   = 0;
    *length = PyUnicode_GET_SIZE(ustring);
    *data   = (void*)PyUnicode_AS_UNICODE(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(PyInt_CheckExact(obj)) ? \
 PyFloat_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj))
#else
#define __Pyx_PyObject_AsDouble(obj) \
((likely(PyFloat_CheckExact(obj))) ? \
 PyFloat_AS_DOUBLE(obj) : __Pyx__PyObject_AsDouble(obj))
#endif

/////////////// pyobject_as_double ///////////////

static double __Pyx__PyObject_AsDouble(PyObject* obj) {
    PyObject* float_value;
#if CYTHON_COMPILING_IN_PYPY
    float_value = PyNumber_Float(obj);  if (0) goto bad;
#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))) {
            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)) {
#if PY_MAJOR_VERSION >= 3
        float_value = PyFloat_FromString(obj);
#else
        float_value = PyFloat_FromString(obj, 0);
#endif
    } 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);
    }
#endif
    if (likely(float_value)) {
        double value = PyFloat_AS_DOUBLE(float_value);
        Py_DECREF(float_value);
        return value;
    }
bad:
    return (double)-1;
}


/////////////// 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 ///////////////

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
#if CYTHON_COMPILING_IN_CPYTHON
    Py_ssize_t shiftby;
#if PY_MAJOR_VERSION < 3
    if (likely(PyInt_CheckExact(exp))) {
        shiftby = PyInt_AS_LONG(exp);
    } else
#endif
    if (likely(PyLong_CheckExact(exp))) {
        #if CYTHON_USE_PYLONG_INTERNALS
        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);
        }
        #else
        shiftby = PyLong_AsSsize_t(exp);
        #endif
    } 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 *one = PyInt_FromLong(1L);
            if (unlikely(!one)) return NULL;
            return PyNumber_Lshift(one, exp);
        }
    } else if (shiftby == -1 && PyErr_Occurred()) {
        PyErr_Clear();
    }
fallback:
#endif
    return (inplace ? PyNumber_InPlacePower : PyNumber_Power)(two, exp, none);
}


/////////////// PyIntBinop.proto ///////////////

#if CYTHON_COMPILING_IN_CPYTHON
static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long intval, int inplace); /*proto*/
#else
#define __Pyx_PyInt_{{op}}{{order}}(op1, op2, intval, inplace) \
    {{if op in ('Eq', 'Ne')}}PyObject_RichCompare(op1, op2, Py_{{op.upper()}})
    {{else}}(inplace ? PyNumber_InPlace{{op}}(op1, op2) : PyNumber_{{op}}(op1, op2))
    {{endif}}
#endif

/////////////// PyIntBinop ///////////////

#if CYTHON_COMPILING_IN_CPYTHON
{{py: from Cython.Utility import pylong_join }}
{{py: pyval, ival = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py: slot_name = {'TrueDivide': 'true_divide', 'FloorDivide': 'floor_divide'}.get(op, op.lower()) }}
{{py:
c_op = {
    'Add': '+', 'Subtract': '-', 'Remainder': '%', 'TrueDivide': '/', 'FloorDivide': '/',
    'Or': '|', 'Xor': '^', 'And': '&', 'Rshift': '>>',
    'Eq': '==', 'Ne': '!=',
    }[op]
}}

static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
    {{if op in ('Eq', 'Ne')}}
    if (op1 == op2) {
        Py_RETURN_{{'TRUE' if op == 'Eq' else 'FALSE'}};
    }
    {{endif}}

    #if PY_MAJOR_VERSION < 3
    if (likely(PyInt_CheckExact({{pyval}}))) {
        const long {{'a' if order == 'CObj' else 'b'}} = intval;
        {{if c_op in '+-%' or op == 'FloorDivide'}}
        long x;
        {{endif}}
        long {{ival}} = PyInt_AS_LONG({{pyval}});

        {{if op in ('Eq', 'Ne')}}
        if (a {{c_op}} b) {
            Py_RETURN_TRUE;
        } else {
            Py_RETURN_FALSE;
        }
        {{elif c_op in '+-'}}
            // adapted from intobject.c in Py2.7:
            // casts in the line below avoid undefined behaviour on overflow
            x = (long)((unsigned long)a {{c_op}} b);
            if (likely((x^a) >= 0 || (x^{{ '~' if op == 'Subtract' else '' }}b) >= 0))
                return PyInt_FromLong(x);
            return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
        {{elif c_op == '%'}}
            // see ExprNodes.py :: mod_int_utility_code
            x = a % b;
            x += ((x != 0) & ((x ^ b) < 0)) * b;
            return PyInt_FromLong(x);
        {{elif op == 'TrueDivide'}}
            if (8 * sizeof(long) <= 53 || likely(labs({{ival}}) <= (1L << 53))) {
                return PyFloat_FromDouble((double)a / (double)b);
            }
            // let Python do the rounding
            return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
        {{elif op == 'FloorDivide'}}
            // INT_MIN / -1  is the only case that overflows
            if (unlikely(b == -1 && ((unsigned long)a) == 0-(unsigned long)a))
                return PyInt_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
            else {
                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;
            }
            return PyInt_FromLong(x);
        {{else}}
            // other operations are safe, no overflow
            return PyInt_FromLong(a {{c_op}} b);
        {{endif}}
    }
    #endif

    #if CYTHON_USE_PYLONG_INTERNALS && PY_MAJOR_VERSION >= 3
    if (likely(PyLong_CheckExact({{pyval}}))) {
        const long {{'a' if order == 'CObj' else 'b'}} = intval;
        long {{ival}}{{if op not in ('Eq', 'Ne')}}, x{{endif}};
        {{if op not in ('Eq', 'Ne', 'TrueDivide')}}
        const PY_LONG_LONG ll{{'a' if order == 'CObj' else 'b'}} = intval;
        PY_LONG_LONG ll{{ival}}, llx;
        {{endif}}
        const digit* digits = ((PyLongObject*){{pyval}})->ob_digit;
        const Py_ssize_t size = Py_SIZE({{pyval}});
        // handle most common case first to avoid indirect branch and optimise branch prediction
        if (likely(__Pyx_sst_abs(size) <= 1)) {
            {{ival}} = likely(size) ? digits[0] : 0;
            if (size == -1) {{ival}} = -{{ival}};
        } else {
            switch (size) {
                {{for _size in range(2, 5)}}
                {{for _case in (-_size, _size)}}
                case {{_case}}:
                    if (8 * sizeof(long) - 1 > {{_size}} * PyLong_SHIFT{{if op == 'TrueDivide'}} && {{_size-1}} * PyLong_SHIFT < 53{{endif}}) {
                        {{ival}} = {{'-' if _case < 0 else ''}}(long) {{pylong_join(_size, 'digits')}};
                        break;
                    {{if op not in ('Eq', 'Ne', 'TrueDivide')}}
                    } else if (8 * sizeof(PY_LONG_LONG) - 1 > {{_size}} * PyLong_SHIFT) {
                        ll{{ival}} = {{'-' if _case < 0 else ''}}(PY_LONG_LONG) {{pylong_join(_size, 'digits', 'unsigned PY_LONG_LONG')}};
                        goto long_long;
                    {{endif}}
                    }
                    // if size doesn't fit into a long or PY_LONG_LONG anymore, fall through to default
                {{endfor}}
                {{endfor}}

                {{if op in ('Eq', 'Ne')}}
                #if PyLong_SHIFT < 30 && PyLong_SHIFT != 15
                // unusual setup - your fault
                default: return 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
                default: Py_RETURN_{{'FALSE' if op == 'Eq' else 'TRUE'}};
                #endif
                {{else}}
                default: return PyLong_Type.tp_as_number->nb_{{slot_name}}(op1, op2);
                {{endif}}
            }
        }
        {{if op in ('Eq', 'Ne')}}
            if (a {{c_op}} b) {
                Py_RETURN_TRUE;
            } else {
                Py_RETURN_FALSE;
            }
        {{else}}
            {{if c_op == '%'}}
                // see ExprNodes.py :: mod_int_utility_code
                x = a % b;
                x += ((x != 0) & ((x ^ b) < 0)) * b;
            {{elif op == 'TrueDivide'}}
                if ((8 * sizeof(long) <= 53 || likely(labs({{ival}}) <= (1L << 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'}}
                {
                    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;
            {{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;
            {{endif}}
            return PyLong_FromLongLong(llx);
        {{endif}}
        {{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) {
                Py_RETURN_TRUE;
            } else {
                Py_RETURN_FALSE;
            }
        {{else}}
            double result;
            // 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 PyObject_RichCompare(op1, op2, Py_{{op.upper()}});
    {{else}}
    return (inplace ? PyNumber_InPlace{{op}} : PyNumber_{{op}})(op1, op2);
    {{endif}}
}
#endif

/////////////// PyFloatBinop.proto ///////////////

#if CYTHON_COMPILING_IN_CPYTHON
static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, int inplace); /*proto*/
#else
#define __Pyx_PyFloat_{{op}}{{order}}(op1, op2, floatval, inplace) \
    {{if op in ('Eq', 'Ne')}}PyObject_RichCompare(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_CPYTHON
{{py: from Cython.Utility import pylong_join }}
{{py: pyval, fval = ('op2', 'b') if order == 'CObj' else ('op1', 'a') }}
{{py:
c_op = {
    'Add': '+', 'Subtract': '-', 'TrueDivide': '/', 'Divide': '/', 'Remainder': '%',
    'Eq': '==', 'Ne': '!=',
    }[op]
}}

static PyObject* __Pyx_PyFloat_{{op}}{{order}}(PyObject *op1, PyObject *op2, double floatval, CYTHON_UNUSED int inplace) {
    const double {{'a' if order == 'CObj' else 'b'}} = floatval;
    double {{fval}}{{if op not in ('Eq', 'Ne')}}, result{{endif}};

    {{if op in ('Eq', 'Ne')}}
    if (op1 == op2) {
        Py_RETURN_{{'TRUE' if op == 'Eq' else 'FALSE'}};
    }
    {{endif}}

    if (likely(PyFloat_CheckExact({{pyval}}))) {
        {{fval}} = PyFloat_AS_DOUBLE({{pyval}});
    } else

    #if PY_MAJOR_VERSION < 3
    if (likely(PyInt_CheckExact({{pyval}}))) {
        {{fval}} = (double) PyInt_AS_LONG({{pyval}});
    } else
    #endif

    if (likely(PyLong_CheckExact({{pyval}}))) {
        #if CYTHON_USE_PYLONG_INTERNALS && PY_MAJOR_VERSION >= 3
        const digit* digits = ((PyLongObject*){{pyval}})->ob_digit;
        const Py_ssize_t size = Py_SIZE({{pyval}});
        switch (size) {
            case  0: {{fval}} = 0.0; break;
            case -1: {{fval}} = -(double) digits[0]; break;
            case  1: {{fval}} = (double) digits[0]; break;
            {{for _size in (2, 3, 4)}}
            case -{{_size}}:
            case {{_size}}:
                if (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) (1L<<53))) {
                        if (size == {{-_size}})
                            {{fval}} = -{{fval}};
                        break;
                    }
                }
                // 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}}
            default:
        #else
        {
        #endif
        {{if op in ('Eq', 'Ne')}}
            return 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;
        {{endif}}
        }
    } else {
        {{if op in ('Eq', 'Ne')}}
        return 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) {
            Py_RETURN_TRUE;
        } else {
            Py_RETURN_FALSE;
        }
    {{else}}
        // copied from floatobject.c in Py3.5:
        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}}
}
#endif