]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright David Abrahams 2002. |
2 | // Distributed under the Boost Software License, Version 1.0. (See | |
3 | // accompanying file LICENSE_1_0.txt or copy at | |
4 | // http://www.boost.org/LICENSE_1_0.txt) | |
5 | #ifndef OPERATORS_DWA2002530_HPP | |
6 | # define OPERATORS_DWA2002530_HPP | |
7 | ||
8 | # include <boost/python/detail/prefix.hpp> | |
9 | ||
10 | # include <boost/python/def_visitor.hpp> | |
11 | # include <boost/python/converter/arg_to_python.hpp> | |
12 | # include <boost/python/detail/operator_id.hpp> | |
13 | # include <boost/python/detail/not_specified.hpp> | |
14 | # include <boost/python/back_reference.hpp> | |
15 | # include <boost/mpl/if.hpp> | |
16 | # include <boost/mpl/eval_if.hpp> | |
17 | # include <boost/python/self.hpp> | |
18 | # include <boost/python/other.hpp> | |
19 | # include <boost/lexical_cast.hpp> | |
20 | # include <boost/python/refcount.hpp> | |
21 | # include <boost/python/detail/unwrap_wrapper.hpp> | |
22 | # include <string> | |
23 | # include <complex> | |
24 | ||
25 | namespace boost { namespace python { | |
26 | ||
27 | namespace detail | |
28 | { | |
29 | // This is essentially the old v1 to_python(). It will be eliminated | |
30 | // once the public interface for to_python is settled on. | |
31 | template <class T> | |
32 | PyObject* convert_result(T const& x) | |
33 | { | |
34 | return converter::arg_to_python<T>(x).release(); | |
35 | } | |
36 | ||
37 | // Operator implementation template declarations. The nested apply | |
38 | // declaration here keeps MSVC6 happy. | |
39 | template <operator_id> struct operator_l | |
40 | { | |
41 | template <class L, class R> struct apply; | |
42 | }; | |
43 | ||
44 | template <operator_id> struct operator_r | |
45 | { | |
46 | template <class L, class R> struct apply; | |
47 | }; | |
48 | ||
49 | template <operator_id> struct operator_1 | |
50 | { | |
51 | template <class T> struct apply; | |
52 | }; | |
53 | ||
54 | // MSVC6 doesn't want us to do this sort of inheritance on a nested | |
55 | // class template, so we use this layer of indirection to avoid | |
56 | // ::template<...> on the nested apply functions below | |
57 | template <operator_id id, class L, class R> | |
58 | struct operator_l_inner | |
59 | : operator_l<id>::template apply<L,R> | |
60 | {}; | |
61 | ||
62 | template <operator_id id, class L, class R> | |
63 | struct operator_r_inner | |
64 | : operator_r<id>::template apply<L,R> | |
65 | {}; | |
66 | ||
67 | template <operator_id id, class T> | |
68 | struct operator_1_inner | |
69 | : operator_1<id>::template apply<T> | |
70 | {}; | |
71 | ||
72 | // Define three different binary_op templates which take care of | |
73 | // these cases: | |
74 | // self op self | |
75 | // self op R | |
76 | // L op self | |
77 | // | |
78 | // The inner apply metafunction is used to adjust the operator to | |
79 | // the class type being defined. Inheritance of the outer class is | |
80 | // simply used to provide convenient access to the operation's | |
81 | // name(). | |
82 | ||
83 | // self op self | |
84 | template <operator_id id> | |
85 | struct binary_op : operator_l<id> | |
86 | { | |
87 | template <class T> | |
88 | struct apply : operator_l_inner<id,T,T> | |
89 | { | |
90 | }; | |
91 | }; | |
92 | ||
93 | // self op R | |
94 | template <operator_id id, class R> | |
95 | struct binary_op_l : operator_l<id> | |
96 | { | |
97 | template <class T> | |
98 | struct apply : operator_l_inner<id,T,R> | |
99 | { | |
100 | }; | |
101 | }; | |
102 | ||
103 | // L op self | |
104 | template <operator_id id, class L> | |
105 | struct binary_op_r : operator_r<id> | |
106 | { | |
107 | template <class T> | |
108 | struct apply : operator_r_inner<id,L,T> | |
109 | { | |
110 | }; | |
111 | }; | |
112 | ||
113 | template <operator_id id> | |
114 | struct unary_op : operator_1<id> | |
115 | { | |
116 | template <class T> | |
117 | struct apply : operator_1_inner<id,T> | |
118 | { | |
119 | }; | |
120 | }; | |
121 | ||
122 | // This type is what actually gets returned from operators used on | |
123 | // self_t | |
124 | template <operator_id id, class L = not_specified, class R = not_specified> | |
125 | struct operator_ | |
126 | : def_visitor<operator_<id,L,R> > | |
127 | { | |
128 | private: | |
129 | template <class ClassT> | |
130 | void visit(ClassT& cl) const | |
131 | { | |
132 | typedef typename mpl::eval_if< | |
133 | is_same<L,self_t> | |
134 | , mpl::if_< | |
135 | is_same<R,self_t> | |
136 | , binary_op<id> | |
137 | , binary_op_l< | |
138 | id | |
139 | , BOOST_DEDUCED_TYPENAME unwrap_other<R>::type | |
140 | > | |
141 | > | |
142 | , mpl::if_< | |
143 | is_same<L,not_specified> | |
144 | , unary_op<id> | |
145 | , binary_op_r< | |
146 | id | |
147 | , BOOST_DEDUCED_TYPENAME unwrap_other<L>::type | |
148 | > | |
149 | > | |
150 | >::type generator; | |
151 | ||
152 | cl.def( | |
153 | generator::name() | |
154 | , &generator::template apply< | |
155 | BOOST_DEDUCED_TYPENAME ClassT::wrapped_type | |
156 | >::execute | |
157 | ); | |
158 | } | |
159 | ||
160 | friend class python::def_visitor_access; | |
161 | }; | |
162 | } | |
163 | ||
164 | # define BOOST_PYTHON_BINARY_OPERATION(id, rid, expr) \ | |
165 | namespace detail \ | |
166 | { \ | |
167 | template <> \ | |
168 | struct operator_l<op_##id> \ | |
169 | { \ | |
170 | template <class L, class R> \ | |
171 | struct apply \ | |
172 | { \ | |
173 | typedef typename unwrap_wrapper_<L>::type lhs; \ | |
174 | typedef typename unwrap_wrapper_<R>::type rhs; \ | |
175 | static PyObject* execute(lhs& l, rhs const& r) \ | |
176 | { \ | |
177 | return detail::convert_result(expr); \ | |
178 | } \ | |
179 | }; \ | |
180 | static char const* name() { return "__" #id "__"; } \ | |
181 | }; \ | |
182 | \ | |
183 | template <> \ | |
184 | struct operator_r<op_##id> \ | |
185 | { \ | |
186 | template <class L, class R> \ | |
187 | struct apply \ | |
188 | { \ | |
189 | typedef typename unwrap_wrapper_<L>::type lhs; \ | |
190 | typedef typename unwrap_wrapper_<R>::type rhs; \ | |
191 | static PyObject* execute(rhs& r, lhs const& l) \ | |
192 | { \ | |
193 | return detail::convert_result(expr); \ | |
194 | } \ | |
195 | }; \ | |
196 | static char const* name() { return "__" #rid "__"; } \ | |
197 | }; \ | |
198 | } | |
199 | ||
200 | # define BOOST_PYTHON_BINARY_OPERATOR(id, rid, op) \ | |
201 | BOOST_PYTHON_BINARY_OPERATION(id, rid, l op r) \ | |
202 | namespace self_ns \ | |
203 | { \ | |
204 | template <class L, class R> \ | |
205 | inline detail::operator_<detail::op_##id,L,R> \ | |
206 | operator op(L const&, R const&) \ | |
207 | { \ | |
208 | return detail::operator_<detail::op_##id,L,R>(); \ | |
209 | } \ | |
210 | } | |
211 | ||
212 | BOOST_PYTHON_BINARY_OPERATOR(add, radd, +) | |
213 | BOOST_PYTHON_BINARY_OPERATOR(sub, rsub, -) | |
214 | BOOST_PYTHON_BINARY_OPERATOR(mul, rmul, *) | |
215 | #if PY_VERSION_HEX >= 0x03000000 | |
216 | BOOST_PYTHON_BINARY_OPERATOR(truediv, rtruediv, /) | |
217 | #else | |
218 | BOOST_PYTHON_BINARY_OPERATOR(div, rdiv, /) | |
219 | #endif | |
220 | BOOST_PYTHON_BINARY_OPERATOR(mod, rmod, %) | |
221 | BOOST_PYTHON_BINARY_OPERATOR(lshift, rlshift, <<) | |
222 | BOOST_PYTHON_BINARY_OPERATOR(rshift, rrshift, >>) | |
223 | BOOST_PYTHON_BINARY_OPERATOR(and, rand, &) | |
224 | BOOST_PYTHON_BINARY_OPERATOR(xor, rxor, ^) | |
225 | BOOST_PYTHON_BINARY_OPERATOR(or, ror, |) | |
226 | BOOST_PYTHON_BINARY_OPERATOR(gt, lt, >) | |
227 | BOOST_PYTHON_BINARY_OPERATOR(ge, le, >=) | |
228 | BOOST_PYTHON_BINARY_OPERATOR(lt, gt, <) | |
229 | BOOST_PYTHON_BINARY_OPERATOR(le, ge, <=) | |
230 | BOOST_PYTHON_BINARY_OPERATOR(eq, eq, ==) | |
231 | BOOST_PYTHON_BINARY_OPERATOR(ne, ne, !=) | |
232 | # undef BOOST_PYTHON_BINARY_OPERATOR | |
233 | ||
234 | // pow isn't an operator in C++; handle it specially. | |
235 | BOOST_PYTHON_BINARY_OPERATION(pow, rpow, pow(l,r)) | |
236 | # undef BOOST_PYTHON_BINARY_OPERATION | |
237 | ||
238 | namespace self_ns | |
239 | { | |
240 | # ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP | |
241 | template <class L, class R> | |
242 | inline detail::operator_<detail::op_pow,L,R> | |
243 | pow(L const&, R const&) | |
244 | { | |
245 | return detail::operator_<detail::op_pow,L,R>(); | |
246 | } | |
247 | # else | |
248 | // When there's no argument-dependent lookup, we need these | |
249 | // overloads to handle the case when everything is imported into the | |
250 | // global namespace. Note that the plain overload below does /not/ | |
251 | // take const& arguments. This is needed by MSVC6 at least, or it | |
252 | // complains of ambiguities, since there's no partial ordering. | |
253 | inline detail::operator_<detail::op_pow,self_t,self_t> | |
254 | pow(self_t, self_t) | |
255 | { | |
256 | return detail::operator_<detail::op_pow,self_t,self_t>(); | |
257 | } | |
258 | template <class R> | |
259 | inline detail::operator_<detail::op_pow,self_t,R> | |
260 | pow(self_t const&, R const&) | |
261 | { | |
262 | return detail::operator_<detail::op_pow,self_t,R>(); | |
263 | } | |
264 | template <class L> | |
265 | inline detail::operator_<detail::op_pow,L,self_t> | |
266 | pow(L const&, self_t const&) | |
267 | { | |
268 | return detail::operator_<detail::op_pow,L,self_t>(); | |
269 | } | |
270 | # endif | |
271 | } | |
272 | ||
273 | ||
274 | # define BOOST_PYTHON_INPLACE_OPERATOR(id, op) \ | |
275 | namespace detail \ | |
276 | { \ | |
277 | template <> \ | |
278 | struct operator_l<op_##id> \ | |
279 | { \ | |
280 | template <class L, class R> \ | |
281 | struct apply \ | |
282 | { \ | |
283 | typedef typename unwrap_wrapper_<L>::type lhs; \ | |
284 | typedef typename unwrap_wrapper_<R>::type rhs; \ | |
285 | static PyObject* \ | |
286 | execute(back_reference<lhs&> l, rhs const& r) \ | |
287 | { \ | |
288 | l.get() op r; \ | |
289 | return python::incref(l.source().ptr()); \ | |
290 | } \ | |
291 | }; \ | |
292 | static char const* name() { return "__" #id "__"; } \ | |
293 | }; \ | |
294 | } \ | |
295 | namespace self_ns \ | |
296 | { \ | |
297 | template <class R> \ | |
298 | inline detail::operator_<detail::op_##id,self_t,R> \ | |
299 | operator op(self_t const&, R const&) \ | |
300 | { \ | |
301 | return detail::operator_<detail::op_##id,self_t,R>(); \ | |
302 | } \ | |
303 | } | |
304 | ||
305 | BOOST_PYTHON_INPLACE_OPERATOR(iadd,+=) | |
306 | BOOST_PYTHON_INPLACE_OPERATOR(isub,-=) | |
307 | BOOST_PYTHON_INPLACE_OPERATOR(imul,*=) | |
308 | BOOST_PYTHON_INPLACE_OPERATOR(idiv,/=) | |
309 | BOOST_PYTHON_INPLACE_OPERATOR(imod,%=) | |
310 | BOOST_PYTHON_INPLACE_OPERATOR(ilshift,<<=) | |
311 | BOOST_PYTHON_INPLACE_OPERATOR(irshift,>>=) | |
312 | BOOST_PYTHON_INPLACE_OPERATOR(iand,&=) | |
313 | BOOST_PYTHON_INPLACE_OPERATOR(ixor,^=) | |
314 | BOOST_PYTHON_INPLACE_OPERATOR(ior,|=) | |
315 | ||
316 | # define BOOST_PYTHON_UNARY_OPERATOR(id, op, func_name) \ | |
317 | namespace detail \ | |
318 | { \ | |
319 | template <> \ | |
320 | struct operator_1<op_##id> \ | |
321 | { \ | |
322 | template <class T> \ | |
323 | struct apply \ | |
324 | { \ | |
325 | typedef typename unwrap_wrapper_<T>::type self_t; \ | |
326 | static PyObject* execute(self_t& x) \ | |
327 | { \ | |
328 | return detail::convert_result(op(x)); \ | |
329 | } \ | |
330 | }; \ | |
331 | static char const* name() { return "__" #id "__"; } \ | |
332 | }; \ | |
333 | } \ | |
334 | namespace self_ns \ | |
335 | { \ | |
336 | inline detail::operator_<detail::op_##id> \ | |
337 | func_name(self_t const&) \ | |
338 | { \ | |
339 | return detail::operator_<detail::op_##id>(); \ | |
340 | } \ | |
341 | } | |
342 | # undef BOOST_PYTHON_INPLACE_OPERATOR | |
343 | ||
344 | BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-) | |
345 | BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+) | |
346 | BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs) | |
347 | BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~) | |
348 | #if PY_VERSION_HEX >= 0x03000000 | |
349 | BOOST_PYTHON_UNARY_OPERATOR(bool, !!, operator!) | |
350 | #else | |
351 | BOOST_PYTHON_UNARY_OPERATOR(nonzero, !!, operator!) | |
352 | #endif | |
353 | BOOST_PYTHON_UNARY_OPERATOR(int, long, int_) | |
354 | BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_) | |
355 | BOOST_PYTHON_UNARY_OPERATOR(float, double, float_) | |
356 | BOOST_PYTHON_UNARY_OPERATOR(complex, std::complex<double>, complex_) | |
357 | BOOST_PYTHON_UNARY_OPERATOR(str, lexical_cast<std::string>, str) | |
358 | BOOST_PYTHON_UNARY_OPERATOR(repr, lexical_cast<std::string>, repr) | |
359 | # undef BOOST_PYTHON_UNARY_OPERATOR | |
360 | ||
361 | }} // namespace boost::python | |
362 | ||
363 | # ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP | |
364 | using boost::python::self_ns::abs; | |
365 | using boost::python::self_ns::int_; | |
366 | using boost::python::self_ns::long_; | |
367 | using boost::python::self_ns::float_; | |
368 | using boost::python::self_ns::complex_; | |
369 | using boost::python::self_ns::str; | |
370 | using boost::python::self_ns::repr; | |
371 | using boost::python::self_ns::pow; | |
372 | # endif | |
373 | ||
374 | #endif // OPERATORS_DWA2002530_HPP |