| File: | .cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow/tensorflow/python/lib/core/ndarray_tensor.cc | 
| Warning: | line 90, column 47 PyObject ownership leak with reference count of 1  | 
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. | |||
| 2 | ||||
| 3 | Licensed under the Apache License, Version 2.0 (the "License"); | |||
| 4 | you may not use this file except in compliance with the License. | |||
| 5 | You may obtain a copy of the License at | |||
| 6 | ||||
| 7 | http://www.apache.org/licenses/LICENSE-2.0 | |||
| 8 | ||||
| 9 | Unless required by applicable law or agreed to in writing, software | |||
| 10 | distributed under the License is distributed on an "AS IS" BASIS, | |||
| 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| 12 | See the License for the specific language governing permissions and | |||
| 13 | limitations under the License. | |||
| 14 | ==============================================================================*/ | |||
| 15 | ||||
| 16 | #include "tensorflow/python/lib/core/ndarray_tensor.h" | |||
| 17 | ||||
| 18 | #include <cstring> | |||
| 19 | #include <optional> | |||
| 20 | ||||
| 21 | #include "tensorflow/c/eager/tfe_context_internal.h" | |||
| 22 | #include "tensorflow/c/tf_tensor_internal.h" | |||
| 23 | #include "tensorflow/core/lib/core/coding.h" | |||
| 24 | #include "tensorflow/core/lib/core/errors.h" | |||
| 25 | #include "tensorflow/core/lib/gtl/inlined_vector.h" | |||
| 26 | #include "tensorflow/core/platform/types.h" | |||
| 27 | #include "tensorflow/python/lib/core/bfloat16.h" | |||
| 28 | #include "tensorflow/python/lib/core/ndarray_tensor_bridge.h" | |||
| 29 | #include "tensorflow/python/lib/core/numpy.h" | |||
| 30 | ||||
| 31 | namespace tensorflow { | |||
| 32 | namespace { | |||
| 33 | ||||
| 34 | char const* numpy_type_name(int numpy_type) { | |||
| 35 | switch (numpy_type) { | |||
| 36 | #define TYPE_CASE(s)case s: return "s" \ | |||
| 37 | case s: \ | |||
| 38 | return #s | |||
| 39 | ||||
| 40 | TYPE_CASE(NPY_BOOL)case NPY_BOOL: return "NPY_BOOL"; | |||
| 41 | TYPE_CASE(NPY_BYTE)case NPY_BYTE: return "NPY_BYTE"; | |||
| 42 | TYPE_CASE(NPY_UBYTE)case NPY_UBYTE: return "NPY_UBYTE"; | |||
| 43 | TYPE_CASE(NPY_SHORT)case NPY_SHORT: return "NPY_SHORT"; | |||
| 44 | TYPE_CASE(NPY_USHORT)case NPY_USHORT: return "NPY_USHORT"; | |||
| 45 | TYPE_CASE(NPY_INT)case NPY_INT: return "NPY_INT"; | |||
| 46 | TYPE_CASE(NPY_UINT)case NPY_UINT: return "NPY_UINT"; | |||
| 47 | TYPE_CASE(NPY_LONG)case NPY_LONG: return "NPY_LONG"; | |||
| 48 | TYPE_CASE(NPY_ULONG)case NPY_ULONG: return "NPY_ULONG"; | |||
| 49 | TYPE_CASE(NPY_LONGLONG)case NPY_LONGLONG: return "NPY_LONGLONG"; | |||
| 50 | TYPE_CASE(NPY_ULONGLONG)case NPY_ULONGLONG: return "NPY_ULONGLONG"; | |||
| 51 | TYPE_CASE(NPY_FLOAT)case NPY_FLOAT: return "NPY_FLOAT"; | |||
| 52 | TYPE_CASE(NPY_DOUBLE)case NPY_DOUBLE: return "NPY_DOUBLE"; | |||
| 53 | TYPE_CASE(NPY_LONGDOUBLE)case NPY_LONGDOUBLE: return "NPY_LONGDOUBLE"; | |||
| 54 | TYPE_CASE(NPY_CFLOAT)case NPY_CFLOAT: return "NPY_CFLOAT"; | |||
| 55 | TYPE_CASE(NPY_CDOUBLE)case NPY_CDOUBLE: return "NPY_CDOUBLE"; | |||
| 56 | TYPE_CASE(NPY_CLONGDOUBLE)case NPY_CLONGDOUBLE: return "NPY_CLONGDOUBLE"; | |||
| 57 | TYPE_CASE(NPY_OBJECT)case NPY_OBJECT: return "NPY_OBJECT"; | |||
| 58 | TYPE_CASE(NPY_STRING)case NPY_STRING: return "NPY_STRING"; | |||
| 59 | TYPE_CASE(NPY_UNICODE)case NPY_UNICODE: return "NPY_UNICODE"; | |||
| 60 | TYPE_CASE(NPY_VOID)case NPY_VOID: return "NPY_VOID"; | |||
| 61 | TYPE_CASE(NPY_DATETIME)case NPY_DATETIME: return "NPY_DATETIME"; | |||
| 62 | TYPE_CASE(NPY_TIMEDELTA)case NPY_TIMEDELTA: return "NPY_TIMEDELTA"; | |||
| 63 | TYPE_CASE(NPY_HALF)case NPY_HALF: return "NPY_HALF"; | |||
| 64 | TYPE_CASE(NPY_NTYPES)case NPY_NTYPES: return "NPY_NTYPES"; | |||
| 65 | TYPE_CASE(NPY_NOTYPE)case NPY_NOTYPE: return "NPY_NOTYPE"; | |||
| 66 | TYPE_CASE(NPY_CHAR)case NPY_CHAR: return "NPY_CHAR"; | |||
| 67 | TYPE_CASE(NPY_USERDEF)case NPY_USERDEF: return "NPY_USERDEF"; | |||
| 68 | default: | |||
| 69 | return "not a numpy type"; | |||
| 70 | } | |||
| 71 | } | |||
| 72 | ||||
| 73 | Status PyArrayDescr_to_TF_DataType(PyArray_Descr* descr, | |||
| 74 | TF_DataType* out_tf_datatype) { | |||
| 75 | PyObject* key; | |||
| 76 | PyObject* value; | |||
| 77 | Py_ssize_t pos = 0; | |||
| 78 | ||||
| 79 | // Return an error if the fields attribute is null. | |||
| 80 | // Occurs with an improper conversion attempt to resource. | |||
| 81 | if (descr->fields == nullptr) { | |||
| 82 | return errors::Internal("Unexpected numpy data type"); | |||
| 83 | } | |||
| 84 | ||||
| 85 | if (PyDict_Next(descr->fields, &pos, &key, &value)) { | |||
| 86 | // In Python 3, the keys of numpy custom struct types are unicode, unlike | |||
| 87 | // Python 2, where the keys are bytes. | |||
| 88 | const char* key_string = | |||
| 89 |         PyBytes_Check(key)((((((PyObject*)(key))->ob_type))->tp_flags & ((1UL << 27))) != 0) ? PyBytes_AsString(key)  | |||
| 90 | : PyBytes_AsString(PyUnicode_AsASCIIString(key)); | |||
  | ||||
| 91 | if (!key_string) { | |||
| 92 | return errors::Internal("Corrupt numpy type descriptor"); | |||
| 93 | } | |||
| 94 | tensorflow::string key = key_string; | |||
| 95 | // The typenames here should match the field names in the custom struct | |||
| 96 | // types constructed in test_util.py. | |||
| 97 | // TODO(mrry,keveman): Investigate Numpy type registration to replace this | |||
| 98 | // hard-coding of names. | |||
| 99 | if (key == "quint8") { | |||
| 100 | *out_tf_datatype = TF_QUINT8; | |||
| 101 | } else if (key == "qint8") { | |||
| 102 | *out_tf_datatype = TF_QINT8; | |||
| 103 | } else if (key == "qint16") { | |||
| 104 | *out_tf_datatype = TF_QINT16; | |||
| 105 | } else if (key == "quint16") { | |||
| 106 | *out_tf_datatype = TF_QUINT16; | |||
| 107 | } else if (key == "qint32") { | |||
| 108 | *out_tf_datatype = TF_QINT32; | |||
| 109 | } else if (key == "resource") { | |||
| 110 | *out_tf_datatype = TF_RESOURCE; | |||
| 111 | } else { | |||
| 112 | return errors::Internal("Unsupported numpy data type"); | |||
| 113 | } | |||
| 114 | return Status::OK(); | |||
| 115 | } | |||
| 116 | return errors::Internal("Unsupported numpy data type"); | |||
| 117 | } | |||
| 118 | ||||
| 119 | Status PyArray_TYPE_to_TF_DataType(PyArrayObject* array, | |||
| 120 | TF_DataType* out_tf_datatype) { | |||
| 121 | int pyarray_type = PyArray_TYPE(array); | |||
| 122 | PyArray_Descr* descr = PyArray_DESCR(array); | |||
| 123 | switch (pyarray_type) { | |||
| 124 | case NPY_FLOAT16NPY_HALF: | |||
| 125 | *out_tf_datatype = TF_HALF; | |||
| 126 | break; | |||
| 127 | case NPY_FLOAT32NPY_FLOAT: | |||
| 128 | *out_tf_datatype = TF_FLOAT; | |||
| 129 | break; | |||
| 130 | case NPY_FLOAT64NPY_DOUBLE: | |||
| 131 | *out_tf_datatype = TF_DOUBLE; | |||
| 132 | break; | |||
| 133 | case NPY_INT32NPY_INT: | |||
| 134 | *out_tf_datatype = TF_INT32; | |||
| 135 | break; | |||
| 136 | case NPY_UINT8NPY_UBYTE: | |||
| 137 | *out_tf_datatype = TF_UINT8; | |||
| 138 | break; | |||
| 139 | case NPY_UINT16NPY_USHORT: | |||
| 140 | *out_tf_datatype = TF_UINT16; | |||
| 141 | break; | |||
| 142 | case NPY_UINT32NPY_UINT: | |||
| 143 | *out_tf_datatype = TF_UINT32; | |||
| 144 | break; | |||
| 145 | case NPY_UINT64NPY_ULONG: | |||
| 146 | *out_tf_datatype = TF_UINT64; | |||
| 147 | break; | |||
| 148 | case NPY_INT8NPY_BYTE: | |||
| 149 | *out_tf_datatype = TF_INT8; | |||
| 150 | break; | |||
| 151 | case NPY_INT16NPY_SHORT: | |||
| 152 | *out_tf_datatype = TF_INT16; | |||
| 153 | break; | |||
| 154 | case NPY_INT64NPY_LONG: | |||
| 155 | *out_tf_datatype = TF_INT64; | |||
| 156 | break; | |||
| 157 | case NPY_BOOL: | |||
| 158 | *out_tf_datatype = TF_BOOL; | |||
| 159 | break; | |||
| 160 | case NPY_COMPLEX64NPY_CFLOAT: | |||
| 161 | *out_tf_datatype = TF_COMPLEX64; | |||
| 162 | break; | |||
| 163 | case NPY_COMPLEX128NPY_CDOUBLE: | |||
| 164 | *out_tf_datatype = TF_COMPLEX128; | |||
| 165 | break; | |||
| 166 | case NPY_OBJECT: | |||
| 167 | case NPY_STRING: | |||
| 168 | case NPY_UNICODE: | |||
| 169 | *out_tf_datatype = TF_STRING; | |||
| 170 | break; | |||
| 171 | case NPY_VOID: | |||
| 172 | // Quantized types are currently represented as custom struct types. | |||
| 173 | // PyArray_TYPE returns NPY_VOID for structs, and we should look into | |||
| 174 | // descr to derive the actual type. | |||
| 175 | // Direct feeds of certain types of ResourceHandles are represented as a | |||
| 176 | // custom struct type. | |||
| 177 | return PyArrayDescr_to_TF_DataType(descr, out_tf_datatype); | |||
| 178 | default: | |||
| 179 | if (pyarray_type == Bfloat16NumpyType()) { | |||
| 180 | *out_tf_datatype = TF_BFLOAT16; | |||
| 181 | break; | |||
| 182 | } else if (pyarray_type == NPY_ULONGLONG) { | |||
| 183 | // NPY_ULONGLONG is equivalent to NPY_UINT64, while their enum values | |||
| 184 | // might be different on certain platforms. | |||
| 185 | *out_tf_datatype = TF_UINT64; | |||
| 186 | break; | |||
| 187 | } else if (pyarray_type == NPY_LONGLONG) { | |||
| 188 | // NPY_LONGLONG is equivalent to NPY_INT64, while their enum values | |||
| 189 | // might be different on certain platforms. | |||
| 190 | *out_tf_datatype = TF_INT64; | |||
| 191 | break; | |||
| 192 | } else if (pyarray_type == NPY_INT) { | |||
| 193 | // NPY_INT is equivalent to NPY_INT32, while their enum values might be | |||
| 194 | // different on certain platforms. | |||
| 195 | *out_tf_datatype = TF_INT32; | |||
| 196 | break; | |||
| 197 | } else if (pyarray_type == NPY_UINT) { | |||
| 198 | // NPY_UINT is equivalent to NPY_UINT32, while their enum values might | |||
| 199 | // be different on certain platforms. | |||
| 200 | *out_tf_datatype = TF_UINT32; | |||
| 201 | break; | |||
| 202 | } | |||
| 203 | return errors::Internal("Unsupported numpy type: ", | |||
| 204 | numpy_type_name(pyarray_type)); | |||
| 205 | } | |||
| 206 | return Status::OK(); | |||
| 207 | } | |||
| 208 | ||||
| 209 | Status PyObjectToString(PyObject* obj, const char** ptr, Py_ssize_t* len, | |||
| 210 | PyObject** ptr_owner) { | |||
| 211 | *ptr_owner = nullptr; | |||
| 212 |   if (PyBytes_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 27))) != 0)) {  | |||
| 213 | char* buf; | |||
| 214 | if (PyBytes_AsStringAndSize(obj, &buf, len) != 0) { | |||
| 215 | return errors::Internal("Unable to get element as bytes."); | |||
| 216 | } | |||
| 217 | *ptr = buf; | |||
| 218 | return Status::OK(); | |||
| 219 |   } else if (PyUnicode_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 28))) != 0)) {  | |||
| 220 | #if (PY_MAJOR_VERSION3 > 3 || (PY_MAJOR_VERSION3 == 3 && PY_MINOR_VERSION8 >= 3)) | |||
| 221 | *ptr = PyUnicode_AsUTF8AndSize(obj, len); | |||
| 222 | if (*ptr != nullptr) return Status::OK(); | |||
| 223 | #else | |||
| 224 | PyObject* utemp = PyUnicode_AsUTF8String(obj); | |||
| 225 | char* buf; | |||
| 226 | if (utemp != nullptr && PyBytes_AsStringAndSize(utemp, &buf, len) != -1) { | |||
| 227 | *ptr = buf; | |||
| 228 | *ptr_owner = utemp; | |||
| 229 | return Status::OK(); | |||
| 230 | } | |||
| 231 | Py_XDECREF(utemp)_Py_XDECREF(((PyObject*)(utemp))); | |||
| 232 | #endif | |||
| 233 | return errors::Internal("Unable to convert element to UTF-8"); | |||
| 234 | } else { | |||
| 235 | return errors::Internal("Unsupported object type ", obj->ob_type->tp_name); | |||
| 236 | } | |||
| 237 | } | |||
| 238 | ||||
| 239 | // Iterate over the string array 'array', extract the ptr and len of each string | |||
| 240 | // element and call f(ptr, len). | |||
| 241 | template <typename F> | |||
| 242 | Status PyBytesArrayMap(PyArrayObject* array, F f) { | |||
| 243 | Safe_PyObjectPtr iter = tensorflow::make_safe( | |||
| 244 | PyArray_IterNew(*(PyObject * (*)(PyObject *)) _tensorflow_numpy_api[98])(reinterpret_cast<PyObject*>(array))); | |||
| 245 |   while (PyArray_ITER_NOTDONE(iter.get())(((PyArrayIterObject *)(iter.get()))->index < ((PyArrayIterObject *)(iter.get()))->size)) {  | |||
| 246 | auto item = tensorflow::make_safe(PyArray_GETITEM( | |||
| 247 | array, static_cast<char*>(PyArray_ITER_DATA(iter.get())((void *)(((PyArrayIterObject *)(iter.get()))->dataptr))))); | |||
| 248 | if (!item) { | |||
| 249 | return errors::Internal("Unable to get element from the feed - no item."); | |||
| 250 | } | |||
| 251 | Py_ssize_t len; | |||
| 252 | const char* ptr; | |||
| 253 | PyObject* ptr_owner = nullptr; | |||
| 254 |     TF_RETURN_IF_ERROR(PyObjectToString(item.get(), &ptr, &len, &ptr_owner))do { ::tensorflow::Status _status = (PyObjectToString(item.get (), &ptr, &len, &ptr_owner)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0);  | |||
| 255 | f(ptr, len); | |||
| 256 | Py_XDECREF(ptr_owner)_Py_XDECREF(((PyObject*)(ptr_owner))); | |||
| 257 |     PyArray_ITER_NEXT(iter.get())do { ((PyArrayIterObject *)(iter.get()))->index++; if (((PyArrayIterObject *)(iter.get()))->nd_m1 == 0) { do { (((PyArrayIterObject * )(iter.get())))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iter.get()))))->strides[0]; (((PyArrayIterObject *)(iter .get())))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iter.get()))->contiguous) ((PyArrayIterObject *)(iter. get()))->dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter .get()))->ao)->elsize; else if (((PyArrayIterObject *)( iter.get()))->nd_m1 == 1) { do { if ((((PyArrayIterObject * )(iter.get())))->coordinates[1] < (((PyArrayIterObject * )(iter.get())))->dims_m1[1]) { (((PyArrayIterObject *)(iter .get())))->coordinates[1]++; (((PyArrayIterObject *)(iter. get())))->dataptr += (((PyArrayIterObject *)(iter.get()))) ->strides[1]; } else { (((PyArrayIterObject *)(iter.get()) ))->coordinates[1] = 0; (((PyArrayIterObject *)(iter.get() )))->coordinates[0]++; (((PyArrayIterObject *)(iter.get()) ))->dataptr += (((PyArrayIterObject *)(iter.get())))->strides [0] - (((PyArrayIterObject *)(iter.get())))->backstrides[1 ]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iter.get()))->nd_m1; __npy_i >= 0; __npy_i--) { if ( ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] < ((PyArrayIterObject *)(iter.get()))->dims_m1[__npy_i]) { ( (PyArrayIterObject *)(iter.get()))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iter.get()))->dataptr += ((PyArrayIterObject *)(iter.get()))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iter.get()))->dataptr -= ((PyArrayIterObject *)(iter.get ()))->backstrides[__npy_i]; } } } } while (0);  | |||
| 258 | } | |||
| 259 | return Status::OK(); | |||
| 260 | } | |||
| 261 | ||||
| 262 | // Encode the strings in 'array' into a contiguous buffer and return the base of | |||
| 263 | // the buffer. The caller takes ownership of the buffer. | |||
| 264 | Status EncodePyBytesArray(PyArrayObject* array, int64_t nelems, size_t* size, | |||
| 265 | void** buffer) { | |||
| 266 | // Encode all strings. | |||
| 267 | *size = nelems * sizeof(tensorflow::tstring); | |||
| 268 | std::unique_ptr<tensorflow::tstring[]> base_ptr( | |||
| 269 | new tensorflow::tstring[nelems]); | |||
| 270 | tensorflow::tstring* dst = base_ptr.get(); | |||
| 271 | ||||
| 272 |   TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0)  | |||
| 273 |       PyBytesArrayMap(array, [&dst](const char* ptr, Py_ssize_t len) {do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0)  | |||
| 274 |         dst->assign(ptr, len);do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0)  | |||
| 275 |         dst++;do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0)  | |||
| 276 |       }))do { ::tensorflow::Status _status = (PyBytesArrayMap(array, [ &dst](const char* ptr, Py_ssize_t len) { dst->assign(ptr , len); dst++; })); if ((__builtin_expect(!_status.ok(), 0))) return _status; } while (0);  | |||
| 277 | *buffer = base_ptr.release(); | |||
| 278 | return Status::OK(); | |||
| 279 | } | |||
| 280 | ||||
| 281 | Status CopyTF_TensorStringsToPyArray(const TF_Tensor* src, uint64 nelems, | |||
| 282 | PyArrayObject* dst) { | |||
| 283 | const void* tensor_data = TF_TensorData(src); | |||
| 284 |   DCHECK(tensor_data != nullptr)while (false && (tensor_data != nullptr)) ::tensorflow ::internal::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 284);  | |||
| 285 |   DCHECK_EQ(TF_STRING, TF_TensorType(src))while (false && ((void)(TF_STRING), (void)(TF_TensorType (src)), 0)) ::tensorflow::internal::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 285);  | |||
| 286 | ||||
| 287 | const tstring* tstr = static_cast<const tstring*>(tensor_data); | |||
| 288 | ||||
| 289 | std::unique_ptr<TF_Status, decltype(&TF_DeleteStatus)> status( | |||
| 290 | TF_NewStatus(), TF_DeleteStatus); | |||
| 291 | auto iter = make_safe(PyArray_IterNew(*(PyObject * (*)(PyObject *)) _tensorflow_numpy_api[98])(reinterpret_cast<PyObject*>(dst))); | |||
| 292 | for (int64_t i = 0; i < static_cast<int64_t>(nelems); ++i) { | |||
| 293 | const tstring& tstr_i = tstr[i]; | |||
| 294 | auto py_string = | |||
| 295 | make_safe(PyBytes_FromStringAndSize(tstr_i.data(), tstr_i.size())); | |||
| 296 | if (py_string == nullptr) { | |||
| 297 | return errors::Internal( | |||
| 298 | "failed to create a python byte array when converting element #", i, | |||
| 299 | " of a TF_STRING tensor to a numpy ndarray"); | |||
| 300 | } | |||
| 301 | ||||
| 302 | if (PyArray_SETITEM(dst, static_cast<char*>(PyArray_ITER_DATA(iter.get())((void *)(((PyArrayIterObject *)(iter.get()))->dataptr))), | |||
| 303 | py_string.get()) != 0) { | |||
| 304 | return errors::Internal("Error settings element #", i, | |||
| 305 | " in the numpy ndarray"); | |||
| 306 | } | |||
| 307 |     PyArray_ITER_NEXT(iter.get())do { ((PyArrayIterObject *)(iter.get()))->index++; if (((PyArrayIterObject *)(iter.get()))->nd_m1 == 0) { do { (((PyArrayIterObject * )(iter.get())))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iter.get()))))->strides[0]; (((PyArrayIterObject *)(iter .get())))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iter.get()))->contiguous) ((PyArrayIterObject *)(iter. get()))->dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter .get()))->ao)->elsize; else if (((PyArrayIterObject *)( iter.get()))->nd_m1 == 1) { do { if ((((PyArrayIterObject * )(iter.get())))->coordinates[1] < (((PyArrayIterObject * )(iter.get())))->dims_m1[1]) { (((PyArrayIterObject *)(iter .get())))->coordinates[1]++; (((PyArrayIterObject *)(iter. get())))->dataptr += (((PyArrayIterObject *)(iter.get()))) ->strides[1]; } else { (((PyArrayIterObject *)(iter.get()) ))->coordinates[1] = 0; (((PyArrayIterObject *)(iter.get() )))->coordinates[0]++; (((PyArrayIterObject *)(iter.get()) ))->dataptr += (((PyArrayIterObject *)(iter.get())))->strides [0] - (((PyArrayIterObject *)(iter.get())))->backstrides[1 ]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iter.get()))->nd_m1; __npy_i >= 0; __npy_i--) { if ( ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] < ((PyArrayIterObject *)(iter.get()))->dims_m1[__npy_i]) { ( (PyArrayIterObject *)(iter.get()))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iter.get()))->dataptr += ((PyArrayIterObject *)(iter.get()))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iter.get()))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iter.get()))->dataptr -= ((PyArrayIterObject *)(iter.get ()))->backstrides[__npy_i]; } } } } while (0);  | |||
| 308 | } | |||
| 309 | return Status::OK(); | |||
| 310 | } | |||
| 311 | ||||
| 312 | // Determine the dimensions of a numpy ndarray to be created to represent an | |||
| 313 | // output Tensor. | |||
| 314 | Status GetPyArrayDimensionsForTensor(const TF_Tensor* tensor, | |||
| 315 | gtl::InlinedVector<npy_intp, 4>* dims, | |||
| 316 | int64_t* nelems) { | |||
| 317 | dims->clear(); | |||
| 318 | const int ndims = TF_NumDims(tensor); | |||
| 319 | if (TF_TensorType(tensor) == TF_RESOURCE) { | |||
| 320 | if (ndims != 0) { | |||
| 321 | return errors::InvalidArgument( | |||
| 322 | "Fetching of non-scalar resource tensors is not supported."); | |||
| 323 | } | |||
| 324 | dims->push_back(TF_TensorByteSize(tensor)); | |||
| 325 | *nelems = dims->back(); | |||
| 326 | } else { | |||
| 327 | *nelems = 1; | |||
| 328 | for (int i = 0; i < ndims; ++i) { | |||
| 329 | dims->push_back(TF_Dim(tensor, i)); | |||
| 330 | *nelems *= dims->back(); | |||
| 331 | } | |||
| 332 | } | |||
| 333 | return Status::OK(); | |||
| 334 | } | |||
| 335 | ||||
| 336 | // Determine the type description (PyArray_Descr) of a numpy ndarray to be | |||
| 337 | // created to represent an output Tensor. | |||
| 338 | Status GetPyArrayDescrForTensor(const TF_Tensor* tensor, | |||
| 339 | PyArray_Descr** descr) { | |||
| 340 | if (TF_TensorType(tensor) == TF_RESOURCE) { | |||
| 341 | PyObject* field = PyTuple_New(3); | |||
| 342 | #if PY_MAJOR_VERSION3 < 3 | |||
| 343 | PyTuple_SetItem(field, 0, PyBytes_FromString("resource")); | |||
| 344 | #else | |||
| 345 | PyTuple_SetItem(field, 0, PyUnicode_FromString("resource")); | |||
| 346 | #endif | |||
| 347 | PyTuple_SetItem(field, 1, PyArray_TypeObjectFromType(*(PyObject * (*)(int)) _tensorflow_numpy_api[46])(NPY_UBYTE)); | |||
| 348 | PyTuple_SetItem(field, 2, PyLong_FromLong(1)); | |||
| 349 | PyObject* fields = PyList_New(1); | |||
| 350 | PyList_SetItem(fields, 0, field); | |||
| 351 |     int convert_result = PyArray_DescrConverter(*(int (*)(PyObject *, PyArray_Descr **)) _tensorflow_numpy_api [174])(fields, descr);  | |||
| 352 |     Py_CLEAR(field)do { PyObject *_py_tmp = ((PyObject*)(field)); if (_py_tmp != __null) { (field) = __null; _Py_DECREF(((PyObject*)(_py_tmp) )); } } while (0);  | |||
| 353 |     Py_CLEAR(fields)do { PyObject *_py_tmp = ((PyObject*)(fields)); if (_py_tmp != __null) { (fields) = __null; _Py_DECREF(((PyObject*)(_py_tmp ))); } } while (0);  | |||
| 354 | if (convert_result != 1) { | |||
| 355 | return errors::Internal("Failed to create numpy array description for ", | |||
| 356 | "TF_RESOURCE-type tensor"); | |||
| 357 | } | |||
| 358 | } else { | |||
| 359 | int type_num = -1; | |||
| 360 |     TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (TF_DataType_to_PyArray_TYPE (TF_TensorType(tensor), &type_num)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0)  | |||
| 361 |         TF_DataType_to_PyArray_TYPE(TF_TensorType(tensor), &type_num))do { ::tensorflow::Status _status = (TF_DataType_to_PyArray_TYPE (TF_TensorType(tensor), &type_num)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0);  | |||
| 362 | *descr = PyArray_DescrFromType(*(PyArray_Descr * (*)(int)) _tensorflow_numpy_api[45])(type_num); | |||
| 363 | } | |||
| 364 | ||||
| 365 | return Status::OK(); | |||
| 366 | } | |||
| 367 | ||||
| 368 | inline void FastMemcpy(void* dst, const void* src, size_t size) { | |||
| 369 | // clang-format off | |||
| 370 | switch (size) { | |||
| 371 | // Most compilers will generate inline code for fixed sizes, | |||
| 372 | // which is significantly faster for small copies. | |||
| 373 | case 1: memcpy(dst, src, 1); break; | |||
| 374 | case 2: memcpy(dst, src, 2); break; | |||
| 375 | case 3: memcpy(dst, src, 3); break; | |||
| 376 | case 4: memcpy(dst, src, 4); break; | |||
| 377 | case 5: memcpy(dst, src, 5); break; | |||
| 378 | case 6: memcpy(dst, src, 6); break; | |||
| 379 | case 7: memcpy(dst, src, 7); break; | |||
| 380 | case 8: memcpy(dst, src, 8); break; | |||
| 381 | case 9: memcpy(dst, src, 9); break; | |||
| 382 | case 10: memcpy(dst, src, 10); break; | |||
| 383 | case 11: memcpy(dst, src, 11); break; | |||
| 384 | case 12: memcpy(dst, src, 12); break; | |||
| 385 | case 13: memcpy(dst, src, 13); break; | |||
| 386 | case 14: memcpy(dst, src, 14); break; | |||
| 387 | case 15: memcpy(dst, src, 15); break; | |||
| 388 | case 16: memcpy(dst, src, 16); break; | |||
| 389 | #if defined(PLATFORM_GOOGLE) || defined(PLATFORM_POSIX) && \ | |||
| 390 | !defined(IS_MOBILE_PLATFORM) | |||
| 391 | // On Linux, memmove appears to be faster than memcpy for | |||
| 392 | // large sizes, strangely enough. | |||
| 393 | default: memmove(dst, src, size); break; | |||
| 394 | #else | |||
| 395 | default: memcpy(dst, src, size); break; | |||
| 396 | #endif | |||
| 397 | } | |||
| 398 | // clang-format on | |||
| 399 | } | |||
| 400 | ||||
| 401 | } // namespace | |||
| 402 | ||||
| 403 | // TODO(slebedev): revise TF_TensorToPyArray usages and switch to the | |||
| 404 | // aliased version where appropriate. | |||
| 405 | Status TF_TensorToMaybeAliasedPyArray(Safe_TF_TensorPtr tensor, | |||
| 406 | PyObject** out_ndarray) { | |||
| 407 | auto dtype = TF_TensorType(tensor.get()); | |||
| 408 | if (dtype == TF_STRING || dtype == TF_RESOURCE) { | |||
| 409 | return TF_TensorToPyArray(std::move(tensor), out_ndarray); | |||
| 410 | } | |||
| 411 | ||||
| 412 | TF_Tensor* moved = tensor.release(); | |||
| 413 | int64_t nelems = -1; | |||
| 414 | gtl::InlinedVector<npy_intp, 4> dims; | |||
| 415 |   TF_RETURN_IF_ERROR(GetPyArrayDimensionsForTensor(moved, &dims, &nelems))do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (moved, &dims, &nelems)); if ((__builtin_expect(!_status .ok(), 0))) return _status; } while (0);  | |||
| 416 | return ArrayFromMemory( | |||
| 417 | dims.size(), dims.data(), TF_TensorData(moved), | |||
| 418 | static_cast<DataType>(dtype), [moved] { TF_DeleteTensor(moved); }, | |||
| 419 | out_ndarray); | |||
| 420 | } | |||
| 421 | ||||
| 422 | // Converts the given TF_Tensor to a numpy ndarray. | |||
| 423 | // If the returned status is OK, the caller becomes the owner of *out_array. | |||
| 424 | Status TF_TensorToPyArray(Safe_TF_TensorPtr tensor, PyObject** out_ndarray) { | |||
| 425 | // A fetched operation will correspond to a null tensor, and a None | |||
| 426 | // in Python. | |||
| 427 | if (tensor == nullptr) { | |||
| 428 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 429 | *out_ndarray = Py_None(&_Py_NoneStruct); | |||
| 430 | return Status::OK(); | |||
| 431 | } | |||
| 432 | int64_t nelems = -1; | |||
| 433 | gtl::InlinedVector<npy_intp, 4> dims; | |||
| 434 |   TF_RETURN_IF_ERROR(do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (tensor.get(), &dims, &nelems)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0)  | |||
| 435 |       GetPyArrayDimensionsForTensor(tensor.get(), &dims, &nelems))do { ::tensorflow::Status _status = (GetPyArrayDimensionsForTensor (tensor.get(), &dims, &nelems)); if ((__builtin_expect (!_status.ok(), 0))) return _status; } while (0);  | |||
| 436 | ||||
| 437 | // If the type is neither string nor resource we can reuse the Tensor memory. | |||
| 438 | TF_Tensor* original = tensor.get(); | |||
| 439 | TF_Tensor* moved = TF_TensorMaybeMove(tensor.release()); | |||
| 440 | if (moved != nullptr) { | |||
| 441 | if (ArrayFromMemory( | |||
| 442 | dims.size(), dims.data(), TF_TensorData(moved), | |||
| 443 | static_cast<DataType>(TF_TensorType(moved)), | |||
| 444 | [moved] { TF_DeleteTensor(moved); }, out_ndarray) | |||
| 445 | .ok()) { | |||
| 446 | return Status::OK(); | |||
| 447 | } | |||
| 448 | } | |||
| 449 | tensor.reset(original); | |||
| 450 | ||||
| 451 | // Copy the TF_TensorData into a newly-created ndarray and return it. | |||
| 452 | PyArray_Descr* descr = nullptr; | |||
| 453 |   TF_RETURN_IF_ERROR(GetPyArrayDescrForTensor(tensor.get(), &descr))do { ::tensorflow::Status _status = (GetPyArrayDescrForTensor (tensor.get(), &descr)); if ((__builtin_expect(!_status.ok (), 0))) return _status; } while (0);  | |||
| 454 | Safe_PyObjectPtr safe_out_array = | |||
| 455 |       tensorflow::make_safe(PyArray_Empty(*(PyObject * (*)(int, npy_intp const *, PyArray_Descr *, int )) _tensorflow_numpy_api[184])(dims.size(), dims.data(), descr, 0));  | |||
| 456 | if (!safe_out_array) { | |||
| 457 | return errors::Internal("Could not allocate ndarray"); | |||
| 458 | } | |||
| 459 | PyArrayObject* py_array = | |||
| 460 | reinterpret_cast<PyArrayObject*>(safe_out_array.get()); | |||
| 461 | if (TF_TensorType(tensor.get()) == TF_STRING) { | |||
| 462 | Status s = CopyTF_TensorStringsToPyArray(tensor.get(), nelems, py_array); | |||
| 463 | if (!s.ok()) { | |||
| 464 | return s; | |||
| 465 | } | |||
| 466 |   } else if (static_cast<size_t>(PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array)))) !=  | |||
| 467 | TF_TensorByteSize(tensor.get())) { | |||
| 468 |     return errors::Internal("ndarray was ", PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array))),  | |||
| 469 | " bytes but TF_Tensor was ", | |||
| 470 | TF_TensorByteSize(tensor.get()), " bytes"); | |||
| 471 | } else { | |||
| 472 | FastMemcpy(PyArray_DATA(py_array), TF_TensorData(tensor.get()), | |||
| 473 |                PyArray_NBYTES(py_array)(PyArray_ITEMSIZE(py_array) * (*(npy_intp (*)(npy_intp const * , int)) _tensorflow_numpy_api[158])(PyArray_DIMS(py_array), PyArray_NDIM (py_array))));  | |||
| 474 | } | |||
| 475 | ||||
| 476 | *out_ndarray = safe_out_array.release(); | |||
| 477 | return Status::OK(); | |||
| 478 | } | |||
| 479 | ||||
| 480 | Status NdarrayToTensor(TFE_Context* ctx, PyObject* ndarray, | |||
| 481 | Safe_TF_TensorPtr* ret) { | |||
| 482 |   DCHECK(ret != nullptr)while (false && (ret != nullptr)) ::tensorflow::internal ::LogMessageFatal("tensorflow/python/lib/core/ndarray_tensor.cc" , 482);  | |||
| 483 | ||||
| 484 | // Make sure we dereference this array object in case of error, etc. | |||
| 485 | Safe_PyObjectPtr array_safe(make_safe( | |||
| 486 |       PyArray_FromAny(*(PyObject * (*)(PyObject *, PyArray_Descr *, int, int, int, PyObject *)) _tensorflow_numpy_api[69])(ndarray, nullptr, 0, 0, NPY_ARRAY_CARRAY_RO(0x0001 | 0x0100), nullptr)));  | |||
| 487 | if (!array_safe) return errors::InvalidArgument("Not a ndarray."); | |||
| 488 | PyArrayObject* array = reinterpret_cast<PyArrayObject*>(array_safe.get()); | |||
| 489 | ||||
| 490 | // Convert numpy dtype to TensorFlow dtype. | |||
| 491 | TF_DataType dtype = TF_FLOAT; | |||
| 492 |   TF_RETURN_IF_ERROR(PyArray_TYPE_to_TF_DataType(array, &dtype))do { ::tensorflow::Status _status = (PyArray_TYPE_to_TF_DataType (array, &dtype)); if ((__builtin_expect(!_status.ok(), 0) )) return _status; } while (0);  | |||
| 493 | ||||
| 494 | int64_t nelems = 1; | |||
| 495 | gtl::InlinedVector<int64_t, 4> dims; | |||
| 496 | for (int i = 0; i < PyArray_NDIM(array); ++i) { | |||
| 497 | dims.push_back(PyArray_SHAPE(array)[i]); | |||
| 498 | nelems *= dims[i]; | |||
| 499 | } | |||
| 500 | ||||
| 501 | // Create a TF_Tensor based on the fed data. In the case of non-string data | |||
| 502 | // type, this steals a reference to array, which will be relinquished when | |||
| 503 | // the underlying buffer is deallocated. For string, a new temporary buffer | |||
| 504 | // is allocated into which the strings are encoded. | |||
| 505 | if (dtype == TF_RESOURCE) { | |||
| 506 |     size_t size = PyArray_NBYTES(array)(PyArray_ITEMSIZE(array) * (*(npy_intp (*)(npy_intp const *, int )) _tensorflow_numpy_api[158])(PyArray_DIMS(array), PyArray_NDIM (array)));  | |||
| 507 | array_safe.release(); | |||
| 508 | ||||
| 509 | if (ctx) { | |||
| 510 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
| 511 | static_cast<tensorflow::DataType>(dtype), {}, 0, PyArray_DATA(array), | |||
| 512 | size, &DelayedNumpyDecref, array)}); | |||
| 513 | } else { | |||
| 514 | *ret = make_safe(TF_NewTensor(dtype, {}, 0, PyArray_DATA(array), size, | |||
| 515 | &DelayedNumpyDecref, array)); | |||
| 516 | } | |||
| 517 | ||||
| 518 | } else if (dtype != TF_STRING) { | |||
| 519 |     size_t size = PyArray_NBYTES(array)(PyArray_ITEMSIZE(array) * (*(npy_intp (*)(npy_intp const *, int )) _tensorflow_numpy_api[158])(PyArray_DIMS(array), PyArray_NDIM (array)));  | |||
| 520 | array_safe.release(); | |||
| 521 | if (ctx) { | |||
| 522 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
| 523 | static_cast<tensorflow::DataType>(dtype), dims.data(), dims.size(), | |||
| 524 | PyArray_DATA(array), size, &DelayedNumpyDecref, array)}); | |||
| 525 | } else { | |||
| 526 | *ret = make_safe(TF_NewTensor(dtype, dims.data(), dims.size(), | |||
| 527 | PyArray_DATA(array), size, | |||
| 528 | &DelayedNumpyDecref, array)); | |||
| 529 | } | |||
| 530 | ||||
| 531 | } else { | |||
| 532 | size_t size = 0; | |||
| 533 | void* encoded = nullptr; | |||
| 534 |     TF_RETURN_IF_ERROR(EncodePyBytesArray(array, nelems, &size, &encoded))do { ::tensorflow::Status _status = (EncodePyBytesArray(array , nelems, &size, &encoded)); if ((__builtin_expect(!_status .ok(), 0))) return _status; } while (0);  | |||
| 535 | if (ctx) { | |||
| 536 | *ret = make_safe(new TF_Tensor{tensorflow::unwrap(ctx)->CreateTensor( | |||
| 537 | static_cast<tensorflow::DataType>(dtype), dims.data(), dims.size(), | |||
| 538 | encoded, size, | |||
| 539 | [](void* data, size_t len, void* arg) { | |||
| 540 | delete[] reinterpret_cast<tensorflow::tstring*>(data); | |||
| 541 | }, | |||
| 542 | nullptr)}); | |||
| 543 | } else { | |||
| 544 | *ret = make_safe(TF_NewTensor( | |||
| 545 | dtype, dims.data(), dims.size(), encoded, size, | |||
| 546 | [](void* data, size_t len, void* arg) { | |||
| 547 | delete[] reinterpret_cast<tensorflow::tstring*>(data); | |||
| 548 | }, | |||
| 549 | nullptr)); | |||
| 550 | } | |||
| 551 | } | |||
| 552 | ||||
| 553 | return Status::OK(); | |||
| 554 | } | |||
| 555 | ||||
| 556 | Status TF_TensorToTensor(const TF_Tensor* src, Tensor* dst); | |||
| 557 | TF_Tensor* TF_TensorFromTensor(const tensorflow::Tensor& src, Status* status); | |||
| 558 | ||||
| 559 | Status NdarrayToTensor(PyObject* obj, Tensor* ret) { | |||
| 560 | Safe_TF_TensorPtr tf_tensor = make_safe(static_cast<TF_Tensor*>(nullptr)); | |||
| 561 | Status s = NdarrayToTensor(nullptr /*ctx*/, obj, &tf_tensor); | |||
  | ||||
| 562 | if (!s.ok()) { | |||
| 563 | return s; | |||
| 564 | } | |||
| 565 | return TF_TensorToTensor(tf_tensor.get(), ret); | |||
| 566 | } | |||
| 567 | ||||
| 568 | Status TensorToNdarray(const Tensor& t, PyObject** ret) { | |||
| 569 | Status status; | |||
| 570 | Safe_TF_TensorPtr tf_tensor = make_safe(TF_TensorFromTensor(t, &status)); | |||
| 571 | if (!status.ok()) { | |||
| 572 | return status; | |||
| 573 | } | |||
| 574 | return TF_TensorToMaybeAliasedPyArray(std::move(tf_tensor), ret); | |||
| 575 | } | |||
| 576 | ||||
| 577 | } // namespace tensorflow | 
| 1 | #ifndef PyUnicode_AsASCIIString | 
| 2 | struct _object; | 
| 3 | typedef struct _object PyObject; | 
| 4 | PyObject* clang_analyzer_PyObject_New_Reference(); | 
| 5 | PyObject* PyUnicode_AsASCIIString(PyObject *unicode) { | 
| 6 | return clang_analyzer_PyObject_New_Reference(); | 
| 7 | } | 
| 8 | #else | 
| 9 | #warning "API PyUnicode_AsASCIIString is defined as a macro." | 
| 10 | #endif |