GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ops.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2022 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
33namespace 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#define INSTALL_UNOP_TI(ti, op, t, f) \
46 ti.install_unary_op \
47 (octave_value::op, t::static_type_id (), CONCAT2 (oct_unop_, f));
48
49#define INSTALL_NCUNOP_TI(ti, op, t, f) \
50 ti.install_non_const_unary_op \
51 (octave_value::op, t::static_type_id (), CONCAT2 (oct_unop_, f));
52
53#define INSTALL_BINOP_TI(ti, op, t1, t2, f) \
54 ti.install_binary_op \
55 (octave_value::op, t1::static_type_id (), t2::static_type_id (), \
56 CONCAT2 (oct_binop_, f));
57
58#define INSTALL_CATOP_TI(ti, t1, t2, f) \
59 ti.install_cat_op \
60 (t1::static_type_id (), t2::static_type_id (), CONCAT2 (oct_catop_, f));
61
62#define INSTALL_ASSIGNOP_TI(ti, op, t1, t2, f) \
63 ti.install_assign_op \
64 (octave_value::op, t1::static_type_id (), t2::static_type_id (), \
65 CONCAT2 (oct_assignop_, f));
66
67#define INSTALL_ASSIGNANYOP_TI(ti, op, t1, f) \
68 ti.install_assignany_op \
69 (octave_value::op, t1::static_type_id (), CONCAT2 (oct_assignop_, f));
70
71#define INSTALL_ASSIGNCONV_TI(ti, t1, t2, tr) \
72 ti.install_pref_assign_conv \
73 (t1::static_type_id (), t2::static_type_id (), tr::static_type_id ());
74
75#define INSTALL_WIDENOP_TI(ti, t1, t2, f) \
76 ti.install_widening_op \
77 (t1::static_type_id (), t2::static_type_id (), CONCAT2 (oct_conv_, f));
78
79#define DEFASSIGNOP(name, t1, t2) \
80 static octave_value \
81 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
82 const octave_value_list& idx, \
83 const octave_base_value& a2)
84
85#define DEFASSIGNOP_FN(name, t1, t2, f) \
86 static octave_value \
87 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
88 const octave_value_list& idx, \
89 const octave_base_value& a2) \
90 { \
91 CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
92 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
93 \
94 v1.f (idx, v2.CONCAT2 (t1, _value) ()); \
95 return octave_value (); \
96 }
97
98#define DEFNULLASSIGNOP_FN(name, t, f) \
99 static octave_value \
100 CONCAT2 (oct_assignop_, name) (octave_base_value& a, \
101 const octave_value_list& idx, \
102 const octave_base_value&) \
103 { \
104 CONCAT2 (octave_, t)& v = dynamic_cast<CONCAT2 (octave_, t)&> (a); \
105 \
106 v.f (idx); \
107 return octave_value (); \
108 }
109
110#define DEFNDASSIGNOP_FN(name, t1, t2, e, f) \
111 static octave_value \
112 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
113 const octave_value_list& idx, \
114 const octave_base_value& a2) \
115 { \
116 CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
117 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
118 \
119 v1.f (idx, v2.CONCAT2 (e, _value) ()); \
120 return octave_value (); \
121 }
122
123// FIXME: the following currently don't handle index.
124#define DEFNDASSIGNOP_OP(name, t1, t2, f, op) \
125 static octave_value \
126 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
127 const octave_value_list& idx, \
128 const octave_base_value& a2) \
129 { \
130 CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
131 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
132 \
133 assert (idx.empty ()); \
134 v1.matrix_ref () op v2.CONCAT2 (f, _value) (); \
135 \
136 return octave_value (); \
137 }
138
139#define DEFNDASSIGNOP_FNOP(name, t1, t2, f, fnop) \
140 static octave_value \
141 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
142 const octave_value_list& idx, \
143 const octave_base_value& a2) \
144 { \
145 CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
146 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
147 \
148 assert (idx.empty ()); \
149 fnop (v1.matrix_ref (), v2.CONCAT2 (f, _value) ()); \
150 \
151 return octave_value (); \
152 }
153
154#define DEFASSIGNANYOP_FN(name, t1, f) \
155 static octave_value \
156 CONCAT2 (oct_assignop_, name) (octave_base_value& a1, \
157 const octave_value_list& idx, \
158 const octave_value& a2) \
159 { \
160 CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
161 \
162 v1.f (idx, a2); \
163 return octave_value (); \
164 }
165
166#define CONVDECL(name) \
167 static octave_base_value * \
168 CONCAT2 (oct_conv_, name) (const octave_base_value& a)
169
170#define DEFCONV(name, a_dummy, b_dummy) \
171 CONVDECL (name)
172
173#define DEFUNOPX(name, t) \
174 static octave_value \
175 CONCAT2 (oct_unop_, name) (const octave_base_value&)
176
177#define DEFUNOP(name, t) \
178 static octave_value \
179 CONCAT2 (oct_unop_, name) (const octave_base_value& a)
180
181#define DEFUNOP_OP(name, t, op) \
182 static octave_value \
183 CONCAT2 (oct_unop_, name) (const octave_base_value& a) \
184 { \
185 const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
186 return octave_value (op v.CONCAT2 (t, _value) ()); \
187 }
188
189#define DEFNDUNOP_OP(name, t, e, op) \
190 static octave_value \
191 CONCAT2 (oct_unop_, name) (const octave_base_value& a) \
192 { \
193 const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
194 return octave_value (op v.CONCAT2 (e, _value) ()); \
195 }
196
197// FIXME: in some cases, the constructor isn't necessary.
198
199#define DEFUNOP_FN(name, t, f) \
200 static octave_value \
201 CONCAT2 (oct_unop_, name) (const octave_base_value& a) \
202 { \
203 const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
204 return octave_value (f (v.CONCAT2 (t, _value) ())); \
205 }
206
207#define DEFNDUNOP_FN(name, t, e, f) \
208 static octave_value \
209 CONCAT2 (oct_unop_, name) (const octave_base_value& a) \
210 { \
211 const CONCAT2 (octave_, t)& v = dynamic_cast<const CONCAT2 (octave_, t)&> (a); \
212 return octave_value (f (v.CONCAT2 (e, _value) ())); \
213 }
214
215#define DEFNCUNOP_METHOD(name, t, method) \
216 static void \
217 CONCAT2 (oct_unop_, name) (octave_base_value& a) \
218 { \
219 CONCAT2 (octave_, t)& v = dynamic_cast<CONCAT2 (octave_, t)&> (a); \
220 v.method (); \
221 }
222
223#define DEFBINOPX(name, t1, t2) \
224 static octave_value \
225 CONCAT2 (oct_binop_, name) (const octave_base_value&, \
226 const octave_base_value&)
227
228#define DEFBINOP(name, t1, t2) \
229 static octave_value \
230 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
231 const octave_base_value& a2)
232
233#define DEFBINOP_OP(name, t1, t2, op) \
234 static octave_value \
235 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
236 const octave_base_value& a2) \
237 { \
238 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
239 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
240 \
241 return octave_value \
242 (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ()); \
243 }
244
245#define DEFCMPLXCMPOP_OP(name, t1, t2, op) \
246 static octave_value \
247 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
248 const octave_base_value& a2) \
249 { \
250 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
251 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
252 \
253 warn_complex_cmp (); \
254 \
255 return octave_value \
256 (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ()); \
257 }
258
259#define DEFSCALARBOOLOP_OP(name, t1, t2, op) \
260 static octave_value \
261 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
262 const octave_base_value& a2) \
263 { \
264 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
265 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
266 \
267 if (octave::math::isnan (v1.CONCAT2 (t1, _value) ()) || octave::math::isnan (v2.CONCAT2 (t2, _value) ())) \
268 octave::err_nan_to_logical_conversion (); \
269 \
270 return octave_value \
271 (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ()); \
272 }
273
274#define DEFNDBINOP_OP(name, t1, t2, e1, e2, op) \
275 static octave_value \
276 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
277 const octave_base_value& a2) \
278 { \
279 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
280 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
281 \
282 return octave_value \
283 (v1.CONCAT2 (e1, _value) () op v2.CONCAT2 (e2, _value) ()); \
284 }
285
286// FIXME: in some cases, the constructor isn't necessary.
287
288#define DEFBINOP_FN(name, t1, t2, f) \
289 static octave_value \
290 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
291 const octave_base_value& a2) \
292 { \
293 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
294 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
295 \
296 return octave_value (f (v1.CONCAT2 (t1, _value) (), v2.CONCAT2 (t2, _value) ())); \
297 }
298
299#define DEFNDBINOP_FN(name, t1, t2, e1, e2, f) \
300 static octave_value \
301 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
302 const octave_base_value& a2) \
303 { \
304 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
305 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
306 \
307 return octave_value (f (v1.CONCAT2 (e1, _value) (), v2.CONCAT2 (e2, _value) ())); \
308 }
309
310#define DEFNDCMPLXCMPOP_FN(name, t1, t2, e1, e2, f) \
311 static octave_value \
312 CONCAT2 (oct_binop_, name) (const octave_base_value& a1, \
313 const octave_base_value& a2) \
314 { \
315 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
316 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
317 \
318 return octave_value (f (v1.CONCAT2 (e1, _value) (), v2.CONCAT2 (e2, _value) ())); \
319 }
320
321#define DEFCATOPX(name, t1, t2) \
322 static octave_value \
323 CONCAT2 (oct_catop_, name) (const octave_base_value&, \
324 const octave_base_value&, \
325 const Array<octave_idx_type>& ra_idx)
326
327#define DEFCATOP(name, t1, t2) \
328 static octave_value \
329 CONCAT2 (oct_catop_, name) (const octave_base_value& a1, \
330 const octave_base_value& a2, \
331 const Array<octave_idx_type>& ra_idx)
332
333// FIXME: in some cases, the constructor isn't necessary.
334
335#define DEFCATOP_FN(name, t1, t2, f) \
336 static octave_value \
337 CONCAT2 (oct_catop_, name) (const octave_base_value& a1, \
338 const octave_base_value& a2, \
339 const Array<octave_idx_type>& ra_idx) \
340 { \
341 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
342 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
343 \
344 return octave_value (v1.CONCAT2 (t1, _value) () . f (v2.CONCAT2 (t2, _value) (), ra_idx)); \
345 }
346
347#define DEFNDCATOP_FN(name, t1, t2, e1, e2, f) \
348 static octave_value \
349 CONCAT2 (oct_catop_, name) (const octave_base_value& a1, \
350 const octave_base_value& a2, \
351 const Array<octave_idx_type>& ra_idx) \
352 { \
353 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
354 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
355 \
356 return octave_value (v1.CONCAT2 (e1, _value) () . f (v2.CONCAT2 (e2, _value) (), ra_idx)); \
357 }
358
359#define DEFNDCHARCATOP_FN(name, t1, t2, f) \
360 static octave_value \
361 CONCAT2 (oct_catop_, name) (const octave_base_value& a1, \
362 const octave_base_value& a2, \
363 const Array<octave_idx_type>& ra_idx) \
364 { \
365 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
366 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
367 \
368 return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \
369 ((a1.is_sq_string () || a2.is_sq_string ()) \
370 ? '\'' : '"')); \
371 }
372
373// For compatibility, the second arg is always converted to the type
374// of the first. Hmm.
375
376#define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f) \
377 static octave_value \
378 CONCAT2 (oct_catop_, name) (const octave_base_value& a1, \
379 const octave_base_value& a2, \
380 const Array<octave_idx_type>& ra_idx) \
381 { \
382 const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
383 const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
384 \
385 return octave_value (tc1 (v1.CONCAT2 (e1, _value) ()) . f (tc2 (v2.CONCAT2 (e2, _value) ()), ra_idx)); \
386 }
387
388#endif