00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <iostream>
00029
00030 #include "Array-util.h"
00031 #include "byte-swap.h"
00032 #include "oct-locbuf.h"
00033 #include "lo-mappers.h"
00034
00035 #include "Cell.h"
00036 #include "defun.h"
00037 #include "error.h"
00038 #include "file-ops.h"
00039 #include "gripes.h"
00040 #include "load-path.h"
00041 #include "ls-hdf5.h"
00042 #include "ls-oct-ascii.h"
00043 #include "ls-oct-binary.h"
00044 #include "ls-utils.h"
00045 #include "oct-lvalue.h"
00046 #include "ov-class.h"
00047 #include "ov-fcn.h"
00048 #include "ov-usr-fcn.h"
00049 #include "pager.h"
00050 #include "parse.h"
00051 #include "pr-output.h"
00052 #include "toplev.h"
00053 #include "unwind-prot.h"
00054 #include "variables.h"
00055
00056 DEFINE_OCTAVE_ALLOCATOR(octave_class);
00057
00058 int octave_class::t_id (-1);
00059
00060 const std::string octave_class::t_name ("class");
00061
00062 void
00063 octave_class::register_type (void)
00064 {
00065 t_id = octave_value_typeinfo::register_type
00066 (octave_class::t_name, "<unknown>", octave_value (new octave_class ()));
00067 }
00068
00069 octave_class::octave_class (const octave_map& m, const std::string& id,
00070 const octave_value_list& parents)
00071 : octave_base_value (), map (m), c_name (id), obsolete_copies (0)
00072 {
00073 octave_idx_type n = parents.length ();
00074
00075 for (octave_idx_type idx = 0; idx < n; idx++)
00076 {
00077 octave_value parent = parents(idx);
00078
00079 if (! parent.is_object ())
00080 error ("parents must be objects");
00081 else
00082 {
00083 std::string pcnm = parent.class_name ();
00084
00085 if (find_parent_class (pcnm))
00086 error ("duplicate class in parent tree");
00087 else
00088 {
00089 parent_list.push_back (pcnm);
00090
00091 octave_idx_type nel = map.numel ();
00092 octave_idx_type p_nel = parent.numel ();
00093
00094 if (nel == 0)
00095 {
00096 if (p_nel == 0)
00097 {
00098
00099
00100
00101 map.assign (pcnm, Cell (map.dims ()));
00102 }
00103 else if (p_nel == 1)
00104 {
00105 if (map.nfields () == 0)
00106 {
00107
00108
00109
00110
00111
00112 map.resize (parent.dims ());
00113
00114 map.assign (pcnm, parent);
00115 }
00116 else
00117 {
00118
00119
00120
00121
00122 map.assign (pcnm, Cell (map.dims ()));
00123 }
00124 }
00125 else if (map.nfields () == 0)
00126 {
00127
00128
00129
00130
00131
00132
00133 dim_vector parent_dims = parent.dims ();
00134
00135 map.resize (parent_dims);
00136
00137 Cell c (parent_dims);
00138
00139 octave_map pmap = parent.map_value ();
00140
00141 std::list<std::string> plist
00142 = parent.parent_class_name_list ();
00143
00144 for (octave_idx_type i = 0; i < p_nel; i++)
00145 c(i) = octave_value (pmap.index(i), pcnm, plist);
00146
00147 map.assign (pcnm, c);
00148 }
00149 else
00150 error ("class: parent class dimension mismatch");
00151 }
00152 else if (nel == 1 && p_nel == 1)
00153 {
00154
00155
00156 map.assign (pcnm, parent);
00157 }
00158 else
00159 {
00160 if (p_nel == 1)
00161 {
00162
00163
00164
00165 Cell pcell (map.dims (), parent);
00166
00167 map.assign (pcnm, pcell);
00168 }
00169
00170 else if (nel == p_nel)
00171 {
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 Cell c (parent.dims ());
00183
00184 octave_map pmap = parent.map_value ();
00185
00186 std::list<std::string> plist
00187 = parent.parent_class_name_list ();
00188
00189 for (octave_idx_type i = 0; i < p_nel; i++)
00190 c(i) = octave_value (pmap.index(i), pcnm, plist);
00191
00192 map.assign (pcnm, c);
00193 }
00194 else
00195 error ("class: parent class dimension mismatch");
00196 }
00197 }
00198 }
00199 }
00200
00201 if (! error_state)
00202 symbol_table::add_to_parent_map (id, parent_list);
00203 }
00204
00205 octave_base_value *
00206 octave_class::unique_clone (void)
00207 {
00208 if (count == obsolete_copies)
00209 {
00210
00211 count++;
00212 return this;
00213 }
00214 else
00215 {
00216
00217 if (count < obsolete_copies)
00218 obsolete_copies = 0;
00219
00220 return clone ();
00221 }
00222 }
00223
00224 std::string
00225 octave_class::get_current_method_class (void)
00226 {
00227 std::string retval = class_name ();
00228
00229 if (nparents () > 0)
00230 {
00231 octave_function *fcn = octave_call_stack::current ();
00232
00233
00234
00235 if (fcn && (fcn->is_class_method () || fcn->is_class_constructor ()))
00236 retval = fcn->dispatch_class ();
00237 }
00238
00239 return retval;
00240 }
00241
00242 static void
00243 gripe_invalid_index1 (void)
00244 {
00245 error ("invalid index for class");
00246 }
00247
00248 static void
00249 gripe_invalid_index_for_assignment (void)
00250 {
00251 error ("invalid index for class assignment");
00252 }
00253
00254 static void
00255 gripe_invalid_index_type (const std::string& nm, char t)
00256 {
00257 error ("%s cannot be indexed with %c", nm.c_str (), t);
00258 }
00259
00260 static void
00261 gripe_failed_assignment (void)
00262 {
00263 error ("assignment to class element failed");
00264 }
00265
00266 static inline octave_value_list
00267 sanitize (const octave_value_list& ovl)
00268 {
00269 octave_value_list retval = ovl;
00270
00271 for (octave_idx_type i = 0; i < ovl.length (); i++)
00272 {
00273 if (retval(i).is_magic_colon ())
00274 retval(i) = ":";
00275 }
00276
00277 return retval;
00278 }
00279
00280 static inline octave_value
00281 make_idx_args (const std::string& type,
00282 const std::list<octave_value_list>& idx,
00283 const std::string& who)
00284 {
00285 octave_value retval;
00286
00287 size_t len = type.length ();
00288
00289 if (len == idx.size ())
00290 {
00291 Cell type_field (1, len);
00292 Cell subs_field (1, len);
00293
00294 std::list<octave_value_list>::const_iterator p = idx.begin ();
00295
00296 for (size_t i = 0; i < len; i++)
00297 {
00298 char t = type[i];
00299
00300 switch (t)
00301 {
00302 case '(':
00303 type_field(i) = "()";
00304 subs_field(i) = Cell (sanitize (*p++));
00305 break;
00306
00307 case '{':
00308 type_field(i) = "{}";
00309 subs_field(i) = Cell (sanitize (*p++));
00310 break;
00311
00312 case '.':
00313 {
00314 type_field(i) = ".";
00315
00316 octave_value_list vlist = *p++;
00317
00318 if (vlist.length () == 1)
00319 {
00320 octave_value val = vlist(0);
00321
00322 if (val.is_string ())
00323 subs_field(i) = val;
00324 else
00325 {
00326 error ("expecting character string argument for '.' index");
00327 return retval;
00328 }
00329 }
00330 else
00331 {
00332 error ("expecting single argument for '.' index");
00333 return retval;
00334 }
00335 }
00336 break;
00337
00338 default:
00339 panic_impossible ();
00340 break;
00341 }
00342 }
00343
00344 octave_map m;
00345
00346 m.assign ("type", type_field);
00347 m.assign ("subs", subs_field);
00348
00349 retval = m;
00350 }
00351 else
00352 error ("invalid index for %s", who.c_str ());
00353
00354 return retval;
00355 }
00356
00357 Cell
00358 octave_class::dotref (const octave_value_list& idx)
00359 {
00360 Cell retval;
00361
00362 assert (idx.length () == 1);
00363
00364 std::string method_class = get_current_method_class ();
00365
00366
00367
00368
00369 octave_base_value *obvp = find_parent_class (method_class);
00370
00371 if (obvp == 0)
00372 {
00373 error ("malformed class");
00374 return retval;
00375 }
00376
00377 octave_map my_map = (obvp != this) ? obvp->map_value () : map;
00378
00379 std::string nm = idx(0).string_value ();
00380
00381 if (! error_state)
00382 {
00383 octave_map::const_iterator p = my_map.seek (nm);
00384
00385 if (p != my_map.end ())
00386 retval = my_map.contents (p);
00387 else
00388 error ("class has no member '%s'", nm.c_str ());
00389 }
00390 else
00391 gripe_invalid_index1 ();
00392
00393 return retval;
00394 }
00395
00396 static bool
00397 called_from_builtin (void)
00398 {
00399 octave_function *fcn = octave_call_stack::caller ();
00400
00401
00402
00403
00404
00405
00406
00407 return (fcn && fcn->name () == "builtin");
00408 }
00409
00410 Matrix
00411 octave_class::size (void)
00412 {
00413 if (in_class_method () || called_from_builtin ())
00414 return octave_base_value::size ();
00415
00416 Matrix retval (1, 2, 1.0);
00417 octave_value meth = symbol_table::find_method ("size", class_name ());
00418
00419 if (meth.is_defined ())
00420 {
00421 count++;
00422 octave_value_list args (1, octave_value (this));
00423
00424 octave_value_list lv = feval (meth.function_value (), args, 1);
00425 if (lv.length () > 0 && lv(0).is_matrix_type () && lv(0).dims ().is_vector ())
00426 retval = lv(0).matrix_value ();
00427 else
00428 error ("@%s/size: invalid return value", class_name ().c_str ());
00429 }
00430 else
00431 {
00432 dim_vector dv = dims ();
00433
00434 int nd = dv.length ();
00435
00436 retval.resize (1, nd);
00437
00438 for (int i = 0; i < nd; i++)
00439 retval(i) = dv(i);
00440 }
00441
00442 return retval;
00443 }
00444
00445 octave_idx_type
00446 octave_class::numel (const octave_value_list& idx)
00447 {
00448 if (in_class_method () || called_from_builtin ())
00449 return octave_base_value::numel (idx);
00450
00451 octave_idx_type retval = -1;
00452 const std::string cn = class_name ();
00453
00454 octave_value meth = symbol_table::find_method ("numel", cn);
00455
00456 if (meth.is_defined ())
00457 {
00458 octave_value_list args (idx.length () + 1, octave_value ());
00459
00460 count++;
00461 args(0) = octave_value (this);
00462
00463 for (octave_idx_type i = 0; i < idx.length (); i++)
00464 args(i+1) = idx(i);
00465
00466 octave_value_list lv = feval (meth.function_value (), args, 1);
00467 if (lv.length () == 1 && lv(0).is_scalar_type ())
00468 retval = lv(0).idx_type_value (true);
00469 else
00470 error ("@%s/numel: invalid return value", cn.c_str ());
00471 }
00472 else
00473 retval = octave_base_value::numel (idx);
00474
00475 return retval;
00476 }
00477
00478 octave_value_list
00479 octave_class::subsref (const std::string& type,
00480 const std::list<octave_value_list>& idx,
00481 int nargout)
00482 {
00483 octave_value_list retval;
00484
00485 if (in_class_method () || called_from_builtin ())
00486 {
00487
00488
00489
00490
00491 int skip = 1;
00492
00493 switch (type[0])
00494 {
00495 case '(':
00496 {
00497 if (type.length () > 1 && type[1] == '.')
00498 {
00499 std::list<octave_value_list>::const_iterator p = idx.begin ();
00500 octave_value_list key_idx = *++p;
00501
00502 Cell tmp = dotref (key_idx);
00503
00504 if (! error_state)
00505 {
00506 Cell t = tmp.index (idx.front ());
00507
00508 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
00509
00510
00511
00512
00513 skip++;
00514 }
00515 }
00516 else
00517 retval(0) = octave_value (map.index (idx.front ()),
00518 c_name, parent_list);
00519 }
00520 break;
00521
00522 case '.':
00523 {
00524 if (map.numel() > 0)
00525 {
00526 Cell t = dotref (idx.front ());
00527
00528 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
00529 }
00530 }
00531 break;
00532
00533 case '{':
00534 gripe_invalid_index_type (type_name (), type[0]);
00535 break;
00536
00537 default:
00538 panic_impossible ();
00539 }
00540
00541
00542
00543
00544
00545 if (idx.size () > 1)
00546 retval = retval(0).next_subsref (nargout, type, idx, skip);
00547 }
00548 else
00549 {
00550 octave_value meth = symbol_table::find_method ("subsref", class_name ());
00551
00552 if (meth.is_defined ())
00553 {
00554 octave_value_list args;
00555
00556 args(1) = make_idx_args (type, idx, "subsref");
00557
00558 if (error_state)
00559 return octave_value_list ();
00560
00561 count++;
00562 args(0) = octave_value (this);
00563
00564
00565
00566
00567
00568
00569 bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
00570 || (type.length () > 1 && type[0] == '('
00571 && type[1] == '.'));
00572
00573 int true_nargout = nargout;
00574
00575 if (maybe_cs_list_query)
00576 {
00577
00578 octave_value_list tmp;
00579 if (type[0] != '.') tmp = idx.front ();
00580 true_nargout = numel (tmp);
00581 }
00582
00583 retval = feval (meth.function_value (), args, true_nargout);
00584
00585
00586
00587
00588 if (retval.length () > 1)
00589 retval = octave_value (retval, true);
00590 }
00591 else
00592 {
00593 if (type.length () == 1 && type[0] == '(')
00594 retval(0) = octave_value (map.index (idx.front ()), c_name,
00595 parent_list);
00596 else
00597 gripe_invalid_index1 ();
00598 }
00599 }
00600
00601 return retval;
00602 }
00603
00604 octave_value
00605 octave_class::numeric_conv (const Cell& val, const std::string& type)
00606 {
00607 octave_value retval;
00608
00609 if (val.length () == 1)
00610 {
00611 retval = val(0);
00612
00613 if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
00614 retval = octave_map ();
00615 }
00616 else
00617 gripe_invalid_index_for_assignment ();
00618
00619 return retval;
00620 }
00621
00622 octave_value
00623 octave_class::subsasgn (const std::string& type,
00624 const std::list<octave_value_list>& idx,
00625 const octave_value& rhs)
00626 {
00627 count++;
00628 return subsasgn_common (octave_value (this), type, idx, rhs);
00629 }
00630
00631 octave_value
00632 octave_class::undef_subsasgn (const std::string& type,
00633 const std::list<octave_value_list>& idx,
00634 const octave_value& rhs)
00635 {
00636
00637
00638
00639
00640 return subsasgn_common (Matrix (), type, idx, rhs);
00641 }
00642
00643 octave_value
00644 octave_class::subsasgn_common (const octave_value& obj,
00645 const std::string& type,
00646 const std::list<octave_value_list>& idx,
00647 const octave_value& rhs)
00648 {
00649 octave_value retval;
00650
00651 if (! (in_class_method () || called_from_builtin ()))
00652 {
00653 octave_value meth = symbol_table::find_method ("subsasgn", class_name ());
00654
00655 if (meth.is_defined ())
00656 {
00657 octave_value_list args;
00658
00659 if (rhs.is_cs_list ())
00660 {
00661 octave_value_list lrhs = rhs.list_value ();
00662 args.resize (2 + lrhs.length ());
00663 for (octave_idx_type i = 0; i < lrhs.length (); i++)
00664 args(2+i) = lrhs(i);
00665 }
00666 else
00667 args(2) = rhs;
00668
00669 args(1) = make_idx_args (type, idx, "subsasgn");
00670
00671 if (error_state)
00672 return octave_value_list ();
00673
00674 args(0) = obj;
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 octave_value_list tmp;
00690
00691 if (obsolete_copies == 0 && meth.is_user_function ()
00692 && meth.user_function_value ()->subsasgn_optimization_ok ())
00693 {
00694 unwind_protect frame;
00695 frame.protect_var (obsolete_copies);
00696 obsolete_copies = 2;
00697
00698 tmp = feval (meth.function_value (), args);
00699 }
00700 else
00701 tmp = feval (meth.function_value (), args);
00702
00703
00704
00705
00706 if (tmp.length () > 1)
00707 error ("expecting single return value from @%s/subsasgn",
00708 class_name().c_str ());
00709
00710 else
00711 retval = tmp(0);
00712
00713 return retval;
00714 }
00715 }
00716
00717
00718
00719
00720 std::string method_class = get_current_method_class ();
00721
00722 octave_base_value *obvp = unique_parent_class (method_class);
00723 if (obvp != this)
00724 {
00725
00726 if (obvp)
00727 {
00728 obvp->subsasgn (type, idx, rhs);
00729 if (! error_state)
00730 {
00731 count++;
00732 retval = octave_value (this);
00733 }
00734 else
00735 gripe_failed_assignment ();
00736 }
00737 else
00738 error ("malformed class");
00739
00740 return retval;
00741 }
00742
00743
00744
00745
00746
00747 int n = type.length ();
00748
00749 octave_value t_rhs = rhs;
00750
00751 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
00752 {
00753 switch (type[0])
00754 {
00755 case '(':
00756 {
00757 if (type.length () > 1 && type[1] == '.')
00758 {
00759 std::list<octave_value_list>::const_iterator p = idx.begin ();
00760 octave_value_list t_idx = *p;
00761
00762 octave_value_list key_idx = *++p;
00763
00764 assert (key_idx.length () == 1);
00765
00766 std::string key = key_idx(0).string_value ();
00767
00768 if (! error_state)
00769 {
00770 octave_value u;
00771
00772 if (! map.contains (key))
00773 u = octave_value::empty_conv (type.substr (2), rhs);
00774 else
00775 {
00776 Cell map_val = map.contents (key);
00777
00778 Cell map_elt = map_val.index (idx.front (), true);
00779
00780 u = numeric_conv (map_elt, type.substr (2));
00781 }
00782
00783 if (! error_state)
00784 {
00785 std::list<octave_value_list> next_idx (idx);
00786
00787
00788
00789
00790 next_idx.erase (next_idx.begin ());
00791 next_idx.erase (next_idx.begin ());
00792
00793 u.make_unique ();
00794
00795 t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
00796 }
00797 }
00798 else
00799 gripe_invalid_index_for_assignment ();
00800 }
00801 else
00802 gripe_invalid_index_for_assignment ();
00803 }
00804 break;
00805
00806 case '.':
00807 {
00808 octave_value_list key_idx = idx.front ();
00809
00810 assert (key_idx.length () == 1);
00811
00812 std::string key = key_idx(0).string_value ();
00813
00814 std::list<octave_value_list> next_idx (idx);
00815
00816 next_idx.erase (next_idx.begin ());
00817
00818 std::string next_type = type.substr (1);
00819
00820 Cell tmpc (1, 1);
00821 octave_map::iterator pkey = map.seek (key);
00822 if (pkey != map.end ())
00823 {
00824 map.contents (pkey).make_unique ();
00825 tmpc = map.contents (pkey);
00826 }
00827
00828
00829 if (! error_state)
00830 {
00831 if (tmpc.numel () == 1)
00832 {
00833 octave_value& tmp = tmpc(0);
00834
00835 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
00836 {
00837 tmp = octave_value::empty_conv (next_type, rhs);
00838 tmp.make_unique ();
00839 }
00840 else
00841
00842 tmp.make_unique (1);
00843
00844 if (! error_state)
00845 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
00846 }
00847 else
00848 gripe_indexed_cs_list ();
00849 }
00850 }
00851 break;
00852
00853 case '{':
00854 gripe_invalid_index_type (type_name (), type[0]);
00855 break;
00856
00857 default:
00858 panic_impossible ();
00859 }
00860 }
00861
00862 if (! error_state)
00863 {
00864 switch (type[0])
00865 {
00866 case '(':
00867 {
00868 if (n > 1 && type[1] == '.')
00869 {
00870 std::list<octave_value_list>::const_iterator p = idx.begin ();
00871 octave_value_list key_idx = *++p;
00872
00873 assert (key_idx.length () == 1);
00874
00875 std::string key = key_idx(0).string_value ();
00876
00877 if (! error_state)
00878 {
00879 map.assign (idx.front (), key, t_rhs);
00880
00881 if (! error_state)
00882 {
00883 count++;
00884 retval = octave_value (this);
00885 }
00886 else
00887 gripe_failed_assignment ();
00888 }
00889 else
00890 gripe_failed_assignment ();
00891 }
00892 else
00893 {
00894 if (t_rhs.is_object () || t_rhs.is_map ())
00895 {
00896 octave_map rhs_map = t_rhs.map_value ();
00897
00898 if (! error_state)
00899 {
00900 map.assign (idx.front (), rhs_map);
00901
00902 if (! error_state)
00903 {
00904 count++;
00905 retval = octave_value (this);
00906 }
00907 else
00908 gripe_failed_assignment ();
00909 }
00910 else
00911 error ("invalid class assignment");
00912 }
00913 else
00914 {
00915 if (t_rhs.is_empty ())
00916 {
00917 map.delete_elements (idx.front());
00918
00919 if (! error_state)
00920 {
00921 count++;
00922 retval = octave_value (this);
00923 }
00924 else
00925 gripe_failed_assignment ();
00926 }
00927 else
00928 error ("invalid class assignment");
00929 }
00930 }
00931 }
00932 break;
00933
00934 case '.':
00935 {
00936 octave_value_list key_idx = idx.front ();
00937
00938 assert (key_idx.length () == 1);
00939
00940 std::string key = key_idx(0).string_value ();
00941
00942 if (t_rhs.is_cs_list ())
00943 {
00944 Cell tmp_cell = Cell (t_rhs.list_value ());
00945
00946
00947
00948
00949
00950 if (numel () == tmp_cell.numel ())
00951 tmp_cell = tmp_cell.reshape (dims ());
00952
00953 map.setfield (key, tmp_cell);
00954 }
00955 else
00956 {
00957 Cell tmp_cell(1, 1);
00958 tmp_cell(0) = t_rhs.storable_value ();
00959 map.setfield (key, tmp_cell);
00960 }
00961
00962 if (! error_state)
00963 {
00964 count++;
00965 retval = octave_value (this);
00966 }
00967 else
00968 gripe_failed_assignment ();
00969 }
00970 break;
00971
00972 case '{':
00973 gripe_invalid_index_type (type_name (), type[0]);
00974 break;
00975
00976 default:
00977 panic_impossible ();
00978 }
00979 }
00980 else
00981 gripe_failed_assignment ();
00982
00983 return retval;
00984 }
00985
00986 idx_vector
00987 octave_class::index_vector (void) const
00988 {
00989 idx_vector retval;
00990
00991 octave_value meth = symbol_table::find_method ("subsindex", class_name ());
00992
00993 if (meth.is_defined ())
00994 {
00995 octave_value_list args;
00996 args(0) = octave_value (new octave_class (map, c_name, parent_list));
00997
00998 octave_value_list tmp = feval (meth.function_value (), args, 1);
00999
01000 if (!error_state && tmp.length () >= 1)
01001 {
01002 if (tmp(0).is_object())
01003 error ("subsindex function must return a valid index vector");
01004 else
01005
01006
01007
01008
01009 retval = do_binary_op (octave_value::op_add, tmp (0),
01010 octave_value (1.0)).index_vector ();
01011 }
01012 }
01013 else
01014 error ("no subsindex method defined for class %s",
01015 class_name().c_str ());
01016
01017 return retval;
01018 }
01019
01020 size_t
01021 octave_class::byte_size (void) const
01022 {
01023
01024
01025 size_t retval = 0;
01026
01027 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
01028 {
01029 std::string key = map.key (p);
01030
01031 octave_value val = octave_value (map.contents (p));
01032
01033 retval += val.byte_size ();
01034 }
01035
01036 return retval;
01037 }
01038
01039 string_vector
01040 octave_class::map_keys (void) const
01041 {
01042 string_vector retval;
01043 gripe_wrong_type_arg ("octave_class::map_keys()", type_name ());
01044 return retval;
01045 }
01046
01047 octave_base_value *
01048 octave_class::find_parent_class (const std::string& parent_class_name)
01049 {
01050 octave_base_value* retval = 0;
01051
01052 if (parent_class_name == class_name ())
01053 retval = this;
01054 else
01055 {
01056 for (std::list<std::string>::iterator pit = parent_list.begin ();
01057 pit != parent_list.end ();
01058 pit++)
01059 {
01060 octave_map::const_iterator smap = map.seek (*pit);
01061
01062 const Cell& tmp = map.contents (smap);
01063
01064 octave_value vtmp = tmp(0);
01065
01066 octave_base_value *obvp = vtmp.internal_rep ();
01067
01068 retval = obvp->find_parent_class (parent_class_name);
01069
01070 if (retval)
01071 break;
01072 }
01073 }
01074
01075 return retval;
01076 }
01077
01078 octave_base_value *
01079 octave_class::unique_parent_class (const std::string& parent_class_name)
01080 {
01081 octave_base_value* retval = 0;
01082
01083 if (parent_class_name == class_name ())
01084 retval = this;
01085 else
01086 {
01087 for (std::list<std::string>::iterator pit = parent_list.begin ();
01088 pit != parent_list.end ();
01089 pit++)
01090 {
01091 octave_map::iterator smap = map.seek (*pit);
01092
01093 Cell& tmp = map.contents (smap);
01094
01095 octave_value& vtmp = tmp(0);
01096
01097 octave_base_value *obvp = vtmp.internal_rep ();
01098
01099
01100 retval = obvp->find_parent_class (parent_class_name);
01101
01102 if (retval)
01103 {
01104 vtmp.make_unique ();
01105 obvp = vtmp.internal_rep ();
01106 retval = obvp->unique_parent_class (parent_class_name);
01107
01108 break;
01109 }
01110 }
01111 }
01112
01113 return retval;
01114 }
01115
01116 string_vector
01117 octave_class::all_strings (bool pad) const
01118 {
01119 string_vector retval;
01120
01121 octave_value meth = symbol_table::find_method ("char", class_name ());
01122
01123 if (meth.is_defined ())
01124 {
01125 octave_value_list args;
01126 args(0) = octave_value (new octave_class (map, c_name, parent_list));
01127
01128 octave_value_list tmp = feval (meth.function_value (), args, 1);
01129
01130 if (!error_state && tmp.length () >= 1)
01131 {
01132 if (tmp(0).is_string ())
01133 retval = tmp(0).all_strings (pad);
01134 else
01135 error ("cname/char method did not return a character string");
01136 }
01137 }
01138 else
01139 error ("no char method defined for class %s", class_name().c_str ());
01140
01141 return retval;
01142 }
01143
01144
01145 void
01146 octave_class::print (std::ostream& os, bool) const
01147 {
01148 print_raw (os);
01149 }
01150
01151 void
01152 octave_class::print_raw (std::ostream& os, bool) const
01153 {
01154 unwind_protect frame;
01155
01156 indent (os);
01157 os << " <class " << class_name () << ">";
01158 newline (os);
01159 }
01160
01161 bool
01162 octave_class::print_name_tag (std::ostream& os, const std::string& name) const
01163 {
01164 bool retval = false;
01165
01166 indent (os);
01167 os << name << " =";
01168 newline (os);
01169 if (! Vcompact_format)
01170 newline (os);
01171
01172 return retval;
01173 }
01174
01175 void
01176 octave_class::print_with_name (std::ostream& os, const std::string& name,
01177 bool)
01178 {
01179 octave_value fcn = symbol_table::find_method ("display", class_name ());
01180
01181 if (fcn.is_defined ())
01182 {
01183 octave_value_list args;
01184
01185 count++;
01186 args(0) = octave_value (this);
01187
01188 string_vector arg_names (1);
01189
01190 arg_names[0] = name;
01191
01192 args.stash_name_tags (arg_names);
01193
01194 feval (fcn.function_value (), args);
01195 }
01196 else
01197 {
01198 indent (os);
01199 os << name << " = <class " << class_name () << ">";
01200 newline (os);
01201 }
01202 }
01203
01204
01205
01206
01207 bool
01208 octave_class::reconstruct_exemplar (void)
01209 {
01210 bool retval = false;
01211
01212 octave_class::exemplar_const_iterator it
01213 = octave_class::exemplar_map.find (c_name);
01214
01215 if (it != octave_class::exemplar_map.end ())
01216 retval = true;
01217 else
01218 {
01219 octave_value ctor = symbol_table::find_method (c_name, c_name);
01220
01221 bool have_ctor = false;
01222
01223 if (ctor.is_defined () && ctor.is_function ())
01224 {
01225 octave_function *fcn = ctor.function_value ();
01226
01227 if (fcn && fcn->is_class_constructor (c_name))
01228 have_ctor = true;
01229
01230
01231
01232
01233 assert (have_ctor);
01234 }
01235
01236 if (have_ctor)
01237 {
01238 octave_value_list result
01239 = ctor.do_multi_index_op (1, octave_value_list ());
01240
01241 if (result.length () == 1)
01242 retval = true;
01243 else
01244 warning ("call to constructor for class %s failed", c_name.c_str ());
01245 }
01246 else
01247 warning ("no constructor for class %s", c_name.c_str ());
01248 }
01249
01250 return retval;
01251 }
01252
01253 void
01254 octave_class::clear_exemplar_map (void)
01255 {
01256 exemplar_map.clear ();
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266 bool
01267 octave_class::reconstruct_parents (void)
01268 {
01269 bool retval = true, might_have_inheritance = false;
01270 std::string dbgstr = "dork";
01271
01272
01273 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
01274 {
01275 std::string key = map.key (p);
01276 Cell val = map.contents (p);
01277 if ( val(0).is_object() )
01278 {
01279 dbgstr = "blork";
01280 if( key == val(0).class_name() )
01281 {
01282 might_have_inheritance = true;
01283 dbgstr = "cork";
01284 break;
01285 }
01286 }
01287 }
01288
01289 if (might_have_inheritance)
01290 {
01291 octave_class::exemplar_const_iterator it
01292 = octave_class::exemplar_map.find (c_name);
01293
01294 if (it == octave_class::exemplar_map.end ())
01295 retval = false;
01296 else
01297 {
01298 octave_class::exemplar_info exmplr = it->second;
01299 parent_list = exmplr.parents ();
01300 for (std::list<std::string>::iterator pit = parent_list.begin ();
01301 pit != parent_list.end ();
01302 pit++)
01303 {
01304 dbgstr = *pit;
01305 bool dbgbool = map.contains (*pit);
01306 if (!dbgbool)
01307 {
01308 retval = false;
01309 break;
01310 }
01311 }
01312 }
01313 }
01314
01315 return retval;
01316 }
01317
01318 bool
01319 octave_class::save_ascii (std::ostream& os)
01320 {
01321 os << "# classname: " << class_name () << "\n";
01322 octave_map m;
01323 if (load_path::find_method (class_name (), "saveobj") != std::string ())
01324 {
01325 octave_value in = new octave_class (*this);
01326 octave_value_list tmp = feval ("saveobj", in, 1);
01327 if (! error_state)
01328 m = tmp(0).map_value ();
01329 else
01330 return false;
01331 }
01332 else
01333 m = map_value ();
01334
01335 os << "# length: " << m.nfields () << "\n";
01336
01337 octave_map::iterator i = m.begin ();
01338 while (i != m.end ())
01339 {
01340 octave_value val = map.contents (i);
01341
01342 bool b = save_ascii_data (os, val, m.key (i), false, 0);
01343
01344 if (! b)
01345 return os;
01346
01347 i++;
01348 }
01349
01350 return true;
01351 }
01352
01353 bool
01354 octave_class::load_ascii (std::istream& is)
01355 {
01356 octave_idx_type len = 0;
01357 std::string classname;
01358 bool success = true;
01359
01360 if (extract_keyword (is, "classname", classname) && classname != "")
01361 {
01362 if (extract_keyword (is, "length", len) && len >= 0)
01363 {
01364 if (len > 0)
01365 {
01366 octave_map m (map);
01367
01368 for (octave_idx_type j = 0; j < len; j++)
01369 {
01370 octave_value t2;
01371 bool dummy;
01372
01373
01374 std::string nm
01375 = read_ascii_data (is, std::string (), dummy, t2, j);
01376
01377 if (! is)
01378 break;
01379
01380 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
01381
01382 if (error_state)
01383 {
01384 error ("load: internal error loading class elements");
01385 return false;
01386 }
01387
01388 m.assign (nm, tcell);
01389 }
01390
01391 if (is)
01392 {
01393 c_name = classname;
01394 reconstruct_exemplar ();
01395
01396 map = m;
01397
01398 if (! reconstruct_parents ())
01399 warning ("load: unable to reconstruct object inheritance");
01400 else
01401 {
01402 if (load_path::find_method (classname, "loadobj")
01403 != std::string ())
01404 {
01405 octave_value in = new octave_class (*this);
01406 octave_value_list tmp = feval ("loadobj", in, 1);
01407
01408 if (! error_state)
01409 map = tmp(0).map_value ();
01410 else
01411 success = false;
01412 }
01413 }
01414 }
01415 else
01416 {
01417 error ("load: failed to load class");
01418 success = false;
01419 }
01420 }
01421 else if (len == 0 )
01422 {
01423 map = octave_map (dim_vector (1, 1));
01424 c_name = classname;
01425 }
01426 else
01427 panic_impossible ();
01428 }
01429 else
01430 {
01431 error ("load: failed to extract number of elements in class");
01432 success = false;
01433 }
01434 }
01435 else
01436 {
01437 error ("load: failed to extract name of class");
01438 success = false;
01439 }
01440
01441 return success;
01442 }
01443
01444 bool
01445 octave_class::save_binary (std::ostream& os, bool& save_as_floats)
01446 {
01447 int32_t classname_len = class_name().length ();
01448
01449 os.write (reinterpret_cast<char *> (&classname_len), 4);
01450 os << class_name ();
01451
01452 octave_map m;
01453 if (load_path::find_method (class_name (), "saveobj") != std::string ())
01454 {
01455 octave_value in = new octave_class (*this);
01456 octave_value_list tmp = feval ("saveobj", in, 1);
01457 if (! error_state)
01458 m = tmp(0).map_value ();
01459 else
01460 return false;
01461 }
01462 else
01463 m = map_value ();
01464
01465 int32_t len = m.nfields();
01466 os.write (reinterpret_cast<char *> (&len), 4);
01467
01468 octave_map::iterator i = m.begin ();
01469 while (i != m.end ())
01470 {
01471 octave_value val = map.contents (i);
01472
01473 bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
01474
01475 if (! b)
01476 return os;
01477
01478 i++;
01479 }
01480
01481 return true;
01482 }
01483
01484 bool
01485 octave_class::load_binary (std::istream& is, bool swap,
01486 oct_mach_info::float_format fmt)
01487 {
01488 bool success = true;
01489
01490 int32_t classname_len;
01491
01492 is.read (reinterpret_cast<char *> (&classname_len), 4);
01493 if (! is)
01494 return false;
01495 else if (swap)
01496 swap_bytes<4> (&classname_len);
01497
01498 {
01499 OCTAVE_LOCAL_BUFFER (char, classname, classname_len+1);
01500 classname[classname_len] = '\0';
01501 if (! is.read (reinterpret_cast<char *> (classname), classname_len))
01502 return false;
01503 c_name = classname;
01504 }
01505 reconstruct_exemplar ();
01506
01507 int32_t len;
01508 if (! is.read (reinterpret_cast<char *> (&len), 4))
01509 return false;
01510 if (swap)
01511 swap_bytes<4> (&len);
01512
01513 if (len > 0)
01514 {
01515 octave_map m (map);
01516
01517 for (octave_idx_type j = 0; j < len; j++)
01518 {
01519 octave_value t2;
01520 bool dummy;
01521 std::string doc;
01522
01523
01524 std::string nm = read_binary_data (is, swap, fmt, std::string (),
01525 dummy, t2, doc);
01526
01527 if (! is)
01528 break;
01529
01530 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
01531
01532 if (error_state)
01533 {
01534 error ("load: internal error loading class elements");
01535 return false;
01536 }
01537
01538 m.assign (nm, tcell);
01539 }
01540
01541 if (is)
01542 {
01543 map = m;
01544
01545 if (! reconstruct_parents ())
01546 warning ("load: unable to reconstruct object inheritance");
01547 else
01548 {
01549 if (load_path::find_method (c_name, "loadobj") != std::string ())
01550 {
01551 octave_value in = new octave_class (*this);
01552 octave_value_list tmp = feval ("loadobj", in, 1);
01553
01554 if (! error_state)
01555 map = tmp(0).map_value ();
01556 else
01557 success = false;
01558 }
01559 }
01560 }
01561 else
01562 {
01563 warning ("load: failed to load class");
01564 success = false;
01565 }
01566 }
01567 else if (len == 0 )
01568 map = octave_map (dim_vector (1, 1));
01569 else
01570 panic_impossible ();
01571
01572 return success;
01573 }
01574
01575 #if defined (HAVE_HDF5)
01576
01577 bool
01578 octave_class::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
01579 {
01580 hsize_t hdims[3];
01581 hid_t group_hid = -1;
01582 hid_t type_hid = -1;
01583 hid_t space_hid = -1;
01584 hid_t class_hid = -1;
01585 hid_t data_hid = -1;
01586 octave_map m;
01587 octave_map::iterator i;
01588
01589 #if HAVE_HDF5_18
01590 group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01591 #else
01592 group_hid = H5Gcreate (loc_id, name, 0);
01593 #endif
01594 if (group_hid < 0)
01595 goto error_cleanup;
01596
01597
01598 type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, c_name.length () + 1);
01599 if (type_hid < 0)
01600 goto error_cleanup;
01601
01602 hdims[0] = 0;
01603 space_hid = H5Screate_simple (0 , hdims, 0);
01604 if (space_hid < 0)
01605 goto error_cleanup;
01606 #if HAVE_HDF5_18
01607 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
01608 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01609 #else
01610 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
01611 H5P_DEFAULT);
01612 #endif
01613 if (class_hid < 0 || H5Dwrite (class_hid, type_hid, H5S_ALL, H5S_ALL,
01614 H5P_DEFAULT, c_name.c_str ()) < 0)
01615 goto error_cleanup;
01616
01617 #if HAVE_HDF5_18
01618 data_hid = H5Gcreate (group_hid, "value", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01619 #else
01620 data_hid = H5Gcreate (group_hid, "value", 0);
01621 #endif
01622 if (data_hid < 0)
01623 goto error_cleanup;
01624
01625 if (load_path::find_method (class_name (), "saveobj") != std::string ())
01626 {
01627 octave_value in = new octave_class (*this);
01628 octave_value_list tmp = feval ("saveobj", in, 1);
01629 if (! error_state)
01630 m = tmp(0).map_value ();
01631 else
01632 goto error_cleanup;
01633 }
01634 else
01635 m = map_value ();
01636
01637
01638 i = m.begin ();
01639 while (i != m.end ())
01640 {
01641 octave_value val = map.contents (i);
01642
01643 bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false,
01644 save_as_floats);
01645
01646 if (! retval2)
01647 break;
01648
01649 i++;
01650 }
01651
01652 error_cleanup:
01653
01654 if (data_hid > 0)
01655 H5Gclose (data_hid);
01656
01657 if (class_hid > 0)
01658 H5Dclose (class_hid);
01659
01660 if (space_hid > 0)
01661 H5Sclose (space_hid);
01662
01663 if (type_hid > 0)
01664 H5Tclose (type_hid);
01665
01666 if (group_hid > 0)
01667 H5Gclose (group_hid);
01668
01669 return true;
01670 }
01671
01672 bool
01673 octave_class::load_hdf5 (hid_t loc_id, const char *name)
01674 {
01675 bool retval = false;
01676
01677 hid_t group_hid = -1;
01678 hid_t data_hid = -1;
01679 hid_t type_hid = -1;
01680 hid_t type_class_hid = -1;
01681 hid_t space_hid = -1;
01682 hid_t subgroup_hid = -1;
01683 hid_t st_id = -1;
01684
01685 hdf5_callback_data dsub;
01686
01687 herr_t retval2 = 0;
01688 octave_map m (dim_vector (1, 1));
01689 int current_item = 0;
01690 hsize_t num_obj = 0;
01691 int slen = 0;
01692 hsize_t rank = 0;
01693
01694 #if HAVE_HDF5_18
01695 group_hid = H5Gopen (loc_id, name, H5P_DEFAULT);
01696 #else
01697 group_hid = H5Gopen (loc_id, name);
01698 #endif
01699 if (group_hid < 0)
01700 goto error_cleanup;
01701
01702 #if HAVE_HDF5_18
01703 data_hid = H5Dopen (group_hid, "classname", H5P_DEFAULT);
01704 #else
01705 data_hid = H5Dopen (group_hid, "classname");
01706 #endif
01707
01708 if (data_hid < 0)
01709 goto error_cleanup;
01710
01711 type_hid = H5Dget_type (data_hid);
01712
01713 type_class_hid = H5Tget_class (type_hid);
01714
01715 if (type_class_hid != H5T_STRING)
01716 goto error_cleanup;
01717
01718 space_hid = H5Dget_space (data_hid);
01719 rank = H5Sget_simple_extent_ndims (space_hid);
01720
01721 if (rank != 0)
01722 goto error_cleanup;
01723
01724 slen = H5Tget_size (type_hid);
01725 if (slen < 0)
01726 goto error_cleanup;
01727
01728
01729 do
01730 {
01731 OCTAVE_LOCAL_BUFFER (char, classname, slen);
01732
01733
01734 st_id = H5Tcopy (H5T_C_S1);
01735 H5Tset_size (st_id, slen);
01736
01737 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
01738 classname) < 0)
01739 {
01740 H5Tclose (st_id);
01741 H5Dclose (data_hid);
01742 H5Gclose (group_hid);
01743 return false;
01744 }
01745
01746 H5Tclose (st_id);
01747 H5Dclose (data_hid);
01748 data_hid = -1;
01749
01750 c_name = classname;
01751 }
01752 while (0);
01753 reconstruct_exemplar ();
01754
01755 #if HAVE_HDF5_18
01756 subgroup_hid = H5Gopen (group_hid, name, H5P_DEFAULT);
01757 #else
01758 subgroup_hid = H5Gopen (group_hid, name);
01759 #endif
01760 H5Gget_num_objs (subgroup_hid, &num_obj);
01761 H5Gclose (subgroup_hid);
01762
01763 while (current_item < static_cast<int> (num_obj)
01764 && (retval2 = H5Giterate (group_hid, name, ¤t_item,
01765 hdf5_read_next_data, &dsub)) > 0)
01766 {
01767 octave_value t2 = dsub.tc;
01768
01769 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
01770
01771 if (error_state)
01772 {
01773 error ("load: internal error loading class elements");
01774 return false;
01775 }
01776
01777 m.assign (dsub.name, tcell);
01778
01779 }
01780
01781 if (retval2 >= 0)
01782 {
01783 map = m;
01784
01785 if (!reconstruct_parents ())
01786 warning ("load: unable to reconstruct object inheritance");
01787 else
01788 {
01789 if (load_path::find_method (c_name, "loadobj") != std::string ())
01790 {
01791 octave_value in = new octave_class (*this);
01792 octave_value_list tmp = feval ("loadobj", in, 1);
01793
01794 if (! error_state)
01795 {
01796 map = tmp(0).map_value ();
01797 retval = true;
01798 }
01799 else
01800 retval = false;
01801 }
01802 else
01803 retval = true;
01804 }
01805 }
01806
01807 error_cleanup:
01808 if (data_hid > 0)
01809 H5Dclose (data_hid);
01810
01811 if (data_hid > 0)
01812 H5Gclose (group_hid);
01813
01814 return retval;
01815 }
01816
01817 #endif
01818
01819 mxArray *
01820 octave_class::as_mxArray (void) const
01821 {
01822 gripe_wrong_type_arg ("octave_class::as_mxArray ()", type_name ());
01823
01824 return 0;
01825 }
01826
01827 bool
01828 octave_class::in_class_method (void)
01829 {
01830 octave_function *fcn = octave_call_stack::current ();
01831
01832 return (fcn
01833 && (fcn->is_class_method ()
01834 || fcn->is_class_constructor ()
01835 || fcn->is_anonymous_function_of_class ()
01836 || fcn->is_private_function_of_class (class_name ()))
01837 && find_parent_class (fcn->dispatch_class ()));
01838 }
01839
01840 octave_class::exemplar_info::exemplar_info (const octave_value& obj)
01841 : field_names (), parent_class_names ()
01842 {
01843 if (obj.is_object ())
01844 {
01845 octave_map m = obj.map_value ();
01846 field_names = m.keys ();
01847
01848 parent_class_names = obj.parent_class_name_list ();
01849 }
01850 else
01851 error ("invalid call to exemplar_info constructor");
01852 }
01853
01854
01855
01856 std::map<std::string, octave_class::exemplar_info> octave_class::exemplar_map;
01857
01858 bool
01859 octave_class::exemplar_info::compare (const octave_value& obj) const
01860 {
01861 bool retval = true;
01862
01863 if (obj.is_object ())
01864 {
01865 if (nfields () == obj.nfields ())
01866 {
01867 octave_map obj_map = obj.map_value ();
01868 string_vector obj_fnames = obj_map.keys ();
01869 string_vector fnames = fields ();
01870
01871 for (octave_idx_type i = 0; i < nfields (); i++)
01872 {
01873 if (obj_fnames[i] != fnames[i])
01874 {
01875 retval = false;
01876 error ("mismatch in field names");
01877 break;
01878 }
01879 }
01880
01881 if (nparents () == obj.nparents ())
01882 {
01883 std::list<std::string> obj_parents
01884 = obj.parent_class_name_list ();
01885 std::list<std::string> pnames = parents ();
01886
01887 std::list<std::string>::const_iterator p = obj_parents.begin ();
01888 std::list<std::string>::const_iterator q = pnames.begin ();
01889
01890 while (p != obj_parents.end ())
01891 {
01892 if (*p++ != *q++)
01893 {
01894 retval = false;
01895 error ("mismatch in parent classes");
01896 break;
01897 }
01898 }
01899 }
01900 else
01901 {
01902 retval = false;
01903 error ("mismatch in number of parent classes");
01904 }
01905 }
01906 else
01907 {
01908 retval = false;
01909 error ("mismatch in number of fields");
01910 }
01911 }
01912 else
01913 {
01914 retval = false;
01915 error ("invalid comparison of class exemplar to non-class object");
01916 }
01917
01918 return retval;
01919 }
01920
01921 DEFUN (class, args, ,
01922 "-*- texinfo -*-\n\
01923 @deftypefn {Built-in Function} {} class (@var{expr})\n\
01924 @deftypefnx {Built-in Function} {} class (@var{s}, @var{id})\n\
01925 @deftypefnx {Built-in Function} {} class (@var{s}, @var{id}, @var{p}, @dots{})\n\
01926 Return the class of the expression @var{expr} or create a class with\n\
01927 fields from structure @var{s} and name (string) @var{id}. Additional\n\
01928 arguments name a list of parent classes from which the new class is\n\
01929 derived.\n\
01930 @end deftypefn")
01931 {
01932 octave_value retval;
01933
01934 int nargin = args.length ();
01935
01936 if (nargin == 0)
01937 print_usage ();
01938 else if (nargin == 1)
01939 retval = args(0).class_name ();
01940 else
01941 {
01942 octave_function *fcn = octave_call_stack::caller ();
01943
01944 std::string id = args(1).string_value ();
01945
01946 if (! error_state)
01947 {
01948 if (fcn)
01949 {
01950 if (fcn->is_class_constructor (id) || fcn->is_class_method (id))
01951 {
01952 octave_map m = args(0).map_value ();
01953
01954 if (! error_state)
01955 {
01956 if (nargin == 2)
01957 retval
01958 = octave_value (new octave_class
01959 (m, id, std::list<std::string> ()));
01960 else
01961 {
01962 octave_value_list parents = args.slice (2, nargin-2);
01963
01964 retval
01965 = octave_value (new octave_class (m, id, parents));
01966 }
01967
01968 if (! error_state)
01969 {
01970 octave_class::exemplar_const_iterator it
01971 = octave_class::exemplar_map.find (id);
01972
01973 if (it == octave_class::exemplar_map.end ())
01974 octave_class::exemplar_map[id]
01975 = octave_class::exemplar_info (retval);
01976 else if (! it->second.compare (retval))
01977 error ("class: object of class '%s' does not match previously constructed objects",
01978 id.c_str ());
01979 }
01980 }
01981 else
01982 error ("class: expecting structure S as first argument");
01983 }
01984 else
01985 error ("class: '%s' is invalid as a class name in this context",
01986 id.c_str ());
01987 }
01988 else
01989 error ("class: invalid call from outside class constructor or method");
01990 }
01991 else
01992 error ("class: ID (class name) must be a character string");
01993 }
01994
01995 return retval;
01996 }
01997
01998 DEFUN (__isa_parent__, args, ,
01999 "-*- texinfo -*-\n\
02000 @deftypefn {Built-in Function} {} __isa_parent__ (@var{class}, @var{name})\n\
02001 Undocumented internal function.\n\
02002 @end deftypefn")
02003 {
02004 octave_value retval = false;
02005
02006 if (args.length () == 2)
02007 {
02008 octave_value cls = args(0);
02009 octave_value nm = args(1);
02010
02011 if (! error_state)
02012 {
02013 if (cls.find_parent_class (nm.string_value ()))
02014 retval = true;
02015 }
02016 else
02017 error ("__isa_parent__: expecting arguments to be character strings");
02018 }
02019 else
02020 print_usage ();
02021
02022 return retval;
02023 }
02024
02025 DEFUN (__parent_classes__, args, ,
02026 "-*- texinfo -*-\n\
02027 @deftypefn {Built-in Function} {} __parent_classes__ (@var{x})\n\
02028 Undocumented internal function.\n\
02029 @end deftypefn")
02030 {
02031 octave_value retval = Cell ();
02032
02033 if (args.length () == 1)
02034 {
02035 octave_value arg = args(0);
02036
02037 if (arg.is_object ())
02038 retval = Cell (arg.parent_class_names ());
02039 }
02040 else
02041 print_usage ();
02042
02043 return retval;
02044 }
02045
02046 DEFUN (isobject, args, ,
02047 "-*- texinfo -*-\n\
02048 @deftypefn {Built-in Function} {} isobject (@var{x})\n\
02049 Return true if @var{x} is a class object.\n\
02050 @seealso{class, typeinfo, isa, ismethod}\n\
02051 @end deftypefn")
02052 {
02053 octave_value retval;
02054
02055 if (args.length () == 1)
02056 retval = args(0).is_object ();
02057 else
02058 print_usage ();
02059
02060 return retval;
02061 }
02062
02063 DEFUN (ismethod, args, ,
02064 "-*- texinfo -*-\n\
02065 @deftypefn {Built-in Function} {} ismethod (@var{x}, @var{method})\n\
02066 Return true if @var{x} is a class object and the string @var{method}\n\
02067 is a method of this class.\n\
02068 @seealso{isobject}\n\
02069 @end deftypefn")
02070 {
02071 octave_value retval;
02072
02073 if (args.length () == 2)
02074 {
02075 octave_value arg = args(0);
02076
02077 std::string class_name;
02078
02079 if (arg.is_object ())
02080 class_name = arg.class_name ();
02081 else if (arg.is_string ())
02082 class_name = arg.string_value ();
02083 else
02084 error ("ismethod: expecting object or class name as first argument");
02085
02086 if (! error_state)
02087 {
02088 std::string method = args(1).string_value ();
02089
02090 if (! error_state)
02091 {
02092 if (load_path::find_method (class_name, method) != std::string ())
02093 retval = true;
02094 else
02095 retval = false;
02096 }
02097 }
02098 }
02099 else
02100 print_usage ();
02101
02102 return retval;
02103 }
02104
02105 DEFUN (methods, args, nargout,
02106 "-*- texinfo -*-\n\
02107 @deftypefn {Built-in Function} {} methods (@var{x})\n\
02108 @deftypefnx {Built-in Function} {} methods (\"classname\")\n\
02109 Return a cell array containing the names of the methods for the\n\
02110 object @var{x} or the named class.\n\
02111 @end deftypefn")
02112 {
02113 octave_value retval;
02114
02115 if (args.length () == 1)
02116 {
02117 octave_value arg = args(0);
02118
02119 std::string class_name;
02120
02121 if (arg.is_object ())
02122 class_name = arg.class_name ();
02123 else if (arg.is_string ())
02124 class_name = arg.string_value ();
02125 else
02126 error ("methods: expecting object or class name as argument");
02127
02128 if (! error_state)
02129 {
02130 string_vector sv = load_path::methods (class_name);
02131
02132 if (nargout == 0)
02133 {
02134 octave_stdout << "Methods for class " << class_name << ":\n\n";
02135
02136 sv.list_in_columns (octave_stdout);
02137
02138 octave_stdout << std::endl;
02139 }
02140 else
02141 retval = Cell (sv);
02142 }
02143 }
02144 else
02145 print_usage ();
02146
02147 return retval;
02148 }
02149
02150 static bool
02151 is_built_in_class (const std::string& cn)
02152 {
02153 static std::set<std::string> built_in_class_names;
02154
02155 if (built_in_class_names.empty ())
02156 {
02157 built_in_class_names.insert ("double");
02158 built_in_class_names.insert ("single");
02159 built_in_class_names.insert ("cell");
02160 built_in_class_names.insert ("struct");
02161 built_in_class_names.insert ("logical");
02162 built_in_class_names.insert ("char");
02163 built_in_class_names.insert ("function handle");
02164 built_in_class_names.insert ("int8");
02165 built_in_class_names.insert ("uint8");
02166 built_in_class_names.insert ("int16");
02167 built_in_class_names.insert ("uint16");
02168 built_in_class_names.insert ("int32");
02169 built_in_class_names.insert ("uint32");
02170 built_in_class_names.insert ("int64");
02171 built_in_class_names.insert ("uint64");
02172 }
02173
02174 return built_in_class_names.find (cn) != built_in_class_names.end ();
02175 }
02176
02177 DEFUN (superiorto, args, ,
02178 "-*- texinfo -*-\n\
02179 @deftypefn {Built-in Function} {} superiorto (@var{class_name}, @dots{})\n\
02180 When called from a class constructor, mark the object currently\n\
02181 constructed as having a higher precedence than @var{class_name}.\n\
02182 More that one such class can be specified in a single call.\n\
02183 This function may only be called from a class constructor.\n\
02184 @end deftypefn")
02185 {
02186 octave_value retval;
02187
02188 octave_function *fcn = octave_call_stack::caller ();
02189
02190 if (fcn && fcn->is_class_constructor ())
02191 {
02192 for (int i = 0; i < args.length(); i++)
02193 {
02194 std::string class_name = args(i).string_value ();
02195
02196 if (! error_state)
02197 {
02198 if (! is_built_in_class (class_name))
02199 {
02200 std::string this_class_name = fcn->name ();
02201
02202 if (! symbol_table::set_class_relationship (this_class_name,
02203 class_name))
02204 {
02205 error ("superiorto: precedence already set for %s and %s",
02206 this_class_name.c_str (), class_name.c_str ());
02207 break;
02208 }
02209 }
02210 else
02211 {
02212
02213
02214 }
02215 }
02216 else
02217 {
02218 error ("superiorto: expecting argument to be class name");
02219 break;
02220 }
02221 }
02222 }
02223 else
02224 error ("superiorto: invalid call from outside class constructor");
02225
02226 return retval;
02227 }
02228
02229 DEFUN (inferiorto, args, ,
02230 "-*- texinfo -*-\n\
02231 @deftypefn {Built-in Function} {} inferiorto (@var{class_name}, @dots{})\n\
02232 When called from a class constructor, mark the object currently\n\
02233 constructed as having a lower precedence than @var{class_name}.\n\
02234 More that one such class can be specified in a single call.\n\
02235 This function may only be called from a class constructor.\n\
02236 @end deftypefn")
02237 {
02238 octave_value retval;
02239
02240 octave_function *fcn = octave_call_stack::caller ();
02241
02242 if (fcn && fcn->is_class_constructor ())
02243 {
02244 for (int i = 0; i < args.length(); i++)
02245 {
02246 std::string class_name = args(i).string_value ();
02247
02248 if (! error_state)
02249 {
02250 if (! is_built_in_class (class_name))
02251 {
02252 std::string this_class_name = fcn->name ();
02253
02254 symbol_table::set_class_relationship (class_name,
02255 this_class_name);
02256
02257 if (! symbol_table::set_class_relationship (this_class_name,
02258 class_name))
02259 {
02260 error ("inferiorto: precedence already set for %s and %s",
02261 this_class_name.c_str (), class_name.c_str ());
02262 break;
02263 }
02264 }
02265 else
02266 {
02267 error ("inferiorto: cannot give user-defined class lower precedence than built-in class");
02268 break;
02269 }
02270 }
02271 else
02272 {
02273 error ("inferiorto: expecting argument to be class name");
02274 break;
02275 }
02276 }
02277 }
02278 else
02279 error ("inferiorto: invalid call from outside class constructor");
02280
02281 return retval;
02282 }