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