#pragma once #include #include #include #include #include #include #include #include #include // largest integer that can be represented consecutively in a double const int64_t DOUBLE_INT_MAX = 9007199254740992; inline PyObject* THPUtils_packDeviceIndex(c10::DeviceIndex value) { return PyLong_FromLong(value); } inline PyObject* THPUtils_packInt32(int32_t value) { return PyLong_FromLong(value); } inline PyObject* THPUtils_packInt64(int64_t value) { return PyLong_FromLongLong(value); } inline PyObject* THPUtils_packUInt32(uint32_t value) { return PyLong_FromUnsignedLong(value); } inline PyObject* THPUtils_packUInt64(uint64_t value) { return PyLong_FromUnsignedLongLong(value); } inline PyObject* THPUtils_packDoubleAsInt(double value) { return PyLong_FromDouble(value); } inline bool THPUtils_checkLongExact(PyObject* obj) { return PyLong_CheckExact(obj) && !PyBool_Check(obj); } inline bool THPUtils_checkLong(PyObject* obj) { // Fast path if (THPUtils_checkLongExact(obj)) { return true; } #ifdef USE_NUMPY if (torch::utils::is_numpy_int(obj)) { return true; } #endif return PyLong_Check(obj) && !PyBool_Check(obj); } inline int32_t THPUtils_unpackInt(PyObject* obj) { int overflow = 0; long value = PyLong_AsLongAndOverflow(obj, &overflow); if (value == -1 && PyErr_Occurred()) { throw python_error(); } if (overflow != 0) { throw std::runtime_error("Overflow when unpacking long"); } if (value > std::numeric_limits::max() || value < std::numeric_limits::min()) { throw std::runtime_error("Overflow when unpacking long"); } return (int32_t)value; } inline int64_t THPUtils_unpackLong(PyObject* obj) { int overflow = 0; long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); if (value == -1 && PyErr_Occurred()) { throw python_error(); } if (overflow != 0) { throw std::runtime_error("Overflow when unpacking long"); } return (int64_t)value; } inline uint32_t THPUtils_unpackUInt32(PyObject* obj) { unsigned long value = PyLong_AsUnsignedLong(obj); if (PyErr_Occurred()) { throw python_error(); } if (value > std::numeric_limits::max()) { throw std::runtime_error("Overflow when unpacking unsigned long"); } return (uint32_t)value; } inline uint64_t THPUtils_unpackUInt64(PyObject* obj) { unsigned long long value = PyLong_AsUnsignedLongLong(obj); if (PyErr_Occurred()) { throw python_error(); } return (uint64_t)value; } bool THPUtils_checkIndex(PyObject* obj); inline int64_t THPUtils_unpackIndex(PyObject* obj) { if (!THPUtils_checkLong(obj)) { auto index = THPObjectPtr(PyNumber_Index(obj)); if (index == nullptr) { throw python_error(); } // NB: This needs to be called before `index` goes out of scope and the // underlying object's refcount is decremented return THPUtils_unpackLong(index.get()); } return THPUtils_unpackLong(obj); } inline bool THPUtils_unpackBool(PyObject* obj) { if (obj == Py_True) { return true; } else if (obj == Py_False) { return false; } else { throw std::runtime_error("couldn't convert python object to boolean"); } } inline bool THPUtils_checkBool(PyObject* obj) { #ifdef USE_NUMPY if (torch::utils::is_numpy_bool(obj)) { return true; } #endif return PyBool_Check(obj); } inline bool THPUtils_checkDouble(PyObject* obj) { #ifdef USE_NUMPY if (torch::utils::is_numpy_scalar(obj)) { return true; } #endif return PyFloat_Check(obj) || PyLong_Check(obj); } inline double THPUtils_unpackDouble(PyObject* obj) { if (PyFloat_Check(obj)) { return PyFloat_AS_DOUBLE(obj); } double value = PyFloat_AsDouble(obj); if (value == -1 && PyErr_Occurred()) { throw python_error(); } return value; } inline c10::complex THPUtils_unpackComplexDouble(PyObject* obj) { Py_complex value = PyComplex_AsCComplex(obj); if (value.real == -1.0 && PyErr_Occurred()) { throw python_error(); } return c10::complex(value.real, value.imag); } inline bool THPUtils_unpackNumberAsBool(PyObject* obj) { if (PyFloat_Check(obj)) { return (bool)PyFloat_AS_DOUBLE(obj); } if (PyComplex_Check(obj)) { double real_val = PyComplex_RealAsDouble(obj); double imag_val = PyComplex_ImagAsDouble(obj); return !(real_val == 0 && imag_val == 0); } int overflow = 0; long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); if (value == -1 && PyErr_Occurred()) { throw python_error(); } // No need to check overflow, because when overflow occured, it should // return true in order to keep the same behavior of numpy. return (bool)value; } inline c10::DeviceIndex THPUtils_unpackDeviceIndex(PyObject* obj) { int overflow = 0; long value = PyLong_AsLongAndOverflow(obj, &overflow); if (value == -1 && PyErr_Occurred()) { throw python_error(); } if (overflow != 0) { throw std::runtime_error("Overflow when unpacking DeviceIndex"); } if (value > std::numeric_limits::max() || value < std::numeric_limits::min()) { throw std::runtime_error("Overflow when unpacking DeviceIndex"); } return (c10::DeviceIndex)value; }