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 (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <iostream> 31 32 #include "Array.h" 33 34 #include "defun.h" 35 #include "error.h" 36 #include "interpreter.h" 37 #include "interpreter-private.h" 38 #include "ops.h" 39 #include "ov-typeinfo.h" 40 #include "ov.h" 41 42 namespace octave 43 { 44 // FIXME: we should also store all class names and provide a 45 // way to list them (calling class with nargin == 0?). 46 as_nd_array(const Array<int> & x)47 static NDArray as_nd_array (const Array<int>& x) 48 { 49 NDArray retval (x.dims ()); 50 51 for (int i = 0; i < x.numel (); i++) 52 retval.xelem(i) = x(i); 53 54 return retval; 55 } 56 as_bool_nd_array(const Array<void * > & x)57 static boolNDArray as_bool_nd_array (const Array<void *>& x) 58 { 59 boolNDArray retval (x.dims ()); 60 61 for (octave_idx_type i = 0; i < x.numel (); i++) 62 retval.xelem (i) = x(i); 63 64 return retval; 65 } 66 type_info(int init_tab_sz)67 type_info::type_info (int init_tab_sz) 68 : num_types (0), types (dim_vector (init_tab_sz, 1), ""), 69 vals (dim_vector (init_tab_sz, 1)), 70 unary_class_ops (dim_vector (octave_value::num_unary_ops, 1), nullptr), 71 unary_ops (dim_vector (octave_value::num_unary_ops, init_tab_sz), nullptr), 72 non_const_unary_ops (dim_vector (octave_value::num_unary_ops, init_tab_sz), nullptr), 73 binary_class_ops (dim_vector (octave_value::num_binary_ops, 1), nullptr), 74 binary_ops (dim_vector (octave_value::num_binary_ops, init_tab_sz, init_tab_sz), nullptr), 75 compound_binary_class_ops (dim_vector (octave_value::num_compound_binary_ops, 1), nullptr), 76 compound_binary_ops (dim_vector (octave_value::num_compound_binary_ops, init_tab_sz, init_tab_sz), nullptr), 77 cat_ops (dim_vector (init_tab_sz, init_tab_sz), nullptr), 78 assign_ops (dim_vector (octave_value::num_assign_ops, init_tab_sz, init_tab_sz), nullptr), 79 assignany_ops (dim_vector (octave_value::num_assign_ops, init_tab_sz), nullptr), 80 pref_assign_conv (dim_vector (init_tab_sz, init_tab_sz), -1), 81 widening_ops (dim_vector (init_tab_sz, init_tab_sz), nullptr) 82 { 83 install_types (*this); 84 85 install_ops (*this); 86 } 87 register_type(const std::string & t_name,const std::string &,const octave_value & val,bool abort_on_duplicate)88 int type_info::register_type (const std::string& t_name, 89 const std::string& /* c_name */, 90 const octave_value& val, 91 bool abort_on_duplicate) 92 { 93 int i = 0; 94 95 for (i = 0; i < num_types; i++) 96 { 97 if (t_name == types (i)) 98 { 99 if (abort_on_duplicate) 100 { 101 std::cerr << "duplicate type " << t_name << std::endl; 102 abort (); 103 } 104 105 warning ("duplicate type %s\n", t_name.c_str ()); 106 107 return i; 108 } 109 } 110 111 int len = types.numel (); 112 113 if (i == len) 114 { 115 len *= 2; 116 117 types.resize (dim_vector (len, 1), ""); 118 119 vals.resize (dim_vector (len, 1), nullptr); 120 121 unary_ops.resize 122 (dim_vector (octave_value::num_unary_ops, len), nullptr); 123 124 non_const_unary_ops.resize 125 (dim_vector (octave_value::num_unary_ops, len), nullptr); 126 127 binary_ops.resize 128 (dim_vector (octave_value::num_binary_ops, len, len), nullptr); 129 130 compound_binary_ops.resize 131 (dim_vector (octave_value::num_compound_binary_ops, len, len), 132 nullptr); 133 134 cat_ops.resize (dim_vector (len, len), nullptr); 135 136 assign_ops.resize 137 (dim_vector (octave_value::num_assign_ops, len, len), nullptr); 138 139 assignany_ops.resize 140 (dim_vector (octave_value::num_assign_ops, len), nullptr); 141 142 pref_assign_conv.resize (dim_vector (len, len), -1); 143 144 widening_ops.resize (dim_vector (len, len), nullptr); 145 } 146 147 types (i) = t_name; 148 149 // Yes, this object is intentionally not deleted in the destructor 150 // so that we avoid a crash on exit for user-defined data types. 151 // See bug #53156. If that problem is properly fixed, then this 152 // could be stored as an object instead of a pointer to an object 153 // allocated with new. 154 155 vals(i) = new octave_value (val); 156 157 num_types++; 158 159 return i; 160 } 161 register_unary_class_op(octave_value::unary_op op,type_info::unary_class_op_fcn f,bool abort_on_duplicate)162 bool type_info::register_unary_class_op (octave_value::unary_op op, 163 type_info::unary_class_op_fcn f, 164 bool abort_on_duplicate) 165 { 166 if (lookup_unary_class_op (op)) 167 { 168 std::string op_name = octave_value::unary_op_as_string (op); 169 170 if (abort_on_duplicate) 171 { 172 std::cerr << "duplicate unary operator '" << op_name 173 << "' for class dispatch" << std::endl; 174 abort (); 175 } 176 177 warning ("duplicate unary operator '%s' for class dispatch", 178 op_name.c_str ()); 179 } 180 181 unary_class_ops.checkelem (static_cast<int> (op)) 182 = reinterpret_cast<void *> (f); 183 184 return false; 185 } 186 register_unary_op(octave_value::unary_op op,int t,unary_op_fcn f,bool abort_on_duplicate)187 bool type_info::register_unary_op (octave_value::unary_op op, int t, 188 unary_op_fcn f, bool abort_on_duplicate) 189 { 190 if (lookup_unary_op (op, t)) 191 { 192 std::string op_name = octave_value::unary_op_as_string (op); 193 std::string type_name = types(t); 194 195 if (abort_on_duplicate) 196 { 197 std::cerr << "duplicate unary operator '" << op_name 198 << "' for type '" << type_name << "'" << std::endl; 199 abort (); 200 } 201 202 warning ("duplicate unary operator '%s' for type '%s'", 203 op_name.c_str (), type_name.c_str ()); 204 } 205 206 unary_ops.checkelem (static_cast<int> (op), t) = reinterpret_cast<void *> (f); 207 208 return false; 209 } 210 211 bool register_non_const_unary_op(octave_value::unary_op op,int t,type_info::non_const_unary_op_fcn f,bool abort_on_duplicate)212 type_info::register_non_const_unary_op (octave_value::unary_op op, int t, 213 type_info::non_const_unary_op_fcn f, 214 bool abort_on_duplicate) 215 { 216 if (lookup_non_const_unary_op (op, t)) 217 { 218 std::string op_name = octave_value::unary_op_as_string (op); 219 std::string type_name = types(t); 220 221 if (abort_on_duplicate) 222 { 223 std::cerr << "duplicate unary operator '" << op_name 224 << "' for type '" << type_name << "'" << std::endl; 225 abort (); 226 } 227 228 warning ("duplicate unary operator '%s' for type '%s'", 229 op_name.c_str (), type_name.c_str ()); 230 } 231 232 non_const_unary_ops.checkelem (static_cast<int> (op), t) 233 = reinterpret_cast<void *> (f); 234 235 return false; 236 } 237 238 bool register_binary_class_op(octave_value::binary_op op,type_info::binary_class_op_fcn f,bool abort_on_duplicate)239 type_info::register_binary_class_op (octave_value::binary_op op, 240 type_info::binary_class_op_fcn f, 241 bool abort_on_duplicate) 242 { 243 if (lookup_binary_class_op (op)) 244 { 245 std::string op_name = octave_value::binary_op_as_string (op); 246 247 if (abort_on_duplicate) 248 { 249 250 std::cerr << "duplicate binary operator '" << op_name 251 << "' for class dispatch" << std::endl; 252 abort (); 253 } 254 255 warning ("duplicate binary operator '%s' for class dispatch", 256 op_name.c_str ()); 257 } 258 259 binary_class_ops.checkelem (static_cast<int> (op)) 260 = reinterpret_cast<void *> (f); 261 262 return false; 263 } 264 register_binary_op(octave_value::binary_op op,int t1,int t2,type_info::binary_op_fcn f,bool abort_on_duplicate)265 bool type_info::register_binary_op (octave_value::binary_op op, 266 int t1, int t2, 267 type_info::binary_op_fcn f, 268 bool abort_on_duplicate) 269 { 270 if (lookup_binary_op (op, t1, t2)) 271 { 272 std::string op_name = octave_value::binary_op_as_string (op); 273 std::string t1_name = types(t1); 274 std::string t2_name = types(t2); 275 276 if (abort_on_duplicate) 277 { 278 std::cerr << "duplicate binary operator '" << op_name 279 << "' for types '" << t1_name << "' and '" 280 << t2_name << "'" << std::endl; 281 abort (); 282 } 283 284 warning ("duplicate binary operator '%s' for types '%s' and '%s'", 285 op_name.c_str (), t1_name.c_str (), t1_name.c_str ()); 286 } 287 288 binary_ops.checkelem (static_cast<int> (op), t1, t2) 289 = reinterpret_cast<void *> (f); 290 291 return false; 292 } 293 294 bool register_binary_class_op(octave_value::compound_binary_op op,type_info::binary_class_op_fcn f,bool abort_on_duplicate)295 type_info::register_binary_class_op (octave_value::compound_binary_op op, 296 type_info::binary_class_op_fcn f, 297 bool abort_on_duplicate) 298 { 299 if (lookup_binary_class_op (op)) 300 { 301 std::string op_name = octave_value::binary_op_fcn_name (op); 302 303 if (abort_on_duplicate) 304 { 305 std::cerr << "duplicate compound binary operator '" 306 << op_name << "' for class dispatch" << std::endl; 307 abort (); 308 } 309 310 warning ("duplicate compound binary operator '%s' for class dispatch", 311 op_name.c_str ()); 312 } 313 314 compound_binary_class_ops.checkelem (static_cast<int> (op)) 315 = reinterpret_cast<void *> (f); 316 317 return false; 318 } 319 register_binary_op(octave_value::compound_binary_op op,int t1,int t2,type_info::binary_op_fcn f,bool abort_on_duplicate)320 bool type_info::register_binary_op (octave_value::compound_binary_op op, 321 int t1, int t2, 322 type_info::binary_op_fcn f, 323 bool abort_on_duplicate) 324 { 325 if (lookup_binary_op (op, t1, t2)) 326 { 327 std::string op_name = octave_value::binary_op_fcn_name (op); 328 std::string t1_name = types(t1); 329 std::string t2_name = types(t2); 330 331 if (abort_on_duplicate) 332 { 333 std::cerr << "duplicate compound binary operator '" 334 << op_name << "' for types '" << t1_name 335 << "' and '" << t2_name << "'" << std::endl; 336 abort (); 337 } 338 339 warning ("duplicate compound binary operator '%s' for types '%s' and '%s'", 340 op_name.c_str (), t1_name.c_str (), t1_name.c_str ()); 341 } 342 343 compound_binary_ops.checkelem (static_cast<int> (op), t1, t2) 344 = reinterpret_cast<void *> (f); 345 346 return false; 347 } 348 register_cat_op(int t1,int t2,type_info::cat_op_fcn f,bool abort_on_duplicate)349 bool type_info::register_cat_op (int t1, int t2, type_info::cat_op_fcn f, 350 bool abort_on_duplicate) 351 { 352 if (lookup_cat_op (t1, t2)) 353 { 354 std::string t1_name = types(t1); 355 std::string t2_name = types(t2); 356 357 if (abort_on_duplicate) 358 { 359 std::cerr << "duplicate concatenation operator for types '" 360 << t1_name << "' and '" << t2_name << "'" << std::endl; 361 abort (); 362 } 363 364 warning ("duplicate concatenation operator for types '%s' and '%s'", 365 t1_name.c_str (), t1_name.c_str ()); 366 } 367 368 cat_ops.checkelem (t1, t2) = reinterpret_cast<void *> (f); 369 370 return false; 371 } 372 register_assign_op(octave_value::assign_op op,int t_lhs,int t_rhs,type_info::assign_op_fcn f,bool abort_on_duplicate)373 bool type_info::register_assign_op (octave_value::assign_op op, 374 int t_lhs, int t_rhs, 375 type_info::assign_op_fcn f, 376 bool abort_on_duplicate) 377 { 378 if (lookup_assign_op (op, t_lhs, t_rhs)) 379 { 380 std::string op_name = octave_value::assign_op_as_string (op); 381 std::string t_lhs_name = types(t_lhs); 382 std::string t_rhs_name = types(t_rhs); 383 384 if (abort_on_duplicate) 385 { 386 std::cerr << "duplicate assignment operator '" 387 << op_name << "' for types '" << t_lhs_name 388 << "' and '" << t_rhs_name << "'" << std::endl; 389 abort (); 390 } 391 392 warning ("duplicate assignment operator '%s' for types '%s' and '%s'", 393 op_name.c_str (), t_lhs_name.c_str (), t_rhs_name.c_str ()); 394 } 395 396 assign_ops.checkelem (static_cast<int> (op), t_lhs, t_rhs) 397 = reinterpret_cast<void *> (f); 398 399 return false; 400 } 401 register_assignany_op(octave_value::assign_op op,int t_lhs,type_info::assignany_op_fcn f,bool abort_on_duplicate)402 bool type_info::register_assignany_op (octave_value::assign_op op, int t_lhs, 403 type_info::assignany_op_fcn f, 404 bool abort_on_duplicate) 405 { 406 if (lookup_assignany_op (op, t_lhs)) 407 { 408 std::string op_name = octave_value::assign_op_as_string (op); 409 std::string t_lhs_name = types(t_lhs); 410 411 if (abort_on_duplicate) 412 { 413 std::cerr << "duplicate assignment operator '" << op_name 414 << "' for types '" << t_lhs_name << "'" << std::endl; 415 abort (); 416 } 417 418 warning ("duplicate assignment operator '%s' for types '%s'", 419 op_name.c_str (), t_lhs_name.c_str ()); 420 } 421 422 assignany_ops.checkelem (static_cast<int> (op), t_lhs) 423 = reinterpret_cast<void *> (f); 424 425 return false; 426 } 427 register_pref_assign_conv(int t_lhs,int t_rhs,int t_result,bool abort_on_duplicate)428 bool type_info::register_pref_assign_conv (int t_lhs, int t_rhs, 429 int t_result, 430 bool abort_on_duplicate) 431 { 432 if (lookup_pref_assign_conv (t_lhs, t_rhs) >= 0) 433 { 434 std::string t_lhs_name = types(t_lhs); 435 std::string t_rhs_name = types(t_rhs); 436 437 if (abort_on_duplicate) 438 { 439 std::cerr << "overriding assignment conversion for types '" 440 << t_lhs_name << "' and '" << t_rhs_name << "'" 441 << std::endl; 442 abort (); 443 } 444 445 warning ("overriding assignment conversion for types '%s' and '%s'", 446 t_lhs_name.c_str (), t_rhs_name.c_str ()); 447 } 448 449 pref_assign_conv.checkelem (t_lhs, t_rhs) = t_result; 450 451 return false; 452 } 453 register_widening_op(int t,int t_result,octave_base_value::type_conv_fcn f,bool abort_on_duplicate)454 bool type_info::register_widening_op (int t, int t_result, 455 octave_base_value::type_conv_fcn f, 456 bool abort_on_duplicate) 457 { 458 if (lookup_widening_op (t, t_result)) 459 { 460 std::string t_name = types(t); 461 std::string t_result_name = types(t_result); 462 463 if (abort_on_duplicate) 464 { 465 std::cerr << "overriding widening op for '" << t_name 466 << "' to '" << t_result_name << "'" << std::endl; 467 abort (); 468 } 469 470 warning ("overriding widening op for '%s' to '%s'", 471 t_name.c_str (), t_result_name.c_str ()); 472 } 473 474 widening_ops.checkelem (t, t_result) = reinterpret_cast<void *> (f); 475 476 return false; 477 } 478 lookup_type(const std::string & nm)479 octave_value type_info::lookup_type (const std::string& nm) 480 { 481 octave_value retval; 482 483 for (int i = 0; i < num_types; i++) 484 { 485 if (nm == types(i)) 486 { 487 retval = *vals(i); 488 retval.make_unique (); 489 break; 490 } 491 } 492 493 return retval; 494 } 495 496 type_info::unary_class_op_fcn lookup_unary_class_op(octave_value::unary_op op)497 type_info::lookup_unary_class_op (octave_value::unary_op op) 498 { 499 void *f = unary_class_ops.checkelem (static_cast<int> (op)); 500 return reinterpret_cast<type_info::unary_class_op_fcn> (f); 501 } 502 503 type_info::unary_op_fcn lookup_unary_op(octave_value::unary_op op,int t)504 type_info::lookup_unary_op (octave_value::unary_op op, int t) 505 { 506 void *f = unary_ops.checkelem (static_cast<int> (op), t); 507 return reinterpret_cast<type_info::unary_op_fcn> (f); 508 } 509 510 type_info::non_const_unary_op_fcn lookup_non_const_unary_op(octave_value::unary_op op,int t)511 type_info::lookup_non_const_unary_op (octave_value::unary_op op, int t) 512 { 513 void *f = non_const_unary_ops.checkelem (static_cast<int> (op), t); 514 return reinterpret_cast<type_info::non_const_unary_op_fcn> (f); 515 } 516 517 type_info::binary_class_op_fcn lookup_binary_class_op(octave_value::binary_op op)518 type_info::lookup_binary_class_op (octave_value::binary_op op) 519 { 520 void *f = binary_class_ops.checkelem (static_cast<int> (op)); 521 return reinterpret_cast<type_info::binary_class_op_fcn> (f); 522 } 523 524 type_info::binary_op_fcn lookup_binary_op(octave_value::binary_op op,int t1,int t2)525 type_info::lookup_binary_op (octave_value::binary_op op, int t1, int t2) 526 { 527 void *f = binary_ops.checkelem (static_cast<int> (op), t1, t2); 528 return reinterpret_cast<type_info::binary_op_fcn> (f); 529 } 530 531 type_info::binary_class_op_fcn lookup_binary_class_op(octave_value::compound_binary_op op)532 type_info::lookup_binary_class_op (octave_value::compound_binary_op op) 533 { 534 void *f = compound_binary_class_ops.checkelem (static_cast<int> (op)); 535 return reinterpret_cast<type_info::binary_class_op_fcn> (f); 536 } 537 538 type_info::binary_op_fcn lookup_binary_op(octave_value::compound_binary_op op,int t1,int t2)539 type_info::lookup_binary_op (octave_value::compound_binary_op op, 540 int t1, int t2) 541 { 542 void *f = compound_binary_ops.checkelem (static_cast<int> (op), t1, t2); 543 return reinterpret_cast<type_info::binary_op_fcn> (f); 544 } 545 546 type_info::cat_op_fcn lookup_cat_op(int t1,int t2)547 type_info::lookup_cat_op (int t1, int t2) 548 { 549 void *f = cat_ops.checkelem (t1, t2); 550 return reinterpret_cast<type_info::cat_op_fcn> (f); 551 } 552 553 type_info::assign_op_fcn lookup_assign_op(octave_value::assign_op op,int t_lhs,int t_rhs)554 type_info::lookup_assign_op (octave_value::assign_op op, 555 int t_lhs, int t_rhs) 556 { 557 void *f = assign_ops.checkelem (static_cast<int> (op), t_lhs, t_rhs); 558 return reinterpret_cast<type_info::assign_op_fcn> (f); 559 } 560 561 type_info::assignany_op_fcn lookup_assignany_op(octave_value::assign_op op,int t_lhs)562 type_info::lookup_assignany_op (octave_value::assign_op op, int t_lhs) 563 { 564 void *f = assignany_ops.checkelem (static_cast<int> (op), t_lhs); 565 return reinterpret_cast<type_info::assignany_op_fcn> (f); 566 } 567 568 int lookup_pref_assign_conv(int t_lhs,int t_rhs)569 type_info::lookup_pref_assign_conv (int t_lhs, int t_rhs) 570 { 571 return pref_assign_conv.checkelem (t_lhs, t_rhs); 572 } 573 574 octave_base_value::type_conv_fcn lookup_widening_op(int t,int t_result)575 type_info::lookup_widening_op (int t, int t_result) 576 { 577 void *f = widening_ops.checkelem (t, t_result); 578 return reinterpret_cast<octave_base_value::type_conv_fcn> (f); 579 } 580 581 string_vector installed_type_names(void) const582 type_info::installed_type_names (void) const 583 { 584 string_vector retval (num_types); 585 586 for (int i = 0; i < num_types; i++) 587 retval(i) = types(i); 588 589 return retval; 590 } 591 592 octave_scalar_map unary_ops_map(void) const593 type_info::unary_ops_map (void) const 594 { 595 octave_scalar_map retval; 596 597 int len = std::min (static_cast<int> (non_const_unary_ops.columns ()), 598 num_types); 599 600 dim_vector tab_dims (1, len); 601 602 for (int j = 0; j < octave_value::num_unary_ops; j++) 603 { 604 boolNDArray tab (tab_dims); 605 606 for (int i = 0; i < len; i++) 607 tab.xelem (i) = (unary_ops(j,i) != nullptr); 608 609 octave_value::unary_op op_id = static_cast<octave_value::unary_op> (j); 610 611 retval.setfield (octave_value::unary_op_as_string (op_id), tab); 612 } 613 614 return retval; 615 } 616 617 octave_scalar_map non_const_unary_ops_map(void) const618 type_info::non_const_unary_ops_map (void) const 619 { 620 octave_scalar_map retval; 621 622 int len = std::min (static_cast<int> (non_const_unary_ops.columns ()), 623 num_types); 624 625 dim_vector tab_dims (1, len); 626 627 for (int j = 0; j < octave_value::num_unary_ops; j++) 628 { 629 boolNDArray tab (tab_dims); 630 631 for (int i = 0; i < len; i++) 632 tab.xelem (i) = (non_const_unary_ops(j,i) != nullptr); 633 634 octave_value::unary_op op_id = static_cast<octave_value::unary_op> (j); 635 636 retval.setfield (octave_value::unary_op_as_string (op_id), tab); 637 } 638 639 return retval; 640 } 641 642 octave_scalar_map binary_ops_map(void) const643 type_info::binary_ops_map (void) const 644 { 645 octave_scalar_map retval; 646 647 int len = std::min (static_cast<int> (binary_ops.columns ()), num_types); 648 649 dim_vector tab_dims (len, len); 650 651 for (int k = 0; k < octave_value::num_binary_ops; k++) 652 { 653 boolNDArray tab (tab_dims); 654 655 for (int j = 0; j < len; j++) 656 for (int i = 0; i < len; i++) 657 tab.xelem (j,i) = (binary_ops(k,j,i) != nullptr); 658 659 octave_value::binary_op op_id = static_cast<octave_value::binary_op> (k); 660 661 retval.setfield (octave_value::binary_op_as_string (op_id), tab); 662 } 663 664 return retval; 665 } 666 667 octave_scalar_map compound_binary_ops_map(void) const668 type_info::compound_binary_ops_map (void) const 669 { 670 octave_scalar_map retval; 671 672 int len = std::min (static_cast<int> (compound_binary_ops.columns ()), 673 num_types); 674 675 dim_vector tab_dims (len, len); 676 677 for (int k = 0; k < octave_value::num_compound_binary_ops; k++) 678 { 679 boolNDArray tab (tab_dims); 680 681 for (int j = 0; j < len; j++) 682 for (int i = 0; i < len; i++) 683 tab.xelem (j,i) = (compound_binary_ops(k,j,i) != nullptr); 684 685 octave_value::compound_binary_op op_id 686 = static_cast<octave_value::compound_binary_op> (k); 687 688 retval.setfield (octave_value::binary_op_fcn_name (op_id), tab); 689 } 690 691 return retval; 692 } 693 694 octave_scalar_map assign_ops_map(void) const695 type_info::assign_ops_map (void) const 696 { 697 octave_scalar_map retval; 698 699 int len = std::min (static_cast<int> (assign_ops.columns ()), num_types); 700 701 dim_vector tab_dims (len, len); 702 703 for (int k = 0; k < octave_value::num_assign_ops; k++) 704 { 705 boolNDArray tab (tab_dims); 706 707 for (int j = 0; j < len; j++) 708 for (int i = 0; i < len; i++) 709 tab.xelem (j,i) = (assign_ops(k,j,i) != nullptr); 710 711 octave_value::assign_op op_id = static_cast<octave_value::assign_op> (k); 712 713 retval.setfield (octave_value::assign_op_as_string (op_id), tab); 714 } 715 716 return retval; 717 } 718 719 octave_scalar_map assignany_ops_map(void) const720 type_info::assignany_ops_map (void) const 721 { 722 octave_scalar_map retval; 723 724 int len = std::min (static_cast<int> (assignany_ops.columns ()), num_types); 725 726 dim_vector tab_dims (1, len); 727 728 for (int j = 0; j < octave_value::num_assign_ops; j++) 729 { 730 boolNDArray tab (tab_dims); 731 732 for (int i = 0; i < len; i++) 733 tab.xelem (i) = (assignany_ops(j,i) != nullptr); 734 735 octave_value::assign_op op_id = static_cast<octave_value::assign_op> (j); 736 737 retval.setfield (octave_value::assign_op_as_string (op_id), tab); 738 } 739 740 return retval; 741 } 742 743 octave_scalar_map installed_type_info(void) const744 type_info::installed_type_info (void) const 745 { 746 octave_scalar_map retval; 747 748 retval.setfield ("types", octave_value (Cell (installed_type_names ()))); 749 retval.setfield ("unary_ops", unary_ops_map ()); 750 retval.setfield ("non_const_unary_ops", non_const_unary_ops_map ()); 751 retval.setfield ("binary_ops", binary_ops_map ()); 752 retval.setfield ("compound_binary_ops", compound_binary_ops_map ()); 753 retval.setfield ("cat_ops", as_bool_nd_array (cat_ops)); 754 retval.setfield ("assign_ops", assign_ops_map ()); 755 retval.setfield ("assignany_ops", assignany_ops_map ()); 756 retval.setfield ("pref_assign_conv", as_nd_array (pref_assign_conv)); 757 retval.setfield ("widening_ops", as_bool_nd_array (widening_ops)); 758 759 return retval; 760 } 761 } 762 763 namespace octave_value_typeinfo 764 { register_type(const std::string & t_name,const std::string & c_name,const octave_value & val)765 int register_type (const std::string& t_name, const std::string& c_name, 766 const octave_value& val) 767 { 768 octave::type_info& type_info 769 = octave::__get_type_info__ ("register_type"); 770 771 return type_info.register_type (t_name, c_name, val); 772 } 773 lookup_type(const std::string & nm)774 octave_value lookup_type (const std::string& nm) 775 { 776 octave::type_info& type_info 777 = octave::__get_type_info__ ("lookup_type"); 778 779 return type_info.lookup_type (nm); 780 } 781 lookup_unary_class_op(octave_value::unary_op op)782 unary_class_op_fcn lookup_unary_class_op (octave_value::unary_op op) 783 { 784 octave::type_info& type_info 785 = octave::__get_type_info__ ("lookup_unary_class_op"); 786 787 return type_info.lookup_unary_class_op (op); 788 } 789 lookup_unary_op(octave_value::unary_op op,int t)790 unary_op_fcn lookup_unary_op (octave_value::unary_op op, int t) 791 { 792 octave::type_info& type_info 793 = octave::__get_type_info__ ("lookup_unary_op"); 794 795 return type_info.lookup_unary_op (op, t); 796 } 797 798 non_const_unary_op_fcn lookup_non_const_unary_op(octave_value::unary_op op,int t)799 lookup_non_const_unary_op (octave_value::unary_op op, int t) 800 { 801 octave::type_info& type_info 802 = octave::__get_type_info__ ("lookup_non_const_unary_op"); 803 804 return type_info.lookup_non_const_unary_op (op, t); 805 } 806 807 binary_class_op_fcn lookup_binary_class_op(octave_value::binary_op op)808 lookup_binary_class_op (octave_value::binary_op op) 809 { 810 octave::type_info& type_info 811 = octave::__get_type_info__ ("lookup_binary_class_op"); 812 813 return type_info.lookup_binary_class_op (op); 814 } 815 816 binary_op_fcn lookup_binary_op(octave_value::binary_op op,int t1,int t2)817 lookup_binary_op (octave_value::binary_op op, int t1, int t2) 818 { 819 octave::type_info& type_info 820 = octave::__get_type_info__ ("lookup_binary_op"); 821 822 return type_info.lookup_binary_op (op, t1, t2); 823 } 824 825 binary_class_op_fcn lookup_binary_class_op(octave_value::compound_binary_op op)826 lookup_binary_class_op (octave_value::compound_binary_op op) 827 { 828 octave::type_info& type_info 829 = octave::__get_type_info__ ("lookup_binary_class_op"); 830 831 return type_info.lookup_binary_class_op (op); 832 } 833 834 binary_op_fcn lookup_binary_op(octave_value::compound_binary_op op,int t1,int t2)835 lookup_binary_op (octave_value::compound_binary_op op, int t1, int t2) 836 { 837 octave::type_info& type_info 838 = octave::__get_type_info__ ("lookup_binary_op"); 839 840 return type_info.lookup_binary_op (op, t1, t2); 841 } 842 lookup_cat_op(int t1,int t2)843 cat_op_fcn lookup_cat_op (int t1, int t2) 844 { 845 octave::type_info& type_info 846 = octave::__get_type_info__ ("lookup_cat_op"); 847 848 return type_info.lookup_cat_op (t1, t2); 849 } 850 851 assign_op_fcn lookup_assign_op(octave_value::assign_op op,int t_lhs,int t_rhs)852 lookup_assign_op (octave_value::assign_op op, int t_lhs, int t_rhs) 853 { 854 octave::type_info& type_info 855 = octave::__get_type_info__ ("lookup_assign_op"); 856 857 return type_info.lookup_assign_op (op, t_lhs, t_rhs); 858 } 859 860 assignany_op_fcn lookup_assignany_op(octave_value::assign_op op,int t_lhs)861 lookup_assignany_op (octave_value::assign_op op, int t_lhs) 862 { 863 octave::type_info& type_info 864 = octave::__get_type_info__ ("lookup_assignany_op"); 865 866 return type_info.lookup_assignany_op (op, t_lhs); 867 } 868 lookup_pref_assign_conv(int t_lhs,int t_rhs)869 int lookup_pref_assign_conv (int t_lhs, int t_rhs) 870 { 871 octave::type_info& type_info 872 = octave::__get_type_info__ ("lookup_pref_assign_conv"); 873 874 return type_info.lookup_pref_assign_conv (t_lhs, t_rhs); 875 } 876 877 octave_base_value::type_conv_fcn lookup_widening_op(int t,int t_result)878 lookup_widening_op (int t, int t_result) 879 { 880 octave::type_info& type_info 881 = octave::__get_type_info__ ("lookup_widening_op"); 882 883 return type_info.lookup_widening_op (t, t_result); 884 } 885 installed_type_names(void)886 string_vector installed_type_names (void) 887 { 888 octave::type_info& type_info 889 = octave::__get_type_info__ ("installed_type_names"); 890 891 return type_info.installed_type_names (); 892 } 893 installed_type_info(void)894 octave_scalar_map installed_type_info (void) 895 { 896 octave::type_info& type_info 897 = octave::__get_type_info__ ("installed_type_info"); 898 899 return type_info.installed_type_info (); 900 } 901 } 902 903 DEFMETHOD (typeinfo, interp, args, , 904 doc: /* -*- texinfo -*- 905 @deftypefn {} {} typeinfo () 906 @deftypefnx {} {} typeinfo (@var{expr}) 907 908 Return the type of the expression @var{expr}, as a string. 909 910 If @var{expr} is omitted, return a cell array of strings containing all the 911 currently installed data types. 912 @seealso{class, isa} 913 @end deftypefn */) 914 { 915 int nargin = args.length (); 916 917 if (nargin > 1) 918 print_usage (); 919 920 if (nargin == 0) 921 { 922 octave::type_info& type_info = interp.get_type_info (); 923 924 return ovl (Cell (type_info.installed_type_names ())); 925 } 926 else 927 return ovl (args(0).type_name ()); 928 } 929 930 /* 931 %!assert (iscellstr (typeinfo ())) 932 933 %!assert (typeinfo ({"cell"}), "cell") 934 935 %!assert (typeinfo (1), "scalar") 936 %!assert (typeinfo (double (1)), "scalar") 937 %!assert (typeinfo (i), "complex scalar") 938 939 %!assert (typeinfo ([1, 2]), "matrix") 940 %!assert (typeinfo (double ([1, 2])), "matrix") 941 %!assert (typeinfo (diag ([1, 2])), "diagonal matrix") 942 %!assert (typeinfo ([i, 2]), "complex matrix") 943 %!assert (typeinfo (diag ([i, 2])), "complex diagonal matrix") 944 945 %!assert (typeinfo (1:2), "range") 946 947 %!assert (typeinfo (false), "bool") 948 %!assert (typeinfo ([true, false]), "bool matrix") 949 950 %!assert (typeinfo ("string"), "string") 951 %!assert (typeinfo ('string'), "sq_string") 952 953 %!assert (typeinfo (int8 (1)), "int8 scalar") 954 %!assert (typeinfo (int16 (1)), "int16 scalar") 955 %!assert (typeinfo (int32 (1)), "int32 scalar") 956 %!assert (typeinfo (int64 (1)), "int64 scalar") 957 %!assert (typeinfo (uint8 (1)), "uint8 scalar") 958 %!assert (typeinfo (uint16 (1)), "uint16 scalar") 959 %!assert (typeinfo (uint32 (1)), "uint32 scalar") 960 %!assert (typeinfo (uint64 (1)), "uint64 scalar") 961 962 %!assert (typeinfo (int8 ([1,2])), "int8 matrix") 963 %!assert (typeinfo (int16 ([1,2])), "int16 matrix") 964 %!assert (typeinfo (int32 ([1,2])), "int32 matrix") 965 %!assert (typeinfo (int64 ([1,2])), "int64 matrix") 966 %!assert (typeinfo (uint8 ([1,2])), "uint8 matrix") 967 %!assert (typeinfo (uint16 ([1,2])), "uint16 matrix") 968 %!assert (typeinfo (uint32 ([1,2])), "uint32 matrix") 969 %!assert (typeinfo (uint64 ([1,2])), "uint64 matrix") 970 971 %!assert (typeinfo (sparse ([true, false])), "sparse bool matrix") 972 %!assert (typeinfo (logical (sparse (i * eye (10)))), "sparse bool matrix") 973 %!assert (typeinfo (sparse ([1,2])), "sparse matrix") 974 %!assert (typeinfo (sparse (eye (10))), "sparse matrix") 975 %!assert (typeinfo (sparse ([i,2])), "sparse complex matrix") 976 %!assert (typeinfo (sparse (i * eye (10))), "sparse complex matrix") 977 978 %!test 979 %! s(2).a = 1; 980 %! assert (typeinfo (s), "struct"); 981 982 %!test 983 %! s.a = 1; 984 %! assert (typeinfo (s), "scalar struct"); 985 986 ## FIXME: This doesn't work as a test for comma-separated list 987 %!#test 988 %! clist = {1, 2, 3}; 989 %! assert (typeinfo (clist{:}), "cs-list"); 990 991 %!assert (typeinfo (@sin), "function handle") 992 %!assert (typeinfo (@(x) x), "function handle") 993 994 %!assert (typeinfo (single (1)), "float scalar") 995 %!assert (typeinfo (single (i)), "float complex scalar") 996 %!assert (typeinfo (single ([1, 2])), "float matrix") 997 998 %!assert (typeinfo (single (diag ([1, 2]))), "float diagonal matrix") 999 %!assert (typeinfo (diag (single ([1, 2]))), "float diagonal matrix") 1000 %!assert (typeinfo (single (diag ([i, 2]))), "float complex diagonal matrix") 1001 %!assert (typeinfo (diag (single ([i, 2]))), "float complex diagonal matrix") 1002 1003 %!assert (typeinfo (eye(3)(:,[1 3 2])), "permutation matrix") 1004 %!test 1005 %! [l, u, p] = lu (rand (3)); 1006 %! assert (typeinfo (p), "permutation matrix"); 1007 1008 %!assert (typeinfo ([]), "null_matrix") 1009 %!assert (typeinfo (""), "null_string") 1010 %!assert (typeinfo (''), "null_sq_string") 1011 1012 %!test 1013 %! cvar = onCleanup (@() ""); 1014 %! assert (typeinfo (cvar), "onCleanup"); 1015 1016 %!testif HAVE_JAVA; usejava ("jvm") 1017 %! x = javaObject ("java.lang.StringBuffer"); 1018 %! assert (typeinfo (x), "octave_java"); 1019 1020 ## Test input validation 1021 %!error typeinfo ("foo", 1) 1022 */ 1023 1024 DEFMETHOD (__dump_typeinfo__, interp, args, , 1025 doc: /* -*- texinfo -*- 1026 @deftypefn {} {} __dump_typeinfo__ () 1027 Undocumented internal function. 1028 @end deftypefn */) 1029 { 1030 if (args.length () > 0) 1031 print_usage (); 1032 1033 octave::type_info& type_info = interp.get_type_info (); 1034 1035 return ovl (type_info.installed_type_info ()); 1036 } 1037