Mercurial > hg > octave-lyh
comparison src/ov-class.cc @ 9529:8e5009334661
partially revert e79470be3ecb
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Mon, 17 Aug 2009 13:09:12 +0200 |
parents | e79470be3ecb |
children | 8bf27324a9d0 |
comparison
equal
deleted
inserted
replaced
9528:ec066ba012c8 | 9529:8e5009334661 |
---|---|
66 (octave_class::t_name, "<unknown>", octave_value (new octave_class ())); | 66 (octave_class::t_name, "<unknown>", octave_value (new octave_class ())); |
67 } | 67 } |
68 | 68 |
69 octave_class::octave_class (const Octave_map& m, const std::string& id, | 69 octave_class::octave_class (const Octave_map& m, const std::string& id, |
70 const octave_value_list& parents) | 70 const octave_value_list& parents) |
71 : octave_struct (m), c_name (id), obsolete_copies (0) | 71 : octave_base_value (), map (m), c_name (id), obsolete_copies (0) |
72 { | 72 { |
73 octave_idx_type n = parents.length (); | 73 octave_idx_type n = parents.length (); |
74 | 74 |
75 for (octave_idx_type idx = 0; idx < n; idx++) | 75 for (octave_idx_type idx = 0; idx < n; idx++) |
76 { | 76 { |
134 | 134 |
135 static void | 135 static void |
136 gripe_invalid_index (void) | 136 gripe_invalid_index (void) |
137 { | 137 { |
138 error ("invalid index for class"); | 138 error ("invalid index for class"); |
139 } | |
140 | |
141 static void | |
142 gripe_invalid_index_for_assignment (void) | |
143 { | |
144 error ("invalid index for class assignment"); | |
145 } | |
146 | |
147 static void | |
148 gripe_invalid_index_type (const std::string& nm, char t) | |
149 { | |
150 error ("%s cannot be indexed with %c", nm.c_str (), t); | |
151 } | |
152 | |
153 static void | |
154 gripe_failed_assignment (void) | |
155 { | |
156 error ("assignment to class element failed"); | |
139 } | 157 } |
140 | 158 |
141 static inline octave_value_list | 159 static inline octave_value_list |
142 sanitize (const octave_value_list& ovl) | 160 sanitize (const octave_value_list& ovl) |
143 { | 161 { |
369 int nargout) | 387 int nargout) |
370 { | 388 { |
371 octave_value_list retval; | 389 octave_value_list retval; |
372 | 390 |
373 if (in_class_method () || called_from_builtin ()) | 391 if (in_class_method () || called_from_builtin ()) |
374 retval = octave_struct::subsref (type, idx, nargout); | 392 { |
393 // FIXME -- this block of code is the same as the body of | |
394 // octave_struct::subsref. Maybe it could be shared instead of | |
395 // duplicated. | |
396 | |
397 int skip = 1; | |
398 | |
399 switch (type[0]) | |
400 { | |
401 case '(': | |
402 { | |
403 if (type.length () > 1 && type[1] == '.') | |
404 { | |
405 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
406 octave_value_list key_idx = *++p; | |
407 | |
408 Cell tmp = dotref (key_idx); | |
409 | |
410 if (! error_state) | |
411 { | |
412 Cell t = tmp.index (idx.front ()); | |
413 | |
414 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); | |
415 | |
416 // We handled two index elements, so tell | |
417 // next_subsref to skip both of them. | |
418 | |
419 skip++; | |
420 } | |
421 } | |
422 else | |
423 retval(0) = octave_value (map.index (idx.front ()), | |
424 class_name ()); | |
425 } | |
426 break; | |
427 | |
428 case '.': | |
429 { | |
430 if (map.numel() > 0) | |
431 { | |
432 Cell t = dotref (idx.front ()); | |
433 | |
434 retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); | |
435 } | |
436 } | |
437 break; | |
438 | |
439 case '{': | |
440 gripe_invalid_index_type (type_name (), type[0]); | |
441 break; | |
442 | |
443 default: | |
444 panic_impossible (); | |
445 } | |
446 | |
447 // FIXME -- perhaps there should be an | |
448 // octave_value_list::next_subsref member function? See also | |
449 // octave_user_function::subsref. | |
450 | |
451 if (idx.size () > 1) | |
452 retval = retval(0).next_subsref (nargout, type, idx, skip); | |
453 } | |
375 else | 454 else |
376 { | 455 { |
377 octave_value meth = symbol_table::find_method ("subsref", class_name ()); | 456 octave_value meth = symbol_table::find_method ("subsref", class_name ()); |
378 | 457 |
379 if (meth.is_defined ()) | 458 if (meth.is_defined ()) |
420 } | 499 } |
421 | 500 |
422 return retval; | 501 return retval; |
423 } | 502 } |
424 | 503 |
425 octave_value | 504 octave_value |
426 octave_class::subsref (const std::string& type, | 505 octave_class::numeric_conv (const Cell& val, const std::string& type) |
427 const std::list<octave_value_list>& idx, | |
428 bool auto_add) | |
429 { | |
430 if (in_class_method () || called_from_builtin ()) | |
431 return octave_struct::subsref (type, idx, auto_add); | |
432 else | |
433 return subsref (type, idx); | |
434 | |
435 } | |
436 | |
437 void | |
438 octave_class::gripe_failed_assignment (void) | |
439 { | |
440 error ("assignment to class element failed"); | |
441 } | |
442 | |
443 octave_value | |
444 octave_class::dotasgn (const octave_value_list& idx, const octave_value& rhs) | |
445 { | 506 { |
446 octave_value retval; | 507 octave_value retval; |
447 | 508 |
448 // Find the class in which this method resides before | 509 if (val.length () == 1) |
449 // attempting to access the requested field. | 510 { |
450 | 511 retval = val(0); |
451 std::string method_class = get_current_method_class (); | 512 |
452 | 513 if (type.length () > 0 && type[0] == '.' && ! retval.is_map ()) |
453 octave_base_value *obvp = find_parent_class (method_class); | 514 retval = Octave_map (); |
454 | 515 } |
455 if (obvp) | 516 else |
456 { | 517 gripe_invalid_index_for_assignment (); |
457 assert (idx.length () == 1); | |
458 | |
459 std::string key = idx(0).string_value (); | |
460 | |
461 if (! error_state) | |
462 { | |
463 obvp->assign (key, rhs); | |
464 | |
465 if (! error_state) | |
466 { | |
467 count++; | |
468 retval = octave_value (this); | |
469 } | |
470 else | |
471 gripe_failed_assignment (); | |
472 } | |
473 else | |
474 gripe_failed_assignment (); | |
475 } | |
476 else | |
477 error ("malformed class"); | |
478 | 518 |
479 return retval; | 519 return retval; |
480 } | 520 } |
481 | 521 |
482 octave_value | 522 octave_value |
483 octave_class::subsasgn (const std::string& type, | 523 octave_class::subsasgn (const std::string& type, |
484 const std::list<octave_value_list>& idx, | 524 const std::list<octave_value_list>& idx, |
485 const octave_value& rhs) | 525 const octave_value& rhs) |
486 { | 526 { |
527 octave_value retval; | |
528 | |
487 if (! (in_class_method () || called_from_builtin ())) | 529 if (! (in_class_method () || called_from_builtin ())) |
488 { | 530 { |
489 octave_value meth = symbol_table::find_method ("subsasgn", class_name ()); | 531 octave_value meth = symbol_table::find_method ("subsasgn", class_name ()); |
490 | 532 |
491 if (meth.is_defined ()) | 533 if (meth.is_defined ()) |
492 { | 534 { |
493 octave_value retval; | |
494 | |
495 octave_value_list args; | 535 octave_value_list args; |
496 | 536 |
497 if (rhs.is_cs_list ()) | 537 if (rhs.is_cs_list ()) |
498 { | 538 { |
499 octave_value_list lrhs = rhs.list_value (); | 539 octave_value_list lrhs = rhs.list_value (); |
552 | 592 |
553 return retval; | 593 return retval; |
554 } | 594 } |
555 } | 595 } |
556 | 596 |
557 return octave_struct::subsasgn (type, idx, rhs); | 597 // FIXME -- this block of code is the same as the body of |
598 // octave_struct::subsasgn. Maybe it could be shared instead of | |
599 // duplicated. | |
600 | |
601 int n = type.length (); | |
602 | |
603 octave_value t_rhs = rhs; | |
604 | |
605 if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.')) | |
606 { | |
607 switch (type[0]) | |
608 { | |
609 case '(': | |
610 { | |
611 if (type.length () > 1 && type[1] == '.') | |
612 { | |
613 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
614 octave_value_list t_idx = *p; | |
615 | |
616 octave_value_list key_idx = *++p; | |
617 | |
618 assert (key_idx.length () == 1); | |
619 | |
620 std::string key = key_idx(0).string_value (); | |
621 | |
622 if (! error_state) | |
623 { | |
624 octave_value u; | |
625 | |
626 if (! map.contains (key)) | |
627 u = octave_value::empty_conv (type.substr (2), rhs); | |
628 else | |
629 { | |
630 Cell map_val = map.contents (key); | |
631 | |
632 Cell map_elt = map_val.index (idx.front (), true); | |
633 | |
634 u = numeric_conv (map_elt, type.substr (2)); | |
635 } | |
636 | |
637 if (! error_state) | |
638 { | |
639 std::list<octave_value_list> next_idx (idx); | |
640 | |
641 // We handled two index elements, so subsasgn to | |
642 // needs to skip both of them. | |
643 | |
644 next_idx.erase (next_idx.begin ()); | |
645 next_idx.erase (next_idx.begin ()); | |
646 | |
647 u.make_unique (); | |
648 | |
649 t_rhs = u.subsasgn (type.substr (2), next_idx, rhs); | |
650 } | |
651 } | |
652 else | |
653 gripe_invalid_index_for_assignment (); | |
654 } | |
655 else | |
656 gripe_invalid_index_for_assignment (); | |
657 } | |
658 break; | |
659 | |
660 case '.': | |
661 { | |
662 octave_value_list key_idx = idx.front (); | |
663 | |
664 assert (key_idx.length () == 1); | |
665 | |
666 std::string key = key_idx(0).string_value (); | |
667 | |
668 std::list<octave_value_list> next_idx (idx); | |
669 | |
670 next_idx.erase (next_idx.begin ()); | |
671 | |
672 std::string next_type = type.substr (1); | |
673 | |
674 Cell tmpc (1, 1); | |
675 Octave_map::iterator pkey = map.seek (key); | |
676 if (pkey != map.end ()) | |
677 { | |
678 pkey->second.make_unique (); | |
679 tmpc = pkey->second; | |
680 } | |
681 | |
682 // FIXME: better code reuse? | |
683 if (! error_state) | |
684 { | |
685 if (tmpc.numel () == 1) | |
686 { | |
687 octave_value& tmp = tmpc(0); | |
688 | |
689 if (! tmp.is_defined () || tmp.is_zero_by_zero ()) | |
690 { | |
691 tmp = octave_value::empty_conv (next_type, rhs); | |
692 tmp.make_unique (); // probably a no-op. | |
693 } | |
694 else | |
695 // optimization: ignore the copy still stored inside our map. | |
696 tmp.make_unique (1); | |
697 | |
698 if (! error_state) | |
699 t_rhs = tmp.subsasgn (next_type, next_idx, rhs); | |
700 } | |
701 else | |
702 gripe_indexed_cs_list (); | |
703 } | |
704 } | |
705 break; | |
706 | |
707 case '{': | |
708 gripe_invalid_index_type (type_name (), type[0]); | |
709 break; | |
710 | |
711 default: | |
712 panic_impossible (); | |
713 } | |
714 } | |
715 | |
716 if (! error_state) | |
717 { | |
718 switch (type[0]) | |
719 { | |
720 case '(': | |
721 { | |
722 if (n > 1 && type[1] == '.') | |
723 { | |
724 std::list<octave_value_list>::const_iterator p = idx.begin (); | |
725 octave_value_list key_idx = *++p; | |
726 | |
727 assert (key_idx.length () == 1); | |
728 | |
729 std::string key = key_idx(0).string_value (); | |
730 | |
731 if (! error_state) | |
732 { | |
733 map.assign (idx.front (), key, t_rhs); | |
734 | |
735 if (! error_state) | |
736 { | |
737 count++; | |
738 retval = octave_value (this); | |
739 } | |
740 else | |
741 gripe_failed_assignment (); | |
742 } | |
743 else | |
744 gripe_failed_assignment (); | |
745 } | |
746 else | |
747 { | |
748 if (t_rhs.is_object () || t_rhs.is_map ()) | |
749 { | |
750 Octave_map rhs_map = t_rhs.map_value (); | |
751 | |
752 if (! error_state) | |
753 { | |
754 map.assign (idx.front (), rhs_map); | |
755 | |
756 if (! error_state) | |
757 { | |
758 count++; | |
759 retval = octave_value (this); | |
760 } | |
761 else | |
762 gripe_failed_assignment (); | |
763 } | |
764 else | |
765 error ("invalid class assignment"); | |
766 } | |
767 else | |
768 { | |
769 if (t_rhs.is_empty ()) | |
770 { | |
771 map.maybe_delete_elements (idx.front()); | |
772 | |
773 if (! error_state) | |
774 { | |
775 count++; | |
776 retval = octave_value (this); | |
777 } | |
778 else | |
779 gripe_failed_assignment (); | |
780 } | |
781 else | |
782 error ("invalid class assignment"); | |
783 } | |
784 } | |
785 } | |
786 break; | |
787 | |
788 case '.': | |
789 { | |
790 // Find the class in which this method resides before | |
791 // attempting to access the requested field. | |
792 | |
793 std::string method_class = get_current_method_class (); | |
794 | |
795 octave_base_value *obvp = find_parent_class (method_class); | |
796 | |
797 if (obvp) | |
798 { | |
799 octave_value_list key_idx = idx.front (); | |
800 | |
801 assert (key_idx.length () == 1); | |
802 | |
803 std::string key = key_idx(0).string_value (); | |
804 | |
805 if (! error_state) | |
806 { | |
807 obvp->assign (key, t_rhs); | |
808 | |
809 if (! error_state) | |
810 { | |
811 count++; | |
812 retval = octave_value (this); | |
813 } | |
814 else | |
815 gripe_failed_assignment (); | |
816 } | |
817 else | |
818 gripe_failed_assignment (); | |
819 } | |
820 else | |
821 error ("malformed class"); | |
822 } | |
823 break; | |
824 | |
825 case '{': | |
826 gripe_invalid_index_type (type_name (), type[0]); | |
827 break; | |
828 | |
829 default: | |
830 panic_impossible (); | |
831 } | |
832 } | |
833 else | |
834 gripe_failed_assignment (); | |
835 | |
836 return retval; | |
558 } | 837 } |
559 | 838 |
560 idx_vector | 839 idx_vector |
561 octave_class::index_vector (void) const | 840 octave_class::index_vector (void) const |
562 { | 841 { |
585 } | 864 } |
586 } | 865 } |
587 else | 866 else |
588 error ("no subsindex method defined for class %s", | 867 error ("no subsindex method defined for class %s", |
589 class_name().c_str ()); | 868 class_name().c_str ()); |
869 | |
870 return retval; | |
871 } | |
872 | |
873 size_t | |
874 octave_class::byte_size (void) const | |
875 { | |
876 // Neglect the size of the fieldnames. | |
877 | |
878 size_t retval = 0; | |
879 | |
880 for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) | |
881 { | |
882 std::string key = map.key (p); | |
883 | |
884 octave_value val = octave_value (map.contents (p)); | |
885 | |
886 retval += val.byte_size (); | |
887 } | |
590 | 888 |
591 return retval; | 889 return retval; |
592 } | 890 } |
593 | 891 |
594 string_vector | 892 string_vector |