1 /* Copyright 2015 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 // Helper macros and typemaps for use in TensorFlow swig files. 17 // 18 %{ 19 #include <memory> 20 #include <vector> 21 #include "tensorflow/core/platform/types.h" 22 using tensorflow::uint64; 23 using tensorflow::string; 24 25 template<class T> _PyObjAs(PyObject * pystr,T * cstr)26 bool _PyObjAs(PyObject *pystr, T* cstr) { 27 T::undefined; // You need to define specialization _PyObjAs<T> 28 return false; 29 } 30 31 template<class T> _PyObjFrom(const T & c)32 PyObject *_PyObjFrom(const T& c) { 33 T::undefined; // You need to define specialization _PyObjFrom<T> 34 return NULL; 35 } 36 37 #ifdef HAS_GLOBAL_STRING 38 template<> _PyObjAs(PyObject * pystr,::string * cstr)39 bool _PyObjAs(PyObject *pystr, ::string* cstr) { 40 char *buf; 41 Py_ssize_t len; 42 if (PyBytes_AsStringAndSize(pystr, &buf, &len) == -1) return false; 43 if (cstr) cstr->assign(buf, len); 44 return true; 45 } 46 #endif 47 template<> _PyObjAs(PyObject * pystr,std::string * cstr)48 bool _PyObjAs(PyObject *pystr, std::string* cstr) { 49 char *buf; 50 Py_ssize_t len; 51 if (PyBytes_AsStringAndSize(pystr, &buf, &len) == -1) return false; 52 if (cstr) cstr->assign(buf, len); 53 return true; 54 } 55 #ifdef HAS_GLOBAL_STRING 56 template<> _PyObjFrom(const::string & c)57 PyObject* _PyObjFrom(const ::string& c) { 58 return PyBytes_FromStringAndSize(c.data(), c.size()); 59 } 60 #endif 61 template<> _PyObjFrom(const std::string & c)62 PyObject* _PyObjFrom(const std::string& c) { 63 return PyBytes_FromStringAndSize(c.data(), c.size()); 64 } 65 _SwigBytes_FromString(const string & s)66 PyObject* _SwigBytes_FromString(const string& s) { 67 return PyBytes_FromStringAndSize(s.data(), s.size()); 68 } 69 70 // The string must be both ASCII and Unicode compatible, so this routine 71 // should be used only for error messages and the like. _SwigSimpleStr_FromString(const string & s)72 PyObject* _SwigSimpleStr_FromString(const string& s) { 73 #if PY_MAJOR_VERSION < 3 74 return PyString_FromStringAndSize(s.data(), s.size()); 75 #else 76 return PyUnicode_FromStringAndSize(s.data(), s.size()); 77 #endif 78 } 79 80 template <class T> tf_vector_input_helper(PyObject * seq,std::vector<T> * out,bool (* convert)(PyObject *,T * const))81 bool tf_vector_input_helper(PyObject * seq, std::vector<T> * out, 82 bool (*convert)(PyObject*, T * const)) { 83 PyObject *item, *it = PyObject_GetIter(seq); 84 if (!it) return false; 85 while ((item = PyIter_Next(it))) { 86 T elem; 87 bool success = convert(item, &elem); 88 Py_DECREF(item); 89 if (!success) { 90 Py_DECREF(it); 91 return false; 92 } 93 if (out) out->push_back(elem); 94 } 95 Py_DECREF(it); 96 return static_cast<bool>(!PyErr_Occurred()); 97 } 98 %} 99 100 %typemap(in) string { 101 if (!_PyObjAs<string>($input, &$1)) return NULL; 102 } 103 104 %typemap(in) const string& (string temp) { 105 if (!_PyObjAs<string>($input, &temp)) return NULL; 106 $1 = &temp; 107 } 108 109 %typemap(out) int64_t { 110 $result = PyLong_FromLongLong($1); 111 } 112 113 %typemap(out) string { 114 $result = PyBytes_FromStringAndSize($1.data(), $1.size()); 115 } 116 117 %typemap(out) const string& { 118 $result = PyBytes_FromStringAndSize($1->data(), $1->size()); 119 } 120 121 %typemap(in, numinputs = 0) string* OUTPUT (string temp) { 122 $1 = &temp; 123 } 124 125 %typemap(argout) string * OUTPUT { 126 PyObject *str = PyBytes_FromStringAndSize($1->data(), $1->length()); 127 if (!str) SWIG_fail; 128 %append_output(str); 129 } 130 131 %typemap(argout) string* INOUT = string* OUTPUT; 132 133 %typemap(varout) string { 134 $result = PyBytes_FromStringAndSize($1.data(), $1.size()); 135 } 136 137 %define _LIST_OUTPUT_TYPEMAP(type, py_converter) 138 %typemap(in) std::vector<type>(std::vector<type> temp) { 139 if (!tf_vector_input_helper($input, &temp, _PyObjAs<type>)) { 140 if (!PyErr_Occurred()) 141 PyErr_SetString(PyExc_TypeError, "sequence(type) expected"); 142 return NULL; 143 } 144 $1 = temp; 145 } 146 %typemap(in) const std::vector<type>& (std::vector<type> temp), 147 const std::vector<type>* (std::vector<type> temp) { 148 if (!tf_vector_input_helper($input, &temp, _PyObjAs<type>)) { 149 if (!PyErr_Occurred()) 150 PyErr_SetString(PyExc_TypeError, "sequence(type) expected"); 151 return NULL; 152 } 153 $1 = &temp; 154 } 155 %typemap(in,numinputs=0) 156 std::vector<type>* OUTPUT (std::vector<type> temp), 157 hash_set<type>* OUTPUT (hash_set<type> temp), 158 set<type>* OUTPUT (set<type> temp) { 159 $1 = &temp; 160 } 161 %enddef 162 163 _LIST_OUTPUT_TYPEMAP(string, _SwigBytes_FromString); 164 _LIST_OUTPUT_TYPEMAP(long long, PyLong_FromLongLong); 165 _LIST_OUTPUT_TYPEMAP(unsigned long long, PyLong_FromUnsignedLongLong); 166 _LIST_OUTPUT_TYPEMAP(unsigned int, PyLong_FromUnsignedLong); 167 168 %typemap(in) uint64 { 169 // TODO(gps): Check if another implementation 170 // from hosting/images/util/image-hosting-utils.swig is better. May be not. 171 %#if PY_MAJOR_VERSION < 3 172 if (PyInt_Check($input)) { 173 $1 = static_cast<uint64>(PyInt_AsLong($input)); 174 } else 175 %#endif 176 if (PyLong_Check($input)) { 177 $1 = static_cast<uint64>(PyLong_AsUnsignedLongLong($input)); 178 } else { 179 PyErr_SetString(PyExc_TypeError, 180 "int or long value expected for argument \"$1_name\""); 181 } 182 // TODO(mrovner): Make consistent use of SWIG_fail vs. return NULL. 183 if (PyErr_Occurred()) return NULL; 184 } 185 186 %define _COPY_TYPEMAPS(oldtype, newtype) 187 typedef oldtype newtype; 188 %apply oldtype * OUTPUT { newtype * OUTPUT }; 189 %apply oldtype & OUTPUT { newtype & OUTPUT }; 190 %apply oldtype * INPUT { newtype * INPUT }; 191 %apply oldtype & INPUT { newtype & INPUT }; 192 %apply oldtype * INOUT { newtype * INOUT }; 193 %apply oldtype & INOUT { newtype & INOUT }; 194 %apply std::vector<oldtype> * OUTPUT { std::vector<newtype> * OUTPUT }; 195 %enddef 196 197 _COPY_TYPEMAPS(unsigned long long, uint64); 198 _COPY_TYPEMAPS(long long, int64); 199 _COPY_TYPEMAPS(unsigned int, mode_t); 200 201 // Proto input arguments to C API functions are passed as a (const 202 // void*, size_t) pair. In Python, typemap these to a single string 203 // argument. This typemap does *not* make a copy of the input. 204 %typemap(in) (const void* proto, size_t proto_len) { 205 char* c_string; 206 Py_ssize_t py_size; 207 // PyBytes_AsStringAndSize() does not copy but simply interprets the input 208 if (PyBytes_AsStringAndSize($input, &c_string, &py_size) == -1) { 209 // Python has raised an error (likely TypeError or UnicodeEncodeError). 210 SWIG_fail; 211 } 212 $1 = static_cast<void*>(c_string); 213 $2 = static_cast<size_t>(py_size); 214 } 215 216 // SWIG macros for explicit API declaration. 217 // Usage: 218 // 219 // %ignoreall 220 // %unignore SomeName; // namespace / class / method 221 // %include "somelib.h" 222 // %unignoreall // mandatory closing "bracket" 223 %define %ignoreall %ignore ""; %enddef 224 %define %unignore %rename("%s") %enddef 225 %define %unignoreall %rename("%s") ""; %enddef 226 227 #if SWIG_VERSION < 0x030000 228 // Define some C++11 keywords safe to ignore so older SWIG does not choke. 229 %define final %enddef 230 %define override %enddef 231 #endif 232 233 // Typemaps to automatically raise a Python exception from bad output TF_Status. 234 // TODO(b/77295559): expand this to all TF_Status* output params and deprecate 235 // raise_exception_on_not_ok_status (currently it only affects the C API). 236 %typemap(in, numinputs=0) TF_Status* status { 237 $1 = TF_NewStatus(); 238 } 239 240 %typemap(freearg) (TF_Status* status) { 241 TF_DeleteStatus($1); 242 } 243 244 %typemap(argout) TF_Status* status { 245 TF_Code code = TF_GetCode($1); 246 if (code != TF_OK) { 247 PyObject* exc = tensorflow::PyExceptionRegistry::Lookup(code); 248 // Arguments to OpError. 249 PyObject* exc_args = Py_BuildValue("sss", nullptr, nullptr, TF_Message($1)); 250 SWIG_SetErrorObj(exc, exc_args); 251 SWIG_fail; 252 } 253 } 254