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