/* Add Python 3.x PyLong_AsLongAndOverflow to Python 2.x. */


/* Get a C long int from a long int object.
   Returns -1 and sets an error condition if overflow occurs. */

#define PY_ABS_LONG_MIN		(0-(unsigned long)LONG_MIN)

#if (PY_VERSION_HEX < 0x02070000)
typedef short sdigit;
#endif

long
PyIntOrLong_AsLongAndOverflow(PyObject *vv, int *overflow)
{
	/* This version by Tim Peters */
	register PyLongObject *v;
	unsigned long x, prev;
	long res;
	Py_ssize_t i;
	int sign;
	int do_decref = 0; /* if nb_int was called */

	*overflow = 0;
	if (vv == NULL) {
		PyErr_BadInternalCall();
		return -1;
	}

    if(PyInt_Check(vv))
        return PyInt_AS_LONG((PyIntObject*) vv);

	if (!PyLong_Check(vv)) {
		PyNumberMethods *nb;
		if ((nb = vv->ob_type->tp_as_number) == NULL ||
		    nb->nb_int == NULL) {
			PyErr_SetString(PyExc_TypeError, "an integer is required");
			return -1;
		}
		vv = (*nb->nb_int) (vv);
		if (vv == NULL)
			return -1;
		do_decref = 1;
        if(PyInt_Check(vv)) {
            res = PyInt_AS_LONG((PyIntObject*) vv);
            goto exit;
        }
		if (!PyLong_Check(vv)) {
			Py_DECREF(vv);
			PyErr_SetString(PyExc_TypeError,
					"nb_int should return int object");
			return -1;
		}
	}

	res = -1;
	v = (PyLongObject *)vv;
	i = Py_SIZE(v);

	switch (i) {
	case -1:
		res = -(sdigit)v->ob_digit[0];
		break;
	case 0:
		res = 0;
		break;
	case 1:
		res = v->ob_digit[0];
		break;
	default:
		sign = 1;
		x = 0;
		if (i < 0) {
			sign = -1;
			i = -(i);
		}
		while (--i >= 0) {
			prev = x;
			x = (x << PyLong_SHIFT) + v->ob_digit[i];
			if ((x >> PyLong_SHIFT) != prev) {
				*overflow = Py_SIZE(v) > 0 ? 1 : -1;
				goto exit;
			}
		}
		/* Haven't lost any bits, but casting to long requires extra care
		 * (see comment above).
	         */
		if (x <= (unsigned long)LONG_MAX) {
			res = (long)x * sign;
		}
		else if (sign < 0 && x == PY_ABS_LONG_MIN) {
			res = LONG_MIN;
		}
		else {
			*overflow = Py_SIZE(v) > 0 ? 1 : -1;
			/* res is already set to -1 */
		}
	}
 exit:
	if (do_decref) {
		Py_DECREF(vv);
	}
	return res;
}

#define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op))
