Caffe2 - C++ API
A deep learning, cross platform ML framework
python_numbers.h
1 #pragma once
2 
3 #include <torch/csrc/python_headers.h>
4 #include <cstdint>
5 #include <stdexcept>
6 #include <torch/csrc/Exceptions.h>
7 #include <torch/csrc/utils/tensor_numpy.h>
8 #include <torch/csrc/jit/tracing_state.h>
9 
10 // largest integer that can be represented consecutively in a double
11 const int64_t DOUBLE_INT_MAX = 9007199254740992;
12 
13 inline PyObject* THPUtils_packInt64(int64_t value) {
14 #if PY_MAJOR_VERSION == 2
15  if (sizeof(long) == sizeof(int64_t)) {
16  return PyInt_FromLong(static_cast<long>(value));
17  } else if (value <= INT32_MAX && value >= INT32_MIN) {
18  return PyInt_FromLong(static_cast<long>(value));
19  }
20 #endif
21  return PyLong_FromLongLong(value);
22 }
23 
24 inline PyObject* THPUtils_packUInt64(uint64_t value) {
25 #if PY_MAJOR_VERSION == 2
26  if (value <= INT32_MAX) {
27  return PyInt_FromLong(static_cast<long>(value));
28  }
29 #endif
30  return PyLong_FromUnsignedLongLong(value);
31 }
32 
33 inline PyObject* THPUtils_packDoubleAsInt(double value) {
34 #if PY_MAJOR_VERSION == 2
35  if (value <= INT32_MAX && value >= INT32_MIN) {
36  return PyInt_FromLong(static_cast<long>(value));
37  }
38 #endif
39  return PyLong_FromDouble(value);
40 }
41 
42 inline bool THPUtils_checkLong(PyObject* obj) {
43 #if PY_MAJOR_VERSION == 2
44  return (PyLong_Check(obj) || PyInt_Check(obj)) && !PyBool_Check(obj);
45 #else
46  return PyLong_Check(obj) && !PyBool_Check(obj);
47 #endif
48 }
49 
50 inline int64_t THPUtils_unpackLong(PyObject* obj) {
51  int overflow;
52  long long value = PyLong_AsLongLongAndOverflow(obj, &overflow);
53  if (value == -1 && PyErr_Occurred()) {
54  throw python_error();
55  }
56  if (overflow != 0) {
57  throw std::runtime_error("Overflow when unpacking long");
58  }
59  return (int64_t)value;
60 }
61 
62 inline bool THPUtils_checkIndex(PyObject *obj) {
63  if (PyBool_Check(obj)) {
64  return false;
65  }
66  if (THPUtils_checkLong(obj)) {
67  return true;
68  }
69  torch::jit::tracer::NoWarn no_warn_guard;
70  auto index = THPObjectPtr(PyNumber_Index(obj));
71  if (!index) {
72  PyErr_Clear();
73  return false;
74  }
75  return true;
76 }
77 
78 inline int64_t THPUtils_unpackIndex(PyObject* obj) {
79  if (!THPUtils_checkLong(obj)) {
80  auto index = THPObjectPtr(PyNumber_Index(obj));
81  if (index == nullptr) {
82  throw python_error();
83  }
84  // NB: This needs to be called before `index` goes out of scope and the
85  // underlying object's refcount is decremented
86  return THPUtils_unpackLong(index.get());
87  }
88  return THPUtils_unpackLong(obj);
89 }
90 
91 inline bool THPUtils_checkDouble(PyObject* obj) {
92  bool is_numpy_scalar;
93 #ifdef USE_NUMPY
94  is_numpy_scalar = torch::utils::is_numpy_scalar(obj);
95 #else
96  is_numpy_scalar = false;
97 #endif
98 #if PY_MAJOR_VERSION == 2
99  return PyFloat_Check(obj) || PyLong_Check(obj) || PyInt_Check(obj) || is_numpy_scalar;
100 #else
101  return PyFloat_Check(obj) || PyLong_Check(obj) || is_numpy_scalar;
102 #endif
103 }
104 
105 inline double THPUtils_unpackDouble(PyObject* obj) {
106  if (PyFloat_Check(obj)) {
107  return PyFloat_AS_DOUBLE(obj);
108  }
109  if (PyLong_Check(obj)) {
110  int overflow;
111  long long value = PyLong_AsLongLongAndOverflow(obj, &overflow);
112  if (overflow != 0) {
113  throw std::runtime_error("Overflow when unpacking double");
114  }
115  if (value > DOUBLE_INT_MAX || value < -DOUBLE_INT_MAX) {
116  throw std::runtime_error("Precision loss when unpacking double");
117  }
118  return (double)value;
119  }
120 #if PY_MAJOR_VERSION == 2
121  if (PyInt_Check(obj)) {
122  return (double)PyInt_AS_LONG(obj);
123  }
124 #endif
125  double value = PyFloat_AsDouble(obj);
126  if (value == -1 && PyErr_Occurred()) {
127  throw python_error();
128  }
129  return value;
130 }
131 
132 inline std::complex<double> THPUtils_unpackComplexDouble(PyObject *obj) {
133  Py_complex value = PyComplex_AsCComplex(obj);
134  if (value.real == -1.0 && PyErr_Occurred()) {
135  throw python_error();
136  }
137 
138  return std::complex<double>(value.real, value.imag);
139 }