1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_ops_h)
27 #define octave_ops_h 1
28 
29 #include "octave-config.h"
30 
31 #include "Array-util.h"
32 
33 namespace octave
34 {
35   class type_info;
36 }
37 
38 // Concatenation macros that enforce argument prescan
39 #define CONCAT2X(x, y) x ## y
40 #define CONCAT2(x, y) CONCAT2X (x, y)
41 
42 #define CONCAT3X(x, y, z) x ## y ## z
43 #define CONCAT3(x, y, z) CONCAT3X (x, y, z)
44 
45 extern void install_ops (octave::type_info&);
46 
47 #define INSTALL_UNOP_TI(ti, op, t, f)                                   \
48   ti.install_unary_op                                                   \
49   (octave_value::op, t::static_type_id (), CONCAT2 (oct_unop_, f));
50 
51 #define INSTALL_NCUNOP_TI(ti, op, t, f)                                 \
52   ti.install_non_const_unary_op                                         \
53   (octave_value::op, t::static_type_id (), CONCAT2 (oct_unop_, f));
54 
55 #define INSTALL_BINOP_TI(ti, op, t1, t2, f)                             \
56   ti.install_binary_op                                                  \
57   (octave_value::op, t1::static_type_id (), t2::static_type_id (),      \
58    CONCAT2 (oct_binop_, f));
59 
60 #define INSTALL_CATOP_TI(ti, t1, t2, f)                                 \
61   ti.install_cat_op                                                     \
62   (t1::static_type_id (), t2::static_type_id (), CONCAT2 (oct_catop_, f));
63 
64 #define INSTALL_ASSIGNOP_TI(ti, op, t1, t2, f)                          \
65   ti.install_assign_op                                                  \
66   (octave_value::op, t1::static_type_id (), t2::static_type_id (),      \
67    CONCAT2 (oct_assignop_, f));
68 
69 #define INSTALL_ASSIGNANYOP_TI(ti, op, t1, f)                           \
70   ti.install_assignany_op                                               \
71   (octave_value::op, t1::static_type_id (), CONCAT2 (oct_assignop_, f));
72 
73 #define INSTALL_ASSIGNCONV_TI(ti, t1, t2, tr)                           \
74   ti.install_pref_assign_conv                                           \
75   (t1::static_type_id (), t2::static_type_id (), tr::static_type_id ());
76 
77 #define INSTALL_WIDENOP_TI(ti, t1, t2, f)                               \
78   ti.install_widening_op                                                \
79   (t1::static_type_id (), t2::static_type_id (), CONCAT2 (oct_conv_, f));
80 
81 #define DEFASSIGNOP(name, t1, t2)                               \
82   static octave_value                                           \
83   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,         \
84                                  const octave_value_list& idx,  \
85                                  const octave_base_value& a2)
86 
87 #define DEFASSIGNOP_FN(name, t1, t2, f)                                 \
88   static octave_value                                                   \
89   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,                 \
90                                  const octave_value_list& idx,          \
91                                  const octave_base_value& a2)           \
92   {                                                                     \
93     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
94     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
95                                                                         \
96     v1.f (idx, v2.CONCAT2 (t1, _value) ());                             \
97     return octave_value ();                                             \
98   }
99 
100 #define DEFNULLASSIGNOP_FN(name, t, f)                                  \
101   static octave_value                                                   \
102   CONCAT2 (oct_assignop_, name) (octave_base_value& a,                  \
103                                  const octave_value_list& idx,          \
104                                  const octave_base_value&)              \
105   {                                                                     \
106     CONCAT2 (octave_, t)& v = dynamic_cast<CONCAT2 (octave_, t)&> (a);  \
107                                                                         \
108     v.f (idx);                                                          \
109     return octave_value ();                                             \
110   }
111 
112 #define DEFNDASSIGNOP_FN(name, t1, t2, e, f)                            \
113   static octave_value                                                   \
114   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,                 \
115                                  const octave_value_list& idx,          \
116                                  const octave_base_value& a2)           \
117   {                                                                     \
118     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
119     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
120                                                                         \
121     v1.f (idx, v2.CONCAT2 (e, _value) ());                              \
122     return octave_value ();                                             \
123   }
124 
125 // FIXME: the following currently don't handle index.
126 #define DEFNDASSIGNOP_OP(name, t1, t2, f, op)                           \
127   static octave_value                                                   \
128   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,                 \
129                                  const octave_value_list& idx,          \
130                                  const octave_base_value& a2)           \
131   {                                                                     \
132     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
133     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
134                                                                         \
135     assert (idx.empty ());                                              \
136     v1.matrix_ref () op v2.CONCAT2 (f, _value) ();                      \
137                                                                         \
138     return octave_value ();                                             \
139   }
140 
141 #define DEFNDASSIGNOP_FNOP(name, t1, t2, f, fnop)                       \
142   static octave_value                                                   \
143   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,                 \
144                                  const octave_value_list& idx,          \
145                                  const octave_base_value& a2)           \
146   {                                                                     \
147     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
148     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
149                                                                         \
150     assert (idx.empty ());                                              \
151     fnop (v1.matrix_ref (), v2.CONCAT2 (f, _value) ());                 \
152                                                                         \
153     return octave_value ();                                             \
154   }
155 
156 #define DEFASSIGNANYOP_FN(name, t1, f)                                  \
157   static octave_value                                                   \
158   CONCAT2 (oct_assignop_, name) (octave_base_value& a1,                 \
159                                  const octave_value_list& idx,          \
160                                  const octave_value& a2)                \
161   {                                                                     \
162     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
163                                                                         \
164     v1.f (idx, a2);                                                     \
165     return octave_value ();                                             \
166   }
167 
168 #define CONVDECL(name)                                          \
169   static octave_base_value *                                    \
170   CONCAT2 (oct_conv_, name) (const octave_base_value& a)
171 
172 #define DEFCONV(name, a_dummy, b_dummy)         \
173   CONVDECL (name)
174 
175 #define DEFUNOPX(name, t)                               \
176   static octave_value                                   \
177   CONCAT2 (oct_unop_, name) (const octave_base_value&)
178 
179 #define DEFUNOP(name, t)                                        \
180   static octave_value                                           \
181   CONCAT2 (oct_unop_, name) (const octave_base_value& a)
182 
183 #define DEFUNOP_OP(name, t, op)                                         \
184   static octave_value                                                   \
185   CONCAT2 (oct_unop_, name) (const octave_base_value& a)                \
186   {                                                                     \
187     const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
188     return octave_value (op v.CONCAT2 (t, _value) ());                  \
189   }
190 
191 #define DEFNDUNOP_OP(name, t, e, op)                                    \
192   static octave_value                                                   \
193   CONCAT2 (oct_unop_, name) (const octave_base_value& a)                \
194   {                                                                     \
195     const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
196     return octave_value (op v.CONCAT2 (e, _value) ());                  \
197   }
198 
199 // FIXME: in some cases, the constructor isn't necessary.
200 
201 #define DEFUNOP_FN(name, t, f)                                          \
202   static octave_value                                                   \
203   CONCAT2 (oct_unop_, name) (const octave_base_value& a)                \
204   {                                                                     \
205     const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
206     return octave_value (f (v.CONCAT2 (t, _value) ()));                 \
207   }
208 
209 #define DEFNDUNOP_FN(name, t, e, f)                                     \
210   static octave_value                                                   \
211   CONCAT2 (oct_unop_, name) (const octave_base_value& a)                \
212   {                                                                     \
213     const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
214     return octave_value (f (v.CONCAT2 (e, _value) ()));                 \
215   }
216 
217 #define DEFNCUNOP_METHOD(name, t, method)                               \
218   static void                                                           \
219   CONCAT2 (oct_unop_, name) (octave_base_value& a)                      \
220   {                                                                     \
221     CONCAT2 (octave_, t)& v = dynamic_cast<CONCAT2 (octave_, t)&> (a);  \
222     v.method ();                                                        \
223   }
224 
225 #define DEFBINOPX(name, t1, t2)                         \
226   static octave_value                                   \
227   CONCAT2 (oct_binop_, name) (const octave_base_value&, \
228                               const octave_base_value&)
229 
230 #define DEFBINOP(name, t1, t2)                                  \
231   static octave_value                                           \
232   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,      \
233                               const octave_base_value& a2)
234 
235 #define DEFBINOP_OP(name, t1, t2, op)                                   \
236   static octave_value                                                   \
237   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
238                               const octave_base_value& a2)              \
239   {                                                                     \
240     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
241     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
242                                                                         \
243     return octave_value                                                 \
244       (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
245   }
246 
247 #define DEFCMPLXCMPOP_OP(name, t1, t2, op)                              \
248   static octave_value                                                   \
249   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
250                               const octave_base_value& a2)              \
251   {                                                                     \
252     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
253     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
254                                                                         \
255     warn_complex_cmp ();                                                \
256                                                                         \
257     return octave_value                                                 \
258       (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
259   }
260 
261 #define DEFSCALARBOOLOP_OP(name, t1, t2, op)                            \
262   static octave_value                                                   \
263   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
264                               const octave_base_value& a2)              \
265   {                                                                     \
266     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
267     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
268                                                                         \
269     if (octave::math::isnan (v1.CONCAT2 (t1, _value) ()) || octave::math::isnan (v2.CONCAT2 (t2, _value) ())) \
270       octave::err_nan_to_logical_conversion ();                                 \
271                                                                         \
272     return octave_value                                                 \
273       (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
274   }
275 
276 #define DEFNDBINOP_OP(name, t1, t2, e1, e2, op)                         \
277   static octave_value                                                   \
278   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
279                               const octave_base_value& a2)              \
280   {                                                                     \
281     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
282     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
283                                                                         \
284     return octave_value                                                 \
285       (v1.CONCAT2 (e1, _value) () op v2.CONCAT2 (e2, _value) ());       \
286   }
287 
288 // FIXME: in some cases, the constructor isn't necessary.
289 
290 #define DEFBINOP_FN(name, t1, t2, f)                                    \
291   static octave_value                                                   \
292   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
293                               const octave_base_value& a2)              \
294   {                                                                     \
295     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
296     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
297                                                                         \
298     return octave_value (f (v1.CONCAT2 (t1, _value) (), v2.CONCAT2 (t2, _value) ())); \
299   }
300 
301 #define DEFNDBINOP_FN(name, t1, t2, e1, e2, f)                          \
302   static octave_value                                                   \
303   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
304                               const octave_base_value& a2)              \
305   {                                                                     \
306     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
307     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
308                                                                         \
309     return octave_value (f (v1.CONCAT2 (e1, _value) (), v2.CONCAT2 (e2, _value) ())); \
310   }
311 
312 #define DEFNDCMPLXCMPOP_FN(name, t1, t2, e1, e2, f)                     \
313   static octave_value                                                   \
314   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
315                               const octave_base_value& a2)              \
316   {                                                                     \
317     const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
318     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
319                                                                         \
320     return octave_value (f (v1.CONCAT2 (e1, _value) (), v2.CONCAT2 (e2, _value) ())); \
321   }
322 
323 #define DEFCATOPX(name, t1, t2)                                         \
324   static octave_value                                                   \
325   CONCAT2 (oct_catop_, name) (octave_base_value&, const octave_base_value&, \
326                               const Array<octave_idx_type>& ra_idx)
327 
328 #define DEFCATOP(name, t1, t2)                                          \
329   static octave_value                                                   \
330   CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
331                               const octave_base_value& a2,              \
332                               const Array<octave_idx_type>& ra_idx)
333 
334 // FIXME: in some cases, the constructor isn't necessary.
335 
336 #define DEFCATOP_FN(name, t1, t2, f)                                    \
337   static octave_value                                                   \
338   CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
339                               const octave_base_value& a2,              \
340                               const Array<octave_idx_type>& ra_idx)     \
341   {                                                                     \
342     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
343     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
344                                                                         \
345     return octave_value (v1.CONCAT2 (t1, _value) () . f (v2.CONCAT2 (t2, _value) (), ra_idx)); \
346   }
347 
348 #define DEFNDCATOP_FN(name, t1, t2, e1, e2, f)                          \
349   static octave_value                                                   \
350   CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
351                               const octave_base_value& a2,              \
352                               const Array<octave_idx_type>& ra_idx)     \
353   {                                                                     \
354     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
355     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
356                                                                         \
357     return octave_value (v1.CONCAT2 (e1, _value) () . f (v2.CONCAT2 (e2, _value) (), ra_idx)); \
358   }
359 
360 #define DEFNDCHARCATOP_FN(name, t1, t2, f)                              \
361   static octave_value                                                   \
362   CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
363                               const octave_base_value& a2,              \
364                               const Array<octave_idx_type>& ra_idx)     \
365   {                                                                     \
366     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
367     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
368                                                                         \
369     return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \
370                          ((a1.is_sq_string () || a2.is_sq_string ())    \
371                           ? '\'' : '"'));                               \
372   }
373 
374 // For compatibility, the second arg is always converted to the type
375 // of the first.  Hmm.
376 
377 #define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f)               \
378   static octave_value                                                   \
379   CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
380                               const octave_base_value& a2,              \
381                               const Array<octave_idx_type>& ra_idx)     \
382   {                                                                     \
383     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
384     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
385                                                                         \
386     return octave_value (tc1 (v1.CONCAT2 (e1, _value) ()) . f (tc2 (v2.CONCAT2 (e2, _value) ()), ra_idx)); \
387   }
388 
389 #endif
390