Mercurial > octave-nkf
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, ¤t_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 } |