comparison libinterp/octave-value/ov-class.cc @ 15195:2fc554ffbc28

split libinterp from src * libinterp: New directory. Move all files from src directory here except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc, mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh. * libinterp/Makefile.am: New file, extracted from src/Makefile.am. * src/Makefile.am: Delete everything except targets and definitions needed to build and link main and utility programs. * Makefile.am (SUBDIRS): Include libinterp in the list. * autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not src/dldfcn directory. * configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not src/octave.cc. (DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src. (AC_CONFIG_FILES): Include libinterp/Makefile in the list. * find-docstring-files.sh: Look in libinterp, not src. * gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 16:23:39 -0400
parents src/octave-value/ov-class.cc@62a35ae7d6a2
children 049e8bbff782
comparison
equal deleted inserted replaced
15194:0f0b795044c3 15195:2fc554ffbc28
1 /*
2
3 Copyright (C) 2007-2012 John W. Eaton
4 Copyright (C) 2009 VZLU Prague
5
6 This file is part of Octave.
7
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <iostream>
29
30 #include "Array-util.h"
31 #include "byte-swap.h"
32 #include "oct-locbuf.h"
33 #include "lo-mappers.h"
34
35 #include "Cell.h"
36 #include "defun.h"
37 #include "error.h"
38 #include "file-ops.h"
39 #include "gripes.h"
40 #include "load-path.h"
41 #include "ls-hdf5.h"
42 #include "ls-oct-ascii.h"
43 #include "ls-oct-binary.h"
44 #include "ls-utils.h"
45 #include "mxarray.h"
46 #include "oct-lvalue.h"
47 #include "ov-class.h"
48 #include "ov-fcn.h"
49 #include "ov-usr-fcn.h"
50 #include "pager.h"
51 #include "parse.h"
52 #include "pr-output.h"
53 #include "toplev.h"
54 #include "unwind-prot.h"
55 #include "variables.h"
56
57 DEFINE_OCTAVE_ALLOCATOR(octave_class);
58
59 int octave_class::t_id (-1);
60
61 const std::string octave_class::t_name ("class");
62
63 void
64 octave_class::register_type (void)
65 {
66 t_id = octave_value_typeinfo::register_type
67 (octave_class::t_name, "<unknown>", octave_value (new octave_class ()));
68 }
69
70 octave_class::octave_class (const octave_map& m, const std::string& id,
71 const octave_value_list& parents)
72 : octave_base_value (), map (m), c_name (id), obsolete_copies (0)
73 {
74 octave_idx_type n = parents.length ();
75
76 for (octave_idx_type idx = 0; idx < n; idx++)
77 {
78 octave_value parent = parents(idx);
79
80 if (! parent.is_object ())
81 error ("parents must be objects");
82 else
83 {
84 std::string pcnm = parent.class_name ();
85
86 if (find_parent_class (pcnm))
87 error ("duplicate class in parent tree");
88 else
89 {
90 parent_list.push_back (pcnm);
91
92 octave_idx_type nel = map.numel ();
93 octave_idx_type p_nel = parent.numel ();
94
95 if (nel == 0)
96 {
97 if (p_nel == 0)
98 {
99 // No elements in MAP or the parent class object,
100 // so just add the field name.
101
102 map.assign (pcnm, Cell (map.dims ()));
103 }
104 else if (p_nel == 1)
105 {
106 if (map.nfields () == 0)
107 {
108 // No elements or fields in MAP, but the
109 // parent is class object with one element.
110 // Resize to match size of parent class and
111 // make the parent a field in MAP.
112
113 map.resize (parent.dims ());
114
115 map.assign (pcnm, parent);
116 }
117 else
118 {
119 // No elements in MAP, but we have at least
120 // one field. So don't resize, just add the
121 // field name.
122
123 map.assign (pcnm, Cell (map.dims ()));
124 }
125 }
126 else if (map.nfields () == 0)
127 {
128 // No elements or fields in MAP and more than one
129 // element in the parent class object, so we can
130 // resize MAP to match parent dimsenions, then
131 // distribute the elements of the parent object to
132 // the elements of MAP.
133
134 dim_vector parent_dims = parent.dims ();
135
136 map.resize (parent_dims);
137
138 Cell c (parent_dims);
139
140 octave_map pmap = parent.map_value ();
141
142 std::list<std::string> plist
143 = parent.parent_class_name_list ();
144
145 for (octave_idx_type i = 0; i < p_nel; i++)
146 c(i) = octave_value (pmap.index (i), pcnm, plist);
147
148 map.assign (pcnm, c);
149 }
150 else
151 error ("class: parent class dimension mismatch");
152 }
153 else if (nel == 1 && p_nel == 1)
154 {
155 // Simple assignment.
156
157 map.assign (pcnm, parent);
158 }
159 else
160 {
161 if (p_nel == 1)
162 {
163 // Broadcast the scalar parent class object to
164 // each element of MAP.
165
166 Cell pcell (map.dims (), parent);
167
168 map.assign (pcnm, pcell);
169 }
170
171 else if (nel == p_nel)
172 {
173 // FIXME -- is there a better way to do this?
174
175 // The parent class object has the same number of
176 // elements as the map we are using to create the
177 // new object, so distribute those elements to
178 // each element of the new object by first
179 // splitting the elements of the parent class
180 // object into a cell array with one element per
181 // cell. Then do the assignment all at once.
182
183 Cell c (parent.dims ());
184
185 octave_map pmap = parent.map_value ();
186
187 std::list<std::string> plist
188 = parent.parent_class_name_list ();
189
190 for (octave_idx_type i = 0; i < p_nel; i++)
191 c(i) = octave_value (pmap.index (i), pcnm, plist);
192
193 map.assign (pcnm, c);
194 }
195 else
196 error ("class: parent class dimension mismatch");
197 }
198 }
199 }
200 }
201
202 if (! error_state)
203 symbol_table::add_to_parent_map (id, parent_list);
204 }
205
206 octave_base_value *
207 octave_class::unique_clone (void)
208 {
209 if (count == obsolete_copies)
210 {
211 // All remaining copies are obsolete. We don't actually need to clone.
212 count++;
213 return this;
214 }
215 else
216 {
217 // In theory, this shouldn't be happening, but it's here just in case.
218 if (count < obsolete_copies)
219 obsolete_copies = 0;
220
221 return clone ();
222 }
223 }
224
225 std::string
226 octave_class::get_current_method_class (void)
227 {
228 std::string retval = class_name ();
229
230 if (nparents () > 0)
231 {
232 octave_function *fcn = octave_call_stack::current ();
233
234 // Here we are just looking to see if FCN is a method or constructor
235 // for any class, not specifically this one.
236 if (fcn && (fcn->is_class_method () || fcn->is_class_constructor ()))
237 retval = fcn->dispatch_class ();
238 }
239
240 return retval;
241 }
242
243 static void
244 gripe_invalid_index1 (void)
245 {
246 error ("invalid index for class");
247 }
248
249 static void
250 gripe_invalid_index_for_assignment (void)
251 {
252 error ("invalid index for class assignment");
253 }
254
255 static void
256 gripe_invalid_index_type (const std::string& nm, char t)
257 {
258 error ("%s cannot be indexed with %c", nm.c_str (), t);
259 }
260
261 static void
262 gripe_failed_assignment (void)
263 {
264 error ("assignment to class element failed");
265 }
266
267 static inline octave_value_list
268 sanitize (const octave_value_list& ovl)
269 {
270 octave_value_list retval = ovl;
271
272 for (octave_idx_type i = 0; i < ovl.length (); i++)
273 {
274 if (retval(i).is_magic_colon ())
275 retval(i) = ":";
276 }
277
278 return retval;
279 }
280
281 static inline octave_value
282 make_idx_args (const std::string& type,
283 const std::list<octave_value_list>& idx,
284 const std::string& who)
285 {
286 octave_value retval;
287
288 size_t len = type.length ();
289
290 if (len == idx.size ())
291 {
292 Cell type_field (1, len);
293 Cell subs_field (1, len);
294
295 std::list<octave_value_list>::const_iterator p = idx.begin ();
296
297 for (size_t i = 0; i < len; i++)
298 {
299 char t = type[i];
300
301 switch (t)
302 {
303 case '(':
304 type_field(i) = "()";
305 subs_field(i) = Cell (sanitize (*p++));
306 break;
307
308 case '{':
309 type_field(i) = "{}";
310 subs_field(i) = Cell (sanitize (*p++));
311 break;
312
313 case '.':
314 {
315 type_field(i) = ".";
316
317 octave_value_list vlist = *p++;
318
319 if (vlist.length () == 1)
320 {
321 octave_value val = vlist(0);
322
323 if (val.is_string ())
324 subs_field(i) = val;
325 else
326 {
327 error ("expecting character string argument for `.' index");
328 return retval;
329 }
330 }
331 else
332 {
333 error ("expecting single argument for `.' index");
334 return retval;
335 }
336 }
337 break;
338
339 default:
340 panic_impossible ();
341 break;
342 }
343 }
344
345 octave_map m;
346
347 m.assign ("type", type_field);
348 m.assign ("subs", subs_field);
349
350 retval = m;
351 }
352 else
353 error ("invalid index for %s", who.c_str ());
354
355 return retval;
356 }
357
358 Cell
359 octave_class::dotref (const octave_value_list& idx)
360 {
361 Cell retval;
362
363 assert (idx.length () == 1);
364
365 std::string method_class = get_current_method_class ();
366
367 // Find the class in which this method resides before attempting to access
368 // the requested field.
369
370 octave_base_value *obvp = find_parent_class (method_class);
371
372 if (obvp == 0)
373 {
374 error ("malformed class");
375 return retval;
376 }
377
378 octave_map my_map = (obvp != this) ? obvp->map_value () : map;
379
380 std::string nm = idx(0).string_value ();
381
382 if (! error_state)
383 {
384 octave_map::const_iterator p = my_map.seek (nm);
385
386 if (p != my_map.end ())
387 retval = my_map.contents (p);
388 else
389 error ("class has no member `%s'", nm.c_str ());
390 }
391 else
392 gripe_invalid_index1 ();
393
394 return retval;
395 }
396
397 static bool
398 called_from_builtin (void)
399 {
400 octave_function *fcn = octave_call_stack::caller ();
401
402 // FIXME -- we probably need a better check here, or some other
403 // mechanism to avoid overloaded functions when builtin is used.
404 // For example, what if someone overloads the builtin function?
405 // Also, are there other places where using builtin is not properly
406 // avoiding dispatch?
407
408 return (fcn && fcn->name () == "builtin");
409 }
410
411 Matrix
412 octave_class::size (void)
413 {
414 if (in_class_method () || called_from_builtin ())
415 return octave_base_value::size ();
416
417 Matrix retval (1, 2, 1.0);
418 octave_value meth = symbol_table::find_method ("size", class_name ());
419
420 if (meth.is_defined ())
421 {
422 count++;
423 octave_value_list args (1, octave_value (this));
424
425 octave_value_list lv = feval (meth.function_value (), args, 1);
426 if (lv.length () > 0 && lv(0).is_matrix_type () && lv(0).dims ().is_vector ())
427 retval = lv(0).matrix_value ();
428 else
429 error ("@%s/size: invalid return value", class_name ().c_str ());
430 }
431 else
432 {
433 dim_vector dv = dims ();
434
435 int nd = dv.length ();
436
437 retval.resize (1, nd);
438
439 for (int i = 0; i < nd; i++)
440 retval(i) = dv(i);
441 }
442
443 return retval;
444 }
445
446 octave_idx_type
447 octave_class::numel (const octave_value_list& idx)
448 {
449 if (in_class_method () || called_from_builtin ())
450 return octave_base_value::numel (idx);
451
452 octave_idx_type retval = -1;
453 const std::string cn = class_name ();
454
455 octave_value meth = symbol_table::find_method ("numel", cn);
456
457 if (meth.is_defined ())
458 {
459 octave_value_list args (idx.length () + 1, octave_value ());
460
461 count++;
462 args(0) = octave_value (this);
463
464 for (octave_idx_type i = 0; i < idx.length (); i++)
465 args(i+1) = idx(i);
466
467 octave_value_list lv = feval (meth.function_value (), args, 1);
468 if (lv.length () == 1 && lv(0).is_scalar_type ())
469 retval = lv(0).idx_type_value (true);
470 else
471 error ("@%s/numel: invalid return value", cn.c_str ());
472 }
473 else
474 retval = octave_base_value::numel (idx);
475
476 return retval;
477 }
478
479 octave_value_list
480 octave_class::subsref (const std::string& type,
481 const std::list<octave_value_list>& idx,
482 int nargout)
483 {
484 octave_value_list retval;
485
486 if (in_class_method () || called_from_builtin ())
487 {
488 // FIXME -- this block of code is the same as the body of
489 // octave_struct::subsref. Maybe it could be shared instead of
490 // duplicated.
491
492 int skip = 1;
493
494 switch (type[0])
495 {
496 case '(':
497 {
498 if (type.length () > 1 && type[1] == '.')
499 {
500 std::list<octave_value_list>::const_iterator p = idx.begin ();
501 octave_value_list key_idx = *++p;
502
503 Cell tmp = dotref (key_idx);
504
505 if (! error_state)
506 {
507 Cell t = tmp.index (idx.front ());
508
509 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
510
511 // We handled two index elements, so tell
512 // next_subsref to skip both of them.
513
514 skip++;
515 }
516 }
517 else
518 retval(0) = octave_value (map.index (idx.front ()),
519 c_name, parent_list);
520 }
521 break;
522
523 case '.':
524 {
525 if (map.numel () > 0)
526 {
527 Cell t = dotref (idx.front ());
528
529 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
530 }
531 }
532 break;
533
534 case '{':
535 gripe_invalid_index_type (type_name (), type[0]);
536 break;
537
538 default:
539 panic_impossible ();
540 }
541
542 // FIXME -- perhaps there should be an
543 // octave_value_list::next_subsref member function? See also
544 // octave_user_function::subsref.
545
546 if (idx.size () > 1)
547 retval = retval(0).next_subsref (nargout, type, idx, skip);
548 }
549 else
550 {
551 octave_value meth = symbol_table::find_method ("subsref", class_name ());
552
553 if (meth.is_defined ())
554 {
555 octave_value_list args;
556
557 args(1) = make_idx_args (type, idx, "subsref");
558
559 if (error_state)
560 return octave_value_list ();
561
562 count++;
563 args(0) = octave_value (this);
564
565 // FIXME: for Matlab compatibility, let us attempt to set up a proper
566 // value for nargout at least in the simple case where the
567 // cs-list-type expression - i.e., {} or ().x, is the leading one.
568 // Note that Octave does not actually need this, since it will
569 // be able to properly react to varargout a posteriori.
570 bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{'
571 || (type.length () > 1 && type[0] == '('
572 && type[1] == '.'));
573
574 int true_nargout = nargout;
575
576 if (maybe_cs_list_query)
577 {
578 // Set up a proper nargout for the subsref call by calling numel.
579 octave_value_list tmp;
580 if (type[0] != '.') tmp = idx.front ();
581 true_nargout = numel (tmp);
582 }
583
584 retval = feval (meth.function_value (), args, true_nargout);
585
586 // Since we're handling subsref, return the list in the first value
587 // if it has more than one element, to be able to pass through
588 // rvalue1 calls.
589 if (retval.length () > 1)
590 retval = octave_value (retval, true);
591 }
592 else
593 {
594 if (type.length () == 1 && type[0] == '(')
595 retval(0) = octave_value (map.index (idx.front ()), c_name,
596 parent_list);
597 else
598 gripe_invalid_index1 ();
599 }
600 }
601
602 return retval;
603 }
604
605 octave_value
606 octave_class::numeric_conv (const Cell& val, const std::string& type)
607 {
608 octave_value retval;
609
610 if (val.length () == 1)
611 {
612 retval = val(0);
613
614 if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
615 retval = octave_map ();
616 }
617 else
618 gripe_invalid_index_for_assignment ();
619
620 return retval;
621 }
622
623 octave_value
624 octave_class::subsasgn (const std::string& type,
625 const std::list<octave_value_list>& idx,
626 const octave_value& rhs)
627 {
628 count++;
629 return subsasgn_common (octave_value (this), type, idx, rhs);
630 }
631
632 octave_value
633 octave_class::undef_subsasgn (const std::string& type,
634 const std::list<octave_value_list>& idx,
635 const octave_value& rhs)
636 {
637 // For compatibility with Matlab, pass [] as the first argument to the
638 // the subsasgn function when the LHS of an indexed assignment is
639 // undefined.
640
641 return subsasgn_common (Matrix (), type, idx, rhs);
642 }
643
644 octave_value
645 octave_class::subsasgn_common (const octave_value& obj,
646 const std::string& type,
647 const std::list<octave_value_list>& idx,
648 const octave_value& rhs)
649 {
650 octave_value retval;
651
652 if (! (in_class_method () || called_from_builtin ()))
653 {
654 octave_value meth = symbol_table::find_method ("subsasgn", class_name ());
655
656 if (meth.is_defined ())
657 {
658 octave_value_list args;
659
660 if (rhs.is_cs_list ())
661 {
662 octave_value_list lrhs = rhs.list_value ();
663 args.resize (2 + lrhs.length ());
664 for (octave_idx_type i = 0; i < lrhs.length (); i++)
665 args(2+i) = lrhs(i);
666 }
667 else
668 args(2) = rhs;
669
670 args(1) = make_idx_args (type, idx, "subsasgn");
671
672 if (error_state)
673 return octave_value_list ();
674
675 args(0) = obj;
676
677 // Now comes the magic. Count copies with me:
678 // 1. myself (obsolete)
679 // 2. the copy inside args (obsolete)
680 // 3. the copy in method's symbol table (working)
681 // ... possibly more (not obsolete).
682 //
683 // So we mark 2 copies as obsolete and hold our fingers crossed.
684 // But prior to doing that, check whether the routine is amenable
685 // to the optimization.
686 // It is essential that the handling function doesn't store extra
687 // copies anywhere. If it does, things will not break but the
688 // optimization won't work.
689
690 octave_value_list tmp;
691
692 if (obsolete_copies == 0 && meth.is_user_function ()
693 && meth.user_function_value ()->subsasgn_optimization_ok ())
694 {
695 unwind_protect frame;
696 frame.protect_var (obsolete_copies);
697 obsolete_copies = 2;
698
699 tmp = feval (meth.function_value (), args);
700 }
701 else
702 tmp = feval (meth.function_value (), args);
703
704 // FIXME -- should the subsasgn method be able to return
705 // more than one value?
706
707 if (tmp.length () > 1)
708 error ("expecting single return value from @%s/subsasgn",
709 class_name ().c_str ());
710
711 else
712 retval = tmp(0);
713
714 return retval;
715 }
716 }
717
718 // Find the class in which this method resides before
719 // attempting to do the indexed assignment.
720
721 std::string method_class = get_current_method_class ();
722
723 octave_base_value *obvp = unique_parent_class (method_class);
724 if (obvp != this)
725 {
726
727 if (obvp)
728 {
729 obvp->subsasgn (type, idx, rhs);
730 if (! error_state)
731 {
732 count++;
733 retval = octave_value (this);
734 }
735 else
736 gripe_failed_assignment ();
737 }
738 else
739 error ("malformed class");
740
741 return retval;
742 }
743
744 // FIXME -- this block of code is the same as the body of
745 // octave_struct::subsasgn. Maybe it could be shared instead of
746 // duplicated.
747
748 int n = type.length ();
749
750 octave_value t_rhs = rhs;
751
752 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
753 {
754 switch (type[0])
755 {
756 case '(':
757 {
758 if (type.length () > 1 && type[1] == '.')
759 {
760 std::list<octave_value_list>::const_iterator p = idx.begin ();
761 octave_value_list t_idx = *p;
762
763 octave_value_list key_idx = *++p;
764
765 assert (key_idx.length () == 1);
766
767 std::string key = key_idx(0).string_value ();
768
769 if (! error_state)
770 {
771 octave_value u;
772
773 if (! map.contains (key))
774 u = octave_value::empty_conv (type.substr (2), rhs);
775 else
776 {
777 Cell map_val = map.contents (key);
778
779 Cell map_elt = map_val.index (idx.front (), true);
780
781 u = numeric_conv (map_elt, type.substr (2));
782 }
783
784 if (! error_state)
785 {
786 std::list<octave_value_list> next_idx (idx);
787
788 // We handled two index elements, so subsasgn to
789 // needs to skip both of them.
790
791 next_idx.erase (next_idx.begin ());
792 next_idx.erase (next_idx.begin ());
793
794 u.make_unique ();
795
796 t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
797 }
798 }
799 else
800 gripe_invalid_index_for_assignment ();
801 }
802 else
803 gripe_invalid_index_for_assignment ();
804 }
805 break;
806
807 case '.':
808 {
809 octave_value_list key_idx = idx.front ();
810
811 assert (key_idx.length () == 1);
812
813 std::string key = key_idx(0).string_value ();
814
815 std::list<octave_value_list> next_idx (idx);
816
817 next_idx.erase (next_idx.begin ());
818
819 std::string next_type = type.substr (1);
820
821 Cell tmpc (1, 1);
822 octave_map::iterator pkey = map.seek (key);
823 if (pkey != map.end ())
824 {
825 map.contents (pkey).make_unique ();
826 tmpc = map.contents (pkey);
827 }
828
829 // FIXME: better code reuse?
830 if (! error_state)
831 {
832 if (tmpc.numel () == 1)
833 {
834 octave_value& tmp = tmpc(0);
835
836 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
837 {
838 tmp = octave_value::empty_conv (next_type, rhs);
839 tmp.make_unique (); // probably a no-op.
840 }
841 else
842 // optimization: ignore the copy still stored inside our map.
843 tmp.make_unique (1);
844
845 if (! error_state)
846 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
847 }
848 else
849 gripe_indexed_cs_list ();
850 }
851 }
852 break;
853
854 case '{':
855 gripe_invalid_index_type (type_name (), type[0]);
856 break;
857
858 default:
859 panic_impossible ();
860 }
861 }
862
863 if (! error_state)
864 {
865 switch (type[0])
866 {
867 case '(':
868 {
869 if (n > 1 && type[1] == '.')
870 {
871 std::list<octave_value_list>::const_iterator p = idx.begin ();
872 octave_value_list key_idx = *++p;
873
874 assert (key_idx.length () == 1);
875
876 std::string key = key_idx(0).string_value ();
877
878 if (! error_state)
879 {
880 map.assign (idx.front (), key, t_rhs);
881
882 if (! error_state)
883 {
884 count++;
885 retval = octave_value (this);
886 }
887 else
888 gripe_failed_assignment ();
889 }
890 else
891 gripe_failed_assignment ();
892 }
893 else
894 {
895 if (t_rhs.is_object () || t_rhs.is_map ())
896 {
897 octave_map rhs_map = t_rhs.map_value ();
898
899 if (! error_state)
900 {
901 map.assign (idx.front (), rhs_map);
902
903 if (! error_state)
904 {
905 count++;
906 retval = octave_value (this);
907 }
908 else
909 gripe_failed_assignment ();
910 }
911 else
912 error ("invalid class assignment");
913 }
914 else
915 {
916 if (t_rhs.is_empty ())
917 {
918 map.delete_elements (idx.front ());
919
920 if (! error_state)
921 {
922 count++;
923 retval = octave_value (this);
924 }
925 else
926 gripe_failed_assignment ();
927 }
928 else
929 error ("invalid class assignment");
930 }
931 }
932 }
933 break;
934
935 case '.':
936 {
937 octave_value_list key_idx = idx.front ();
938
939 assert (key_idx.length () == 1);
940
941 std::string key = key_idx(0).string_value ();
942
943 if (t_rhs.is_cs_list ())
944 {
945 Cell tmp_cell = Cell (t_rhs.list_value ());
946
947 // The shape of the RHS is irrelevant, we just want
948 // the number of elements to agree and to preserve the
949 // shape of the left hand side of the assignment.
950
951 if (numel () == tmp_cell.numel ())
952 tmp_cell = tmp_cell.reshape (dims ());
953
954 map.setfield (key, tmp_cell);
955 }
956 else
957 {
958 Cell tmp_cell(1, 1);
959 tmp_cell(0) = t_rhs.storable_value ();
960 map.setfield (key, tmp_cell);
961 }
962
963 if (! error_state)
964 {
965 count++;
966 retval = octave_value (this);
967 }
968 else
969 gripe_failed_assignment ();
970 }
971 break;
972
973 case '{':
974 gripe_invalid_index_type (type_name (), type[0]);
975 break;
976
977 default:
978 panic_impossible ();
979 }
980 }
981 else
982 gripe_failed_assignment ();
983
984 return retval;
985 }
986
987 idx_vector
988 octave_class::index_vector (void) const
989 {
990 idx_vector retval;
991
992 octave_value meth = symbol_table::find_method ("subsindex", class_name ());
993
994 if (meth.is_defined ())
995 {
996 octave_value_list args;
997 args(0) = octave_value (new octave_class (map, c_name, parent_list));
998
999 octave_value_list tmp = feval (meth.function_value (), args, 1);
1000
1001 if (!error_state && tmp.length () >= 1)
1002 {
1003 if (tmp(0).is_object ())
1004 error ("subsindex function must return a valid index vector");
1005 else
1006 // Index vector returned by subsindex is zero based
1007 // (why this inconsistency Mathworks?), and so we must
1008 // add one to the value returned as the index_vector method
1009 // expects it to be one based.
1010 retval = do_binary_op (octave_value::op_add, tmp (0),
1011 octave_value (1.0)).index_vector ();
1012 }
1013 }
1014 else
1015 error ("no subsindex method defined for class %s",
1016 class_name ().c_str ());
1017
1018 return retval;
1019 }
1020
1021 size_t
1022 octave_class::byte_size (void) const
1023 {
1024 // Neglect the size of the fieldnames.
1025
1026 size_t retval = 0;
1027
1028 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
1029 {
1030 std::string key = map.key (p);
1031
1032 octave_value val = octave_value (map.contents (p));
1033
1034 retval += val.byte_size ();
1035 }
1036
1037 return retval;
1038 }
1039
1040 string_vector
1041 octave_class::map_keys (void) const
1042 {
1043 string_vector retval;
1044 gripe_wrong_type_arg ("octave_class::map_keys()", type_name ());
1045 return retval;
1046 }
1047
1048 octave_base_value *
1049 octave_class::find_parent_class (const std::string& parent_class_name)
1050 {
1051 octave_base_value* retval = 0;
1052
1053 if (parent_class_name == class_name ())
1054 retval = this;
1055 else
1056 {
1057 for (std::list<std::string>::iterator pit = parent_list.begin ();
1058 pit != parent_list.end ();
1059 pit++)
1060 {
1061 octave_map::const_iterator smap = map.seek (*pit);
1062
1063 const Cell& tmp = map.contents (smap);
1064
1065 octave_value vtmp = tmp(0);
1066
1067 octave_base_value *obvp = vtmp.internal_rep ();
1068
1069 retval = obvp->find_parent_class (parent_class_name);
1070
1071 if (retval)
1072 break;
1073 }
1074 }
1075
1076 return retval;
1077 }
1078
1079 octave_base_value *
1080 octave_class::unique_parent_class (const std::string& parent_class_name)
1081 {
1082 octave_base_value* retval = 0;
1083
1084 if (parent_class_name == class_name ())
1085 retval = this;
1086 else
1087 {
1088 for (std::list<std::string>::iterator pit = parent_list.begin ();
1089 pit != parent_list.end ();
1090 pit++)
1091 {
1092 octave_map::iterator smap = map.seek (*pit);
1093
1094 Cell& tmp = map.contents (smap);
1095
1096 octave_value& vtmp = tmp(0);
1097
1098 octave_base_value *obvp = vtmp.internal_rep ();
1099
1100 // Use find_parent_class first to avoid uniquifying if not necessary.
1101 retval = obvp->find_parent_class (parent_class_name);
1102
1103 if (retval)
1104 {
1105 vtmp.make_unique ();
1106 obvp = vtmp.internal_rep ();
1107 retval = obvp->unique_parent_class (parent_class_name);
1108
1109 break;
1110 }
1111 }
1112 }
1113
1114 return retval;
1115 }
1116
1117 string_vector
1118 octave_class::all_strings (bool pad) const
1119 {
1120 string_vector retval;
1121
1122 octave_value meth = symbol_table::find_method ("char", class_name ());
1123
1124 if (meth.is_defined ())
1125 {
1126 octave_value_list args;
1127 args(0) = octave_value (new octave_class (map, c_name, parent_list));
1128
1129 octave_value_list tmp = feval (meth.function_value (), args, 1);
1130
1131 if (!error_state && tmp.length () >= 1)
1132 {
1133 if (tmp(0).is_string ())
1134 retval = tmp(0).all_strings (pad);
1135 else
1136 error ("cname/char method did not return a character string");
1137 }
1138 }
1139 else
1140 error ("no char method defined for class %s", class_name ().c_str ());
1141
1142 return retval;
1143 }
1144
1145
1146 void
1147 octave_class::print (std::ostream& os, bool) const
1148 {
1149 print_raw (os);
1150 }
1151
1152 void
1153 octave_class::print_raw (std::ostream& os, bool) const
1154 {
1155 unwind_protect frame;
1156
1157 indent (os);
1158 os << " <class " << class_name () << ">";
1159 newline (os);
1160 }
1161
1162 bool
1163 octave_class::print_name_tag (std::ostream& os, const std::string& name) const
1164 {
1165 bool retval = false;
1166
1167 indent (os);
1168 os << name << " =";
1169 newline (os);
1170 if (! Vcompact_format)
1171 newline (os);
1172
1173 return retval;
1174 }
1175
1176 void
1177 octave_class::print_with_name (std::ostream& os, const std::string& name,
1178 bool)
1179 {
1180 octave_value fcn = symbol_table::find_method ("display", class_name ());
1181
1182 if (fcn.is_defined ())
1183 {
1184 octave_value_list args;
1185
1186 count++;
1187 args(0) = octave_value (this);
1188
1189 string_vector arg_names (1);
1190
1191 arg_names[0] = name;
1192
1193 args.stash_name_tags (arg_names);
1194
1195 feval (fcn.function_value (), args);
1196 }
1197 else
1198 {
1199 indent (os);
1200 os << name << " = <class " << class_name () << ">";
1201 newline (os);
1202 }
1203 }
1204
1205 // Loading a class properly requires an exemplar map entry for success.
1206 // If we don't have one, we attempt to create one by calling the constructor
1207 // with no arguments.
1208 bool
1209 octave_class::reconstruct_exemplar (void)
1210 {
1211 bool retval = false;
1212
1213 octave_class::exemplar_const_iterator it
1214 = octave_class::exemplar_map.find (c_name);
1215
1216 if (it != octave_class::exemplar_map.end ())
1217 retval = true;
1218 else
1219 {
1220 octave_value ctor = symbol_table::find_method (c_name, c_name);
1221
1222 bool have_ctor = false;
1223
1224 if (ctor.is_defined () && ctor.is_function ())
1225 {
1226 octave_function *fcn = ctor.function_value ();
1227
1228 if (fcn && fcn->is_class_constructor (c_name))
1229 have_ctor = true;
1230
1231 // Something has gone terribly wrong if
1232 // symbol_table::find_method (c_name, c_name) does not return
1233 // a class constructor for the class c_name...
1234 assert (have_ctor);
1235 }
1236
1237 if (have_ctor)
1238 {
1239 octave_value_list result
1240 = ctor.do_multi_index_op (1, octave_value_list ());
1241
1242 if (result.length () == 1)
1243 retval = true;
1244 else
1245 warning ("call to constructor for class %s failed", c_name.c_str ());
1246 }
1247 else
1248 warning ("no constructor for class %s", c_name.c_str ());
1249 }
1250
1251 return retval;
1252 }
1253
1254 void
1255 octave_class::clear_exemplar_map (void)
1256 {
1257 exemplar_map.clear ();
1258 }
1259
1260 // Load/save does not provide enough information to reconstruct the
1261 // class inheritance structure. reconstruct_parents () attempts to
1262 // do so. If successful, a "true" value is returned.
1263 //
1264 // Note that we don't check the loaded object structure against the
1265 // class structure here so the user's loadobj method has a chance
1266 // to do its magic.
1267 bool
1268 octave_class::reconstruct_parents (void)
1269 {
1270 bool retval = true, might_have_inheritance = false;
1271 std::string dbgstr = "dork";
1272
1273 // First, check to see if there might be an issue with inheritance.
1274 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
1275 {
1276 std::string key = map.key (p);
1277 Cell val = map.contents (p);
1278 if ( val(0).is_object () )
1279 {
1280 dbgstr = "blork";
1281 if ( key == val(0).class_name () )
1282 {
1283 might_have_inheritance = true;
1284 dbgstr = "cork";
1285 break;
1286 }
1287 }
1288 }
1289
1290 if (might_have_inheritance)
1291 {
1292 octave_class::exemplar_const_iterator it
1293 = octave_class::exemplar_map.find (c_name);
1294
1295 if (it == octave_class::exemplar_map.end ())
1296 retval = false;
1297 else
1298 {
1299 octave_class::exemplar_info exmplr = it->second;
1300 parent_list = exmplr.parents ();
1301 for (std::list<std::string>::iterator pit = parent_list.begin ();
1302 pit != parent_list.end ();
1303 pit++)
1304 {
1305 dbgstr = *pit;
1306 bool dbgbool = map.contains (*pit);
1307 if (!dbgbool)
1308 {
1309 retval = false;
1310 break;
1311 }
1312 }
1313 }
1314 }
1315
1316 return retval;
1317 }
1318
1319 bool
1320 octave_class::save_ascii (std::ostream& os)
1321 {
1322 os << "# classname: " << class_name () << "\n";
1323 octave_map m;
1324 if (load_path::find_method (class_name (), "saveobj") != std::string ())
1325 {
1326 octave_value in = new octave_class (*this);
1327 octave_value_list tmp = feval ("saveobj", in, 1);
1328 if (! error_state)
1329 m = tmp(0).map_value ();
1330 else
1331 return false;
1332 }
1333 else
1334 m = map_value ();
1335
1336 os << "# length: " << m.nfields () << "\n";
1337
1338 octave_map::iterator i = m.begin ();
1339 while (i != m.end ())
1340 {
1341 octave_value val = map.contents (i);
1342
1343 bool b = save_ascii_data (os, val, m.key (i), false, 0);
1344
1345 if (! b)
1346 return os;
1347
1348 i++;
1349 }
1350
1351 return true;
1352 }
1353
1354 bool
1355 octave_class::load_ascii (std::istream& is)
1356 {
1357 octave_idx_type len = 0;
1358 std::string classname;
1359 bool success = true;
1360
1361 if (extract_keyword (is, "classname", classname) && classname != "")
1362 {
1363 if (extract_keyword (is, "length", len) && len >= 0)
1364 {
1365 if (len > 0)
1366 {
1367 octave_map m (map);
1368
1369 for (octave_idx_type j = 0; j < len; j++)
1370 {
1371 octave_value t2;
1372 bool dummy;
1373
1374 // recurse to read cell elements
1375 std::string nm
1376 = read_ascii_data (is, std::string (), dummy, t2, j);
1377
1378 if (! is)
1379 break;
1380
1381 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1382
1383 if (error_state)
1384 {
1385 error ("load: internal error loading class elements");
1386 return false;
1387 }
1388
1389 m.assign (nm, tcell);
1390 }
1391
1392 if (is)
1393 {
1394 c_name = classname;
1395 reconstruct_exemplar ();
1396
1397 map = m;
1398
1399 if (! reconstruct_parents ())
1400 warning ("load: unable to reconstruct object inheritance");
1401 else
1402 {
1403 if (load_path::find_method (classname, "loadobj")
1404 != std::string ())
1405 {
1406 octave_value in = new octave_class (*this);
1407 octave_value_list tmp = feval ("loadobj", in, 1);
1408
1409 if (! error_state)
1410 map = tmp(0).map_value ();
1411 else
1412 success = false;
1413 }
1414 }
1415 }
1416 else
1417 {
1418 error ("load: failed to load class");
1419 success = false;
1420 }
1421 }
1422 else if (len == 0 )
1423 {
1424 map = octave_map (dim_vector (1, 1));
1425 c_name = classname;
1426 }
1427 else
1428 panic_impossible ();
1429 }
1430 else
1431 {
1432 error ("load: failed to extract number of elements in class");
1433 success = false;
1434 }
1435 }
1436 else
1437 {
1438 error ("load: failed to extract name of class");
1439 success = false;
1440 }
1441
1442 return success;
1443 }
1444
1445 bool
1446 octave_class::save_binary (std::ostream& os, bool& save_as_floats)
1447 {
1448 int32_t classname_len = class_name ().length ();
1449
1450 os.write (reinterpret_cast<char *> (&classname_len), 4);
1451 os << class_name ();
1452
1453 octave_map m;
1454 if (load_path::find_method (class_name (), "saveobj") != std::string ())
1455 {
1456 octave_value in = new octave_class (*this);
1457 octave_value_list tmp = feval ("saveobj", in, 1);
1458 if (! error_state)
1459 m = tmp(0).map_value ();
1460 else
1461 return false;
1462 }
1463 else
1464 m = map_value ();
1465
1466 int32_t len = m.nfields ();
1467 os.write (reinterpret_cast<char *> (&len), 4);
1468
1469 octave_map::iterator i = m.begin ();
1470 while (i != m.end ())
1471 {
1472 octave_value val = map.contents (i);
1473
1474 bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
1475
1476 if (! b)
1477 return os;
1478
1479 i++;
1480 }
1481
1482 return true;
1483 }
1484
1485 bool
1486 octave_class::load_binary (std::istream& is, bool swap,
1487 oct_mach_info::float_format fmt)
1488 {
1489 bool success = true;
1490
1491 int32_t classname_len;
1492
1493 is.read (reinterpret_cast<char *> (&classname_len), 4);
1494 if (! is)
1495 return false;
1496 else if (swap)
1497 swap_bytes<4> (&classname_len);
1498
1499 {
1500 OCTAVE_LOCAL_BUFFER (char, classname, classname_len+1);
1501 classname[classname_len] = '\0';
1502 if (! is.read (reinterpret_cast<char *> (classname), classname_len))
1503 return false;
1504 c_name = classname;
1505 }
1506 reconstruct_exemplar ();
1507
1508 int32_t len;
1509 if (! is.read (reinterpret_cast<char *> (&len), 4))
1510 return false;
1511 if (swap)
1512 swap_bytes<4> (&len);
1513
1514 if (len > 0)
1515 {
1516 octave_map m (map);
1517
1518 for (octave_idx_type j = 0; j < len; j++)
1519 {
1520 octave_value t2;
1521 bool dummy;
1522 std::string doc;
1523
1524 // recurse to read cell elements
1525 std::string nm = read_binary_data (is, swap, fmt, std::string (),
1526 dummy, t2, doc);
1527
1528 if (! is)
1529 break;
1530
1531 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1532
1533 if (error_state)
1534 {
1535 error ("load: internal error loading class elements");
1536 return false;
1537 }
1538
1539 m.assign (nm, tcell);
1540 }
1541
1542 if (is)
1543 {
1544 map = m;
1545
1546 if (! reconstruct_parents ())
1547 warning ("load: unable to reconstruct object inheritance");
1548 else
1549 {
1550 if (load_path::find_method (c_name, "loadobj") != std::string ())
1551 {
1552 octave_value in = new octave_class (*this);
1553 octave_value_list tmp = feval ("loadobj", in, 1);
1554
1555 if (! error_state)
1556 map = tmp(0).map_value ();
1557 else
1558 success = false;
1559 }
1560 }
1561 }
1562 else
1563 {
1564 warning ("load: failed to load class");
1565 success = false;
1566 }
1567 }
1568 else if (len == 0 )
1569 map = octave_map (dim_vector (1, 1));
1570 else
1571 panic_impossible ();
1572
1573 return success;
1574 }
1575
1576 #if defined (HAVE_HDF5)
1577
1578 bool
1579 octave_class::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
1580 {
1581 hsize_t hdims[3];
1582 hid_t group_hid = -1;
1583 hid_t type_hid = -1;
1584 hid_t space_hid = -1;
1585 hid_t class_hid = -1;
1586 hid_t data_hid = -1;
1587 octave_map m;
1588 octave_map::iterator i;
1589
1590 #if HAVE_HDF5_18
1591 group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1592 #else
1593 group_hid = H5Gcreate (loc_id, name, 0);
1594 #endif
1595 if (group_hid < 0)
1596 goto error_cleanup;
1597
1598 // Add the class name to the group
1599 type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, c_name.length () + 1);
1600 if (type_hid < 0)
1601 goto error_cleanup;
1602
1603 hdims[0] = 0;
1604 space_hid = H5Screate_simple (0 , hdims, 0);
1605 if (space_hid < 0)
1606 goto error_cleanup;
1607 #if HAVE_HDF5_18
1608 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
1609 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1610 #else
1611 class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid,
1612 H5P_DEFAULT);
1613 #endif
1614 if (class_hid < 0 || H5Dwrite (class_hid, type_hid, H5S_ALL, H5S_ALL,
1615 H5P_DEFAULT, c_name.c_str ()) < 0)
1616 goto error_cleanup;
1617
1618 #if HAVE_HDF5_18
1619 data_hid = H5Gcreate (group_hid, "value", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1620 #else
1621 data_hid = H5Gcreate (group_hid, "value", 0);
1622 #endif
1623 if (data_hid < 0)
1624 goto error_cleanup;
1625
1626 if (load_path::find_method (class_name (), "saveobj") != std::string ())
1627 {
1628 octave_value in = new octave_class (*this);
1629 octave_value_list tmp = feval ("saveobj", in, 1);
1630 if (! error_state)
1631 m = tmp(0).map_value ();
1632 else
1633 goto error_cleanup;
1634 }
1635 else
1636 m = map_value ();
1637
1638 // recursively add each element of the class to this group
1639 i = m.begin ();
1640 while (i != m.end ())
1641 {
1642 octave_value val = map.contents (i);
1643
1644 bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false,
1645 save_as_floats);
1646
1647 if (! retval2)
1648 break;
1649
1650 i++;
1651 }
1652
1653 error_cleanup:
1654
1655 if (data_hid > 0)
1656 H5Gclose (data_hid);
1657
1658 if (class_hid > 0)
1659 H5Dclose (class_hid);
1660
1661 if (space_hid > 0)
1662 H5Sclose (space_hid);
1663
1664 if (type_hid > 0)
1665 H5Tclose (type_hid);
1666
1667 if (group_hid > 0)
1668 H5Gclose (group_hid);
1669
1670 return true;
1671 }
1672
1673 bool
1674 octave_class::load_hdf5 (hid_t loc_id, const char *name)
1675 {
1676 bool retval = false;
1677
1678 hid_t group_hid = -1;
1679 hid_t data_hid = -1;
1680 hid_t type_hid = -1;
1681 hid_t type_class_hid = -1;
1682 hid_t space_hid = -1;
1683 hid_t subgroup_hid = -1;
1684 hid_t st_id = -1;
1685
1686 hdf5_callback_data dsub;
1687
1688 herr_t retval2 = 0;
1689 octave_map m (dim_vector (1, 1));
1690 int current_item = 0;
1691 hsize_t num_obj = 0;
1692 int slen = 0;
1693 hsize_t rank = 0;
1694
1695 #if HAVE_HDF5_18
1696 group_hid = H5Gopen (loc_id, name, H5P_DEFAULT);
1697 #else
1698 group_hid = H5Gopen (loc_id, name);
1699 #endif
1700 if (group_hid < 0)
1701 goto error_cleanup;
1702
1703 #if HAVE_HDF5_18
1704 data_hid = H5Dopen (group_hid, "classname", H5P_DEFAULT);
1705 #else
1706 data_hid = H5Dopen (group_hid, "classname");
1707 #endif
1708
1709 if (data_hid < 0)
1710 goto error_cleanup;
1711
1712 type_hid = H5Dget_type (data_hid);
1713
1714 type_class_hid = H5Tget_class (type_hid);
1715
1716 if (type_class_hid != H5T_STRING)
1717 goto error_cleanup;
1718
1719 space_hid = H5Dget_space (data_hid);
1720 rank = H5Sget_simple_extent_ndims (space_hid);
1721
1722 if (rank != 0)
1723 goto error_cleanup;
1724
1725 slen = H5Tget_size (type_hid);
1726 if (slen < 0)
1727 goto error_cleanup;
1728
1729 // do-while loop here to prevent goto crossing initialization of classname
1730 do
1731 {
1732 OCTAVE_LOCAL_BUFFER (char, classname, slen);
1733
1734 // create datatype for (null-terminated) string to read into:
1735 st_id = H5Tcopy (H5T_C_S1);
1736 H5Tset_size (st_id, slen);
1737
1738 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
1739 classname) < 0)
1740 {
1741 H5Tclose (st_id);
1742 H5Dclose (data_hid);
1743 H5Gclose (group_hid);
1744 return false;
1745 }
1746
1747 H5Tclose (st_id);
1748 H5Dclose (data_hid);
1749 data_hid = -1;
1750
1751 c_name = classname;
1752 }
1753 while (0);
1754 reconstruct_exemplar ();
1755
1756 #if HAVE_HDF5_18
1757 subgroup_hid = H5Gopen (group_hid, name, H5P_DEFAULT);
1758 #else
1759 subgroup_hid = H5Gopen (group_hid, name);
1760 #endif
1761 H5Gget_num_objs (subgroup_hid, &num_obj);
1762 H5Gclose (subgroup_hid);
1763
1764 while (current_item < static_cast<int> (num_obj)
1765 && (retval2 = H5Giterate (group_hid, name, &current_item,
1766 hdf5_read_next_data, &dsub)) > 0)
1767 {
1768 octave_value t2 = dsub.tc;
1769
1770 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
1771
1772 if (error_state)
1773 {
1774 error ("load: internal error loading class elements");
1775 return false;
1776 }
1777
1778 m.assign (dsub.name, tcell);
1779
1780 }
1781
1782 if (retval2 >= 0)
1783 {
1784 map = m;
1785
1786 if (!reconstruct_parents ())
1787 warning ("load: unable to reconstruct object inheritance");
1788 else
1789 {
1790 if (load_path::find_method (c_name, "loadobj") != std::string ())
1791 {
1792 octave_value in = new octave_class (*this);
1793 octave_value_list tmp = feval ("loadobj", in, 1);
1794
1795 if (! error_state)
1796 {
1797 map = tmp(0).map_value ();
1798 retval = true;
1799 }
1800 else
1801 retval = false;
1802 }
1803 else
1804 retval = true;
1805 }
1806 }
1807
1808 error_cleanup:
1809 if (data_hid > 0)
1810 H5Dclose (data_hid);
1811
1812 if (data_hid > 0)
1813 H5Gclose (group_hid);
1814
1815 return retval;
1816 }
1817
1818 #endif
1819
1820 mxArray *
1821 octave_class::as_mxArray (void) const
1822 {
1823 gripe_wrong_type_arg ("octave_class::as_mxArray ()", type_name ());
1824
1825 return 0;
1826 }
1827
1828 bool
1829 octave_class::in_class_method (void)
1830 {
1831 octave_function *fcn = octave_call_stack::current ();
1832
1833 return (fcn
1834 && (fcn->is_class_method ()
1835 || fcn->is_class_constructor ()
1836 || fcn->is_anonymous_function_of_class ()
1837 || fcn->is_private_function_of_class (class_name ()))
1838 && find_parent_class (fcn->dispatch_class ()));
1839 }
1840
1841 octave_class::exemplar_info::exemplar_info (const octave_value& obj)
1842 : field_names (), parent_class_names ()
1843 {
1844 if (obj.is_object ())
1845 {
1846 octave_map m = obj.map_value ();
1847 field_names = m.keys ();
1848
1849 parent_class_names = obj.parent_class_name_list ();
1850 }
1851 else
1852 error ("invalid call to exemplar_info constructor");
1853 }
1854
1855
1856 // A map from class names to lists of fields.
1857 std::map<std::string, octave_class::exemplar_info> octave_class::exemplar_map;
1858
1859 bool
1860 octave_class::exemplar_info::compare (const octave_value& obj) const
1861 {
1862 bool retval = true;
1863
1864 if (obj.is_object ())
1865 {
1866 if (nfields () == obj.nfields ())
1867 {
1868 octave_map obj_map = obj.map_value ();
1869 string_vector obj_fnames = obj_map.keys ();
1870 string_vector fnames = fields ();
1871
1872 for (octave_idx_type i = 0; i < nfields (); i++)
1873 {
1874 if (obj_fnames[i] != fnames[i])
1875 {
1876 retval = false;
1877 error ("mismatch in field names");
1878 break;
1879 }
1880 }
1881
1882 if (nparents () == obj.nparents ())
1883 {
1884 std::list<std::string> obj_parents
1885 = obj.parent_class_name_list ();
1886 std::list<std::string> pnames = parents ();
1887
1888 std::list<std::string>::const_iterator p = obj_parents.begin ();
1889 std::list<std::string>::const_iterator q = pnames.begin ();
1890
1891 while (p != obj_parents.end ())
1892 {
1893 if (*p++ != *q++)
1894 {
1895 retval = false;
1896 error ("mismatch in parent classes");
1897 break;
1898 }
1899 }
1900 }
1901 else
1902 {
1903 retval = false;
1904 error ("mismatch in number of parent classes");
1905 }
1906 }
1907 else
1908 {
1909 retval = false;
1910 error ("mismatch in number of fields");
1911 }
1912 }
1913 else
1914 {
1915 retval = false;
1916 error ("invalid comparison of class exemplar to non-class object");
1917 }
1918
1919 return retval;
1920 }
1921
1922 DEFUN (class, args, ,
1923 "-*- texinfo -*-\n\
1924 @deftypefn {Built-in Function} {} class (@var{expr})\n\
1925 @deftypefnx {Built-in Function} {} class (@var{s}, @var{id})\n\
1926 @deftypefnx {Built-in Function} {} class (@var{s}, @var{id}, @var{p}, @dots{})\n\
1927 Return the class of the expression @var{expr} or create a class with\n\
1928 fields from structure @var{s} and name (string) @var{id}. Additional\n\
1929 arguments name a list of parent classes from which the new class is\n\
1930 derived.\n\
1931 @end deftypefn")
1932 {
1933 octave_value retval;
1934
1935 int nargin = args.length ();
1936
1937 if (nargin == 0)
1938 print_usage ();
1939 else if (nargin == 1)
1940 retval = args(0).class_name ();
1941 else
1942 {
1943 octave_function *fcn = octave_call_stack::caller ();
1944
1945 std::string id = args(1).string_value ();
1946
1947 if (! error_state)
1948 {
1949 if (fcn)
1950 {
1951 if (fcn->is_class_constructor (id) || fcn->is_class_method (id))
1952 {
1953 octave_map m = args(0).map_value ();
1954
1955 if (! error_state)
1956 {
1957 if (nargin == 2)
1958 retval
1959 = octave_value (new octave_class
1960 (m, id, std::list<std::string> ()));
1961 else
1962 {
1963 octave_value_list parents = args.slice (2, nargin-2);
1964
1965 retval
1966 = octave_value (new octave_class (m, id, parents));
1967 }
1968
1969 if (! error_state)
1970 {
1971 octave_class::exemplar_const_iterator it
1972 = octave_class::exemplar_map.find (id);
1973
1974 if (it == octave_class::exemplar_map.end ())
1975 octave_class::exemplar_map[id]
1976 = octave_class::exemplar_info (retval);
1977 else if (! it->second.compare (retval))
1978 error ("class: object of class `%s' does not match previously constructed objects",
1979 id.c_str ());
1980 }
1981 }
1982 else
1983 error ("class: expecting structure S as first argument");
1984 }
1985 else
1986 error ("class: `%s' is invalid as a class name in this context",
1987 id.c_str ());
1988 }
1989 else
1990 error ("class: invalid call from outside class constructor or method");
1991 }
1992 else
1993 error ("class: ID (class name) must be a character string");
1994 }
1995
1996 return retval;
1997 }
1998
1999 DEFUN (__isa_parent__, args, ,
2000 "-*- texinfo -*-\n\
2001 @deftypefn {Built-in Function} {} __isa_parent__ (@var{class}, @var{name})\n\
2002 Undocumented internal function.\n\
2003 @end deftypefn")
2004 {
2005 octave_value retval = false;
2006
2007 if (args.length () == 2)
2008 {
2009 octave_value cls = args(0);
2010 octave_value nm = args(1);
2011
2012 if (! error_state)
2013 {
2014 if (cls.find_parent_class (nm.string_value ()))
2015 retval = true;
2016 }
2017 else
2018 error ("__isa_parent__: expecting arguments to be character strings");
2019 }
2020 else
2021 print_usage ();
2022
2023 return retval;
2024 }
2025
2026 DEFUN (__parent_classes__, args, ,
2027 "-*- texinfo -*-\n\
2028 @deftypefn {Built-in Function} {} __parent_classes__ (@var{x})\n\
2029 Undocumented internal function.\n\
2030 @end deftypefn")
2031 {
2032 octave_value retval = Cell ();
2033
2034 if (args.length () == 1)
2035 {
2036 octave_value arg = args(0);
2037
2038 if (arg.is_object ())
2039 retval = Cell (arg.parent_class_names ());
2040 }
2041 else
2042 print_usage ();
2043
2044 return retval;
2045 }
2046
2047 DEFUN (isobject, args, ,
2048 "-*- texinfo -*-\n\
2049 @deftypefn {Built-in Function} {} isobject (@var{x})\n\
2050 Return true if @var{x} is a class object.\n\
2051 @seealso{class, typeinfo, isa, ismethod}\n\
2052 @end deftypefn")
2053 {
2054 octave_value retval;
2055
2056 if (args.length () == 1)
2057 retval = args(0).is_object ();
2058 else
2059 print_usage ();
2060
2061 return retval;
2062 }
2063
2064 DEFUN (ismethod, args, ,
2065 "-*- texinfo -*-\n\
2066 @deftypefn {Built-in Function} {} ismethod (@var{x}, @var{method})\n\
2067 Return true if @var{x} is a class object and the string @var{method}\n\
2068 is a method of this class.\n\
2069 @seealso{isobject}\n\
2070 @end deftypefn")
2071 {
2072 octave_value retval;
2073
2074 if (args.length () == 2)
2075 {
2076 octave_value arg = args(0);
2077
2078 std::string class_name;
2079
2080 if (arg.is_object ())
2081 class_name = arg.class_name ();
2082 else if (arg.is_string ())
2083 class_name = arg.string_value ();
2084 else
2085 error ("ismethod: expecting object or class name as first argument");
2086
2087 if (! error_state)
2088 {
2089 std::string method = args(1).string_value ();
2090
2091 if (! error_state)
2092 {
2093 if (load_path::find_method (class_name, method) != std::string ())
2094 retval = true;
2095 else
2096 retval = false;
2097 }
2098 }
2099 }
2100 else
2101 print_usage ();
2102
2103 return retval;
2104 }
2105
2106 DEFUN (methods, args, nargout,
2107 "-*- texinfo -*-\n\
2108 @deftypefn {Built-in Function} {} methods (@var{x})\n\
2109 @deftypefnx {Built-in Function} {} methods (\"classname\")\n\
2110 Return a cell array containing the names of the methods for the\n\
2111 object @var{x} or the named class.\n\
2112 @end deftypefn")
2113 {
2114 octave_value retval;
2115
2116 if (args.length () == 1)
2117 {
2118 octave_value arg = args(0);
2119
2120 std::string class_name;
2121
2122 if (arg.is_object ())
2123 class_name = arg.class_name ();
2124 else if (arg.is_string ())
2125 class_name = arg.string_value ();
2126 else
2127 error ("methods: expecting object or class name as argument");
2128
2129 if (! error_state)
2130 {
2131 string_vector sv = load_path::methods (class_name);
2132
2133 if (nargout == 0)
2134 {
2135 octave_stdout << "Methods for class " << class_name << ":\n\n";
2136
2137 sv.list_in_columns (octave_stdout);
2138
2139 octave_stdout << std::endl;
2140 }
2141 else
2142 retval = Cell (sv);
2143 }
2144 }
2145 else
2146 print_usage ();
2147
2148 return retval;
2149 }
2150
2151 static bool
2152 is_built_in_class (const std::string& cn)
2153 {
2154 static std::set<std::string> built_in_class_names;
2155
2156 if (built_in_class_names.empty ())
2157 {
2158 built_in_class_names.insert ("double");
2159 built_in_class_names.insert ("single");
2160 built_in_class_names.insert ("cell");
2161 built_in_class_names.insert ("struct");
2162 built_in_class_names.insert ("logical");
2163 built_in_class_names.insert ("char");
2164 built_in_class_names.insert ("function handle");
2165 built_in_class_names.insert ("int8");
2166 built_in_class_names.insert ("uint8");
2167 built_in_class_names.insert ("int16");
2168 built_in_class_names.insert ("uint16");
2169 built_in_class_names.insert ("int32");
2170 built_in_class_names.insert ("uint32");
2171 built_in_class_names.insert ("int64");
2172 built_in_class_names.insert ("uint64");
2173 }
2174
2175 return built_in_class_names.find (cn) != built_in_class_names.end ();
2176 }
2177
2178 DEFUN (superiorto, args, ,
2179 "-*- texinfo -*-\n\
2180 @deftypefn {Built-in Function} {} superiorto (@var{class_name}, @dots{})\n\
2181 When called from a class constructor, mark the object currently\n\
2182 constructed as having a higher precedence than @var{class_name}.\n\
2183 More that one such class can be specified in a single call.\n\
2184 This function may only be called from a class constructor.\n\
2185 @end deftypefn")
2186 {
2187 octave_value retval;
2188
2189 octave_function *fcn = octave_call_stack::caller ();
2190
2191 if (fcn && fcn->is_class_constructor ())
2192 {
2193 for (int i = 0; i < args.length (); i++)
2194 {
2195 std::string class_name = args(i).string_value ();
2196
2197 if (! error_state)
2198 {
2199 if (! is_built_in_class (class_name))
2200 {
2201 std::string this_class_name = fcn->name ();
2202
2203 if (! symbol_table::set_class_relationship (this_class_name,
2204 class_name))
2205 {
2206 error ("superiorto: precedence already set for %s and %s",
2207 this_class_name.c_str (), class_name.c_str ());
2208 break;
2209 }
2210 }
2211 else
2212 {
2213 // User defined classes always have higher precedence
2214 // than built-in classes.
2215 }
2216 }
2217 else
2218 {
2219 error ("superiorto: expecting argument to be class name");
2220 break;
2221 }
2222 }
2223 }
2224 else
2225 error ("superiorto: invalid call from outside class constructor");
2226
2227 return retval;
2228 }
2229
2230 DEFUN (inferiorto, args, ,
2231 "-*- texinfo -*-\n\
2232 @deftypefn {Built-in Function} {} inferiorto (@var{class_name}, @dots{})\n\
2233 When called from a class constructor, mark the object currently\n\
2234 constructed as having a lower precedence than @var{class_name}.\n\
2235 More that one such class can be specified in a single call.\n\
2236 This function may only be called from a class constructor.\n\
2237 @end deftypefn")
2238 {
2239 octave_value retval;
2240
2241 octave_function *fcn = octave_call_stack::caller ();
2242
2243 if (fcn && fcn->is_class_constructor ())
2244 {
2245 for (int i = 0; i < args.length (); i++)
2246 {
2247 std::string class_name = args(i).string_value ();
2248
2249 if (! error_state)
2250 {
2251 if (! is_built_in_class (class_name))
2252 {
2253 std::string this_class_name = fcn->name ();
2254
2255 symbol_table::set_class_relationship (class_name,
2256 this_class_name);
2257
2258 if (! symbol_table::set_class_relationship (this_class_name,
2259 class_name))
2260 {
2261 error ("inferiorto: precedence already set for %s and %s",
2262 this_class_name.c_str (), class_name.c_str ());
2263 break;
2264 }
2265 }
2266 else
2267 {
2268 error ("inferiorto: cannot give user-defined class lower precedence than built-in class");
2269 break;
2270 }
2271 }
2272 else
2273 {
2274 error ("inferiorto: expecting argument to be class name");
2275 break;
2276 }
2277 }
2278 }
2279 else
2280 error ("inferiorto: invalid call from outside class constructor");
2281
2282 return retval;
2283 }