1 #pragma once 2 3 #include <c10/core/Device.h> 4 #include <torch/csrc/Exceptions.h> 5 #include <torch/csrc/jit/frontend/tracer.h> 6 #include <torch/csrc/python_headers.h> 7 #include <torch/csrc/utils/object_ptr.h> 8 #include <torch/csrc/utils/tensor_numpy.h> 9 #include <cstdint> 10 #include <limits> 11 #include <stdexcept> 12 13 // largest integer that can be represented consecutively in a double 14 const int64_t DOUBLE_INT_MAX = 9007199254740992; 15 THPUtils_packDeviceIndex(c10::DeviceIndex value)16inline PyObject* THPUtils_packDeviceIndex(c10::DeviceIndex value) { 17 return PyLong_FromLong(value); 18 } 19 THPUtils_packInt32(int32_t value)20inline PyObject* THPUtils_packInt32(int32_t value) { 21 return PyLong_FromLong(value); 22 } 23 THPUtils_packInt64(int64_t value)24inline PyObject* THPUtils_packInt64(int64_t value) { 25 return PyLong_FromLongLong(value); 26 } 27 THPUtils_packUInt32(uint32_t value)28inline PyObject* THPUtils_packUInt32(uint32_t value) { 29 return PyLong_FromUnsignedLong(value); 30 } 31 THPUtils_packUInt64(uint64_t value)32inline PyObject* THPUtils_packUInt64(uint64_t value) { 33 return PyLong_FromUnsignedLongLong(value); 34 } 35 THPUtils_packDoubleAsInt(double value)36inline PyObject* THPUtils_packDoubleAsInt(double value) { 37 return PyLong_FromDouble(value); 38 } 39 THPUtils_checkLongExact(PyObject * obj)40inline bool THPUtils_checkLongExact(PyObject* obj) { 41 return PyLong_CheckExact(obj) && !PyBool_Check(obj); 42 } 43 THPUtils_checkLong(PyObject * obj)44inline bool THPUtils_checkLong(PyObject* obj) { 45 // Fast path 46 if (THPUtils_checkLongExact(obj)) { 47 return true; 48 } 49 50 #ifdef USE_NUMPY 51 if (torch::utils::is_numpy_int(obj)) { 52 return true; 53 } 54 #endif 55 56 return PyLong_Check(obj) && !PyBool_Check(obj); 57 } 58 THPUtils_unpackInt(PyObject * obj)59inline int32_t THPUtils_unpackInt(PyObject* obj) { 60 int overflow = 0; 61 long value = PyLong_AsLongAndOverflow(obj, &overflow); 62 if (value == -1 && PyErr_Occurred()) { 63 throw python_error(); 64 } 65 if (overflow != 0) { 66 throw std::runtime_error("Overflow when unpacking long"); 67 } 68 if (value > std::numeric_limits<int32_t>::max() || 69 value < std::numeric_limits<int32_t>::min()) { 70 throw std::runtime_error("Overflow when unpacking long"); 71 } 72 return (int32_t)value; 73 } 74 THPUtils_unpackLong(PyObject * obj)75inline int64_t THPUtils_unpackLong(PyObject* obj) { 76 int overflow = 0; 77 long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); 78 if (value == -1 && PyErr_Occurred()) { 79 throw python_error(); 80 } 81 if (overflow != 0) { 82 throw std::runtime_error("Overflow when unpacking long"); 83 } 84 return (int64_t)value; 85 } 86 THPUtils_unpackUInt32(PyObject * obj)87inline uint32_t THPUtils_unpackUInt32(PyObject* obj) { 88 unsigned long value = PyLong_AsUnsignedLong(obj); 89 if (PyErr_Occurred()) { 90 throw python_error(); 91 } 92 if (value > std::numeric_limits<uint32_t>::max()) { 93 throw std::runtime_error("Overflow when unpacking unsigned long"); 94 } 95 return (uint32_t)value; 96 } 97 THPUtils_unpackUInt64(PyObject * obj)98inline uint64_t THPUtils_unpackUInt64(PyObject* obj) { 99 unsigned long long value = PyLong_AsUnsignedLongLong(obj); 100 if (PyErr_Occurred()) { 101 throw python_error(); 102 } 103 return (uint64_t)value; 104 } 105 106 bool THPUtils_checkIndex(PyObject* obj); 107 THPUtils_unpackIndex(PyObject * obj)108inline int64_t THPUtils_unpackIndex(PyObject* obj) { 109 if (!THPUtils_checkLong(obj)) { 110 auto index = THPObjectPtr(PyNumber_Index(obj)); 111 if (index == nullptr) { 112 throw python_error(); 113 } 114 // NB: This needs to be called before `index` goes out of scope and the 115 // underlying object's refcount is decremented 116 return THPUtils_unpackLong(index.get()); 117 } 118 return THPUtils_unpackLong(obj); 119 } 120 THPUtils_unpackBool(PyObject * obj)121inline bool THPUtils_unpackBool(PyObject* obj) { 122 if (obj == Py_True) { 123 return true; 124 } else if (obj == Py_False) { 125 return false; 126 } else { 127 throw std::runtime_error("couldn't convert python object to boolean"); 128 } 129 } 130 THPUtils_checkBool(PyObject * obj)131inline bool THPUtils_checkBool(PyObject* obj) { 132 #ifdef USE_NUMPY 133 if (torch::utils::is_numpy_bool(obj)) { 134 return true; 135 } 136 #endif 137 return PyBool_Check(obj); 138 } 139 THPUtils_checkDouble(PyObject * obj)140inline bool THPUtils_checkDouble(PyObject* obj) { 141 #ifdef USE_NUMPY 142 if (torch::utils::is_numpy_scalar(obj)) { 143 return true; 144 } 145 #endif 146 return PyFloat_Check(obj) || PyLong_Check(obj); 147 } 148 THPUtils_unpackDouble(PyObject * obj)149inline double THPUtils_unpackDouble(PyObject* obj) { 150 if (PyFloat_Check(obj)) { 151 return PyFloat_AS_DOUBLE(obj); 152 } 153 double value = PyFloat_AsDouble(obj); 154 if (value == -1 && PyErr_Occurred()) { 155 throw python_error(); 156 } 157 return value; 158 } 159 THPUtils_unpackComplexDouble(PyObject * obj)160inline c10::complex<double> THPUtils_unpackComplexDouble(PyObject* obj) { 161 Py_complex value = PyComplex_AsCComplex(obj); 162 if (value.real == -1.0 && PyErr_Occurred()) { 163 throw python_error(); 164 } 165 166 return c10::complex<double>(value.real, value.imag); 167 } 168 THPUtils_unpackNumberAsBool(PyObject * obj)169inline bool THPUtils_unpackNumberAsBool(PyObject* obj) { 170 if (PyFloat_Check(obj)) { 171 return (bool)PyFloat_AS_DOUBLE(obj); 172 } 173 174 if (PyComplex_Check(obj)) { 175 double real_val = PyComplex_RealAsDouble(obj); 176 double imag_val = PyComplex_ImagAsDouble(obj); 177 return !(real_val == 0 && imag_val == 0); 178 } 179 180 // NOLINTNEXTLINE(cppcoreguidelines-init-variables) 181 int overflow; 182 long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); 183 if (value == -1 && PyErr_Occurred()) { 184 throw python_error(); 185 } 186 // No need to check overflow, because when overflow occured, it should 187 // return true in order to keep the same behavior of numpy. 188 return (bool)value; 189 } 190 THPUtils_unpackDeviceIndex(PyObject * obj)191inline c10::DeviceIndex THPUtils_unpackDeviceIndex(PyObject* obj) { 192 int overflow = 0; 193 long value = PyLong_AsLongAndOverflow(obj, &overflow); 194 if (value == -1 && PyErr_Occurred()) { 195 throw python_error(); 196 } 197 if (overflow != 0) { 198 throw std::runtime_error("Overflow when unpacking DeviceIndex"); 199 } 200 if (value > std::numeric_limits<c10::DeviceIndex>::max() || 201 value < std::numeric_limits<c10::DeviceIndex>::min()) { 202 throw std::runtime_error("Overflow when unpacking DeviceIndex"); 203 } 204 return (c10::DeviceIndex)value; 205 } 206