• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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