Mercurial > octave-nkf
comparison src/ov-struct.cc @ 10742:604e13a89c7f
initial code for structs rewrite
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Tue, 22 Jun 2010 15:22:36 +0200 |
parents | e0ba186b242b |
children | 58c1b5402588 |
comparison
equal
deleted
inserted
replaced
10718:b8d76f4be94a | 10742:604e13a89c7f |
---|---|
49 | 49 |
50 DEFINE_OCTAVE_ALLOCATOR(octave_struct); | 50 DEFINE_OCTAVE_ALLOCATOR(octave_struct); |
51 | 51 |
52 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct"); | 52 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct"); |
53 | 53 |
54 octave_base_value * | |
55 octave_struct::try_narrowing_conversion (void) | |
56 { | |
57 octave_base_value *retval = 0; | |
58 | |
59 if (numel () == 1) | |
60 retval = new octave_scalar_struct (map.checkelem (0)); | |
61 | |
62 return retval; | |
63 } | |
64 | |
54 Cell | 65 Cell |
55 octave_struct::dotref (const octave_value_list& idx, bool auto_add) | 66 octave_struct::dotref (const octave_value_list& idx, bool auto_add) |
56 { | 67 { |
57 Cell retval; | 68 Cell retval; |
58 | 69 |
59 assert (idx.length () == 1); | 70 assert (idx.length () == 1); |
60 | 71 |
61 std::string nm = idx(0).string_value (); | 72 std::string nm = idx(0).string_value (); |
62 | 73 |
63 Octave_map::const_iterator p = map.seek (nm); | 74 octave_map::const_iterator p = map.seek (nm); |
64 | 75 |
65 if (p != map.end ()) | 76 if (p != map.end ()) |
66 retval = map.contents (p); | 77 retval = map.contents (p); |
67 else if (auto_add) | 78 else if (auto_add) |
68 retval = (numel () == 0) ? Cell (dim_vector (1, 1)) : Cell (dims ()); | 79 retval = (numel () == 0) ? Cell (dim_vector (1, 1)) : Cell (dims ()); |
129 | 140 |
130 skip++; | 141 skip++; |
131 } | 142 } |
132 } | 143 } |
133 else | 144 else |
134 retval(0) = map.index (idx.front ()); | 145 retval(0) = do_index_op (idx.front ()); |
135 } | 146 } |
136 break; | 147 break; |
137 | 148 |
138 case '.': | 149 case '.': |
139 { | 150 { |
195 | 206 |
196 skip++; | 207 skip++; |
197 } | 208 } |
198 } | 209 } |
199 else | 210 else |
200 retval = map.index (idx.front (), auto_add); | 211 retval = do_index_op (idx.front (), auto_add); |
201 } | 212 } |
202 break; | 213 break; |
203 | 214 |
204 case '.': | 215 case '.': |
205 { | 216 { |
243 const std::string& type) | 254 const std::string& type) |
244 { | 255 { |
245 octave_value retval; | 256 octave_value retval; |
246 | 257 |
247 if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) | 258 if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) |
248 retval = Octave_map (); | 259 retval = octave_map (); |
249 else | 260 else |
250 retval = val; | 261 retval = val; |
251 | 262 |
252 return retval; | 263 return retval; |
253 } | 264 } |
295 next_idx.erase (next_idx.begin ()); | 306 next_idx.erase (next_idx.begin ()); |
296 | 307 |
297 std::string next_type = type.substr (2); | 308 std::string next_type = type.substr (2); |
298 | 309 |
299 Cell tmpc (1, 1); | 310 Cell tmpc (1, 1); |
300 Octave_map::iterator pkey = map.seek (key); | 311 octave_map::iterator pkey = map.seek (key); |
301 if (pkey != map.end ()) | 312 if (pkey != map.end ()) |
302 { | 313 { |
303 pkey->second.make_unique (); | 314 map.contents (pkey).make_unique (); |
304 tmpc = pkey->second.index (idx.front (), true); | 315 tmpc = map.contents (pkey).index (idx.front (), true); |
305 } | 316 } |
306 | 317 |
307 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below. | 318 // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below. |
308 if (! error_state) | 319 if (! error_state) |
309 { | 320 { |
345 next_idx.erase (next_idx.begin ()); | 356 next_idx.erase (next_idx.begin ()); |
346 | 357 |
347 std::string next_type = type.substr (1); | 358 std::string next_type = type.substr (1); |
348 | 359 |
349 Cell tmpc (1, 1); | 360 Cell tmpc (1, 1); |
350 Octave_map::iterator pkey = map.seek (key); | 361 octave_map::iterator pkey = map.seek (key); |
351 if (pkey != map.end ()) | 362 if (pkey != map.end ()) |
352 { | 363 { |
353 pkey->second.make_unique (); | 364 map.contents (pkey).make_unique (); |
354 tmpc = pkey->second; | 365 tmpc = map.contents (pkey); |
355 } | 366 } |
356 | 367 |
357 // FIXME: better code reuse? | 368 // FIXME: better code reuse? |
358 if (! error_state) | 369 if (! error_state) |
359 { | 370 { |
418 | 429 |
419 if (didx.numel () == tmp_cell.numel ()) | 430 if (didx.numel () == tmp_cell.numel ()) |
420 tmp_cell = tmp_cell.reshape (didx); | 431 tmp_cell = tmp_cell.reshape (didx); |
421 | 432 |
422 | 433 |
423 map.assign (idxf, key, tmp_cell); | 434 map.contents (key).assign (idxf, tmp_cell); |
424 | 435 |
425 if (! error_state) | 436 if (! error_state) |
426 { | 437 { |
427 count++; | 438 count++; |
428 retval = octave_value (this); | 439 retval = octave_value (this); |
430 else | 441 else |
431 gripe_failed_assignment (); | 442 gripe_failed_assignment (); |
432 } | 443 } |
433 else | 444 else |
434 { | 445 { |
435 const Octave_map& cmap = const_cast<const Octave_map &> (map); | 446 const octave_map& cmap = const_cast<const octave_map &> (map); |
436 // cast map to const reference to avoid forced key insertion. | 447 // cast map to const reference to avoid forced key insertion. |
437 if (idxf.all_scalars () | 448 if (idxf.all_scalars () |
438 || cmap.contents (key).index (idxf, true).numel () == 1) | 449 || cmap.contents (key).index (idxf, true).numel () == 1) |
439 { | 450 { |
440 map.assign (idxf, key, t_rhs.storable_value ()); | 451 map.contents (key).assign (idxf, Cell (t_rhs.storable_value ())); |
441 if (! error_state) | 452 if (! error_state) |
442 { | 453 { |
443 count++; | 454 count++; |
444 retval = octave_value (this); | 455 retval = octave_value (this); |
445 } | 456 } |
455 } | 466 } |
456 else | 467 else |
457 { | 468 { |
458 if (t_rhs.is_map()) | 469 if (t_rhs.is_map()) |
459 { | 470 { |
460 Octave_map rhs_map = t_rhs.map_value (); | 471 octave_map rhs_map = t_rhs.map_value (); |
461 | 472 |
462 if (! error_state) | 473 if (! error_state) |
463 { | 474 { |
464 map.assign (idx.front (), rhs_map); | 475 map.assign (idx.front (), rhs_map); |
465 | 476 |
476 } | 487 } |
477 else | 488 else |
478 { | 489 { |
479 if (t_rhs.is_null_value()) | 490 if (t_rhs.is_null_value()) |
480 { | 491 { |
481 map.maybe_delete_elements (idx.front()); | 492 map.delete_elements (idx.front()); |
482 | 493 |
483 if (! error_state) | 494 if (! error_state) |
484 { | 495 { |
485 count++; | 496 count++; |
486 retval = octave_value (this); | 497 retval = octave_value (this); |
512 // shape of the left hand side of the assignment. | 523 // shape of the left hand side of the assignment. |
513 | 524 |
514 if (numel () == tmp_cell.numel ()) | 525 if (numel () == tmp_cell.numel ()) |
515 tmp_cell = tmp_cell.reshape (dims ()); | 526 tmp_cell = tmp_cell.reshape (dims ()); |
516 | 527 |
517 map.assign (key, tmp_cell); | 528 map.setfield (key, tmp_cell); |
518 } | 529 } |
519 else | 530 else |
520 // Regularize a null matrix if stored into a struct component. | 531 { |
521 map.assign (key, t_rhs.storable_value ()); | 532 Cell tmp_cell(1, 1); |
533 tmp_cell(0) = t_rhs.storable_value (); | |
534 map.setfield (key, tmp_cell); | |
535 } | |
522 | 536 |
523 if (! error_state) | 537 if (! error_state) |
524 { | 538 { |
525 count++; | 539 count++; |
526 retval = octave_value (this); | 540 retval = octave_value (this); |
545 } | 559 } |
546 | 560 |
547 octave_value | 561 octave_value |
548 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok) | 562 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok) |
549 { | 563 { |
550 // Octave_map handles indexing itself. | 564 // octave_map handles indexing itself. |
551 return map.index (idx, resize_ok); | 565 return map.index (idx, resize_ok); |
552 } | 566 } |
553 | 567 |
554 size_t | 568 size_t |
555 octave_struct::byte_size (void) const | 569 octave_struct::byte_size (void) const |
556 { | 570 { |
557 // Neglect the size of the fieldnames. | 571 // Neglect the size of the fieldnames. |
558 | 572 |
559 size_t retval = 0; | 573 size_t retval = 0; |
560 | 574 |
561 for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) | 575 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) |
562 { | 576 { |
563 std::string key = map.key (p); | 577 std::string key = map.key (p); |
564 | 578 |
565 octave_value val = octave_value (map.contents (p)); | 579 octave_value val = octave_value (map.contents (p)); |
566 | 580 |
604 newline (os); | 618 newline (os); |
605 | 619 |
606 increment_indent_level (); | 620 increment_indent_level (); |
607 } | 621 } |
608 | 622 |
609 string_vector key_list = map.keys (); | 623 string_vector key_list = map.fieldnames (); |
610 | 624 |
611 for (octave_idx_type i = 0; i < key_list.length (); i++) | 625 for (octave_idx_type i = 0; i < key_list.length (); i++) |
612 { | 626 { |
613 std::string key = key_list[i]; | 627 std::string key = key_list[i]; |
614 | 628 |
691 %!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4") | 705 %!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4") |
692 %!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs"); | 706 %!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs"); |
693 %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs"); | 707 %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs"); |
694 */ | 708 */ |
695 | 709 |
710 bool | |
711 octave_struct::save_ascii (std::ostream& os) | |
712 { | |
713 octave_map m = map_value (); | |
714 | |
715 octave_idx_type nf = m.nfields (); | |
716 | |
717 const dim_vector dv = dims (); | |
718 | |
719 os << "# ndims: " << dv.length () << "\n"; | |
720 | |
721 for (int i = 0; i < dv.length (); i++) | |
722 os << " " << dv (i); | |
723 os << "\n"; | |
724 | |
725 os << "# length: " << nf << "\n"; | |
726 | |
727 // Iterating over the list of keys will preserve the order of the | |
728 // fields. | |
729 string_vector keys = m.fieldnames (); | |
730 | |
731 for (octave_idx_type i = 0; i < nf; i++) | |
732 { | |
733 std::string key = keys(i); | |
734 | |
735 octave_value val = map.contents (key); | |
736 | |
737 bool b = save_ascii_data (os, val, key, false, 0); | |
738 | |
739 if (! b) | |
740 return os; | |
741 } | |
742 | |
743 return true; | |
744 } | |
745 | |
746 bool | |
747 octave_struct::load_ascii (std::istream& is) | |
748 { | |
749 octave_idx_type len = 0; | |
750 dim_vector dv (1, 1); | |
751 bool success = true; | |
752 | |
753 // KLUGE: earlier Octave versions did not save extra dimensions with struct, | |
754 // and as a result did not preserve dimensions for empty structs. | |
755 // The default dimensions were 1x1, which we want to preserve. | |
756 string_vector keywords(2); | |
757 | |
758 keywords[0] = "ndims"; | |
759 keywords[1] = "length"; | |
760 | |
761 std::string kw; | |
762 | |
763 if (extract_keyword (is, keywords, kw, len, true)) | |
764 { | |
765 if (kw == keywords[0]) | |
766 { | |
767 int mdims = std::max (static_cast<int> (len), 2); | |
768 dv.resize (mdims); | |
769 for (int i = 0; i < mdims; i++) | |
770 is >> dv(i); | |
771 | |
772 success = extract_keyword (is, keywords[1], len); | |
773 } | |
774 } | |
775 else | |
776 success = false; | |
777 | |
778 if (success && len >= 0) | |
779 { | |
780 if (len > 0) | |
781 { | |
782 octave_map m (dv); | |
783 | |
784 for (octave_idx_type j = 0; j < len; j++) | |
785 { | |
786 octave_value t2; | |
787 bool dummy; | |
788 | |
789 // recurse to read cell elements | |
790 std::string nm | |
791 = read_ascii_data (is, std::string (), dummy, t2, j); | |
792 | |
793 if (!is) | |
794 break; | |
795 | |
796 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
797 | |
798 if (error_state) | |
799 { | |
800 error ("load: internal error loading struct elements"); | |
801 return false; | |
802 } | |
803 | |
804 m.setfield (nm, tcell); | |
805 } | |
806 | |
807 if (is) | |
808 map = m; | |
809 else | |
810 { | |
811 error ("load: failed to load structure"); | |
812 success = false; | |
813 } | |
814 } | |
815 else if (len == 0 ) | |
816 map = octave_map (dv); | |
817 else | |
818 panic_impossible (); | |
819 } | |
820 else { | |
821 error ("load: failed to extract number of elements in structure"); | |
822 success = false; | |
823 } | |
824 | |
825 return success; | |
826 } | |
827 | |
828 bool | |
829 octave_struct::save_binary (std::ostream& os, bool& save_as_floats) | |
830 { | |
831 octave_map m = map_value (); | |
832 | |
833 octave_idx_type nf = m.nfields (); | |
834 | |
835 dim_vector d = dims (); | |
836 if (d.length () < 1) | |
837 return false; | |
838 | |
839 // Use negative value for ndims | |
840 int32_t di = - d.length(); | |
841 os.write (reinterpret_cast<char *> (&di), 4); | |
842 for (int i = 0; i < d.length (); i++) | |
843 { | |
844 di = d(i); | |
845 os.write (reinterpret_cast<char *> (&di), 4); | |
846 } | |
847 | |
848 int32_t len = nf; | |
849 os.write (reinterpret_cast<char *> (&len), 4); | |
850 | |
851 // Iterating over the list of keys will preserve the order of the | |
852 // fields. | |
853 string_vector keys = m.fieldnames (); | |
854 | |
855 for (octave_idx_type i = 0; i < nf; i++) | |
856 { | |
857 std::string key = keys(i); | |
858 | |
859 octave_value val = map.contents (key); | |
860 | |
861 bool b = save_binary_data (os, val, key, "", 0, save_as_floats); | |
862 | |
863 if (! b) | |
864 return os; | |
865 } | |
866 | |
867 return true; | |
868 } | |
869 | |
870 bool | |
871 octave_struct::load_binary (std::istream& is, bool swap, | |
872 oct_mach_info::float_format fmt) | |
873 { | |
874 bool success = true; | |
875 int32_t len; | |
876 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
877 return false; | |
878 if (swap) | |
879 swap_bytes<4> (&len); | |
880 | |
881 dim_vector dv (1, 1); | |
882 | |
883 if (len < 0) | |
884 { | |
885 // We have explicit dimensions. | |
886 int mdims = -len; | |
887 | |
888 int32_t di; | |
889 dv.resize (mdims); | |
890 | |
891 for (int i = 0; i < mdims; i++) | |
892 { | |
893 if (! is.read (reinterpret_cast<char *> (&di), 4)) | |
894 return false; | |
895 if (swap) | |
896 swap_bytes<4> (&di); | |
897 dv(i) = di; | |
898 } | |
899 | |
900 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
901 return false; | |
902 if (swap) | |
903 swap_bytes<4> (&len); | |
904 } | |
905 | |
906 if (len > 0) | |
907 { | |
908 octave_map m (dv); | |
909 | |
910 for (octave_idx_type j = 0; j < len; j++) | |
911 { | |
912 octave_value t2; | |
913 bool dummy; | |
914 std::string doc; | |
915 | |
916 // recurse to read cell elements | |
917 std::string nm = read_binary_data (is, swap, fmt, std::string (), | |
918 dummy, t2, doc); | |
919 | |
920 if (!is) | |
921 break; | |
922 | |
923 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
924 | |
925 if (error_state) | |
926 { | |
927 error ("load: internal error loading struct elements"); | |
928 return false; | |
929 } | |
930 | |
931 m.setfield (nm, tcell); | |
932 } | |
933 | |
934 if (is) | |
935 map = m; | |
936 else | |
937 { | |
938 error ("load: failed to load structure"); | |
939 success = false; | |
940 } | |
941 } | |
942 else if (len == 0) | |
943 map = octave_map (dv); | |
944 else | |
945 success = false; | |
946 | |
947 return success; | |
948 } | |
949 | |
950 #if defined (HAVE_HDF5) | |
951 | |
952 bool | |
953 octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) | |
954 { | |
955 hid_t data_hid = -1; | |
956 | |
957 #if HAVE_HDF5_18 | |
958 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); | |
959 #else | |
960 data_hid = H5Gcreate (loc_id, name, 0); | |
961 #endif | |
962 if (data_hid < 0) return false; | |
963 | |
964 // recursively add each element of the structure to this group | |
965 octave_map m = map_value (); | |
966 | |
967 octave_idx_type nf = m.nfields (); | |
968 | |
969 // Iterating over the list of keys will preserve the order of the | |
970 // fields. | |
971 string_vector keys = m.fieldnames (); | |
972 | |
973 for (octave_idx_type i = 0; i < nf; i++) | |
974 { | |
975 std::string key = keys(i); | |
976 | |
977 octave_value val = map.contents (key); | |
978 | |
979 bool retval2 = add_hdf5_data (data_hid, val, key, "", false, | |
980 save_as_floats); | |
981 | |
982 if (! retval2) | |
983 break; | |
984 } | |
985 | |
986 H5Gclose (data_hid); | |
987 | |
988 return true; | |
989 } | |
990 | |
991 bool | |
992 octave_struct::load_hdf5 (hid_t loc_id, const char *name) | |
993 { | |
994 bool retval = false; | |
995 | |
996 hdf5_callback_data dsub; | |
997 | |
998 herr_t retval2 = 0; | |
999 octave_map m (dim_vector (1, 1)); | |
1000 int current_item = 0; | |
1001 hsize_t num_obj = 0; | |
1002 #if HAVE_HDF5_18 | |
1003 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); | |
1004 #else | |
1005 hid_t group_id = H5Gopen (loc_id, name); | |
1006 #endif | |
1007 H5Gget_num_objs (group_id, &num_obj); | |
1008 H5Gclose (group_id); | |
1009 | |
1010 // FIXME -- fields appear to be sorted alphabetically on loading. | |
1011 // Why is that happening? | |
1012 | |
1013 while (current_item < static_cast<int> (num_obj) | |
1014 && (retval2 = H5Giterate (loc_id, name, ¤t_item, | |
1015 hdf5_read_next_data, &dsub)) > 0) | |
1016 { | |
1017 octave_value t2 = dsub.tc; | |
1018 | |
1019 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
1020 | |
1021 if (error_state) | |
1022 { | |
1023 error ("load: internal error loading struct elements"); | |
1024 return false; | |
1025 } | |
1026 | |
1027 m.setfield (dsub.name, tcell); | |
1028 | |
1029 } | |
1030 | |
1031 if (retval2 >= 0) | |
1032 { | |
1033 map = m; | |
1034 retval = true; | |
1035 } | |
1036 | |
1037 return retval; | |
1038 } | |
1039 | |
1040 #endif | |
1041 | |
1042 mxArray * | |
1043 octave_struct::as_mxArray (void) const | |
1044 { | |
1045 int nf = nfields (); | |
1046 string_vector kv = map_keys (); | |
1047 | |
1048 OCTAVE_LOCAL_BUFFER (const char *, f, nf); | |
1049 | |
1050 for (int i = 0; i < nf; i++) | |
1051 f[i] = kv[i].c_str (); | |
1052 | |
1053 mxArray *retval = new mxArray (dims (), nf, f); | |
1054 | |
1055 mxArray **elts = static_cast<mxArray **> (retval->get_data ()); | |
1056 | |
1057 mwSize nel = numel (); | |
1058 | |
1059 mwSize ntot = nf * nel; | |
1060 | |
1061 for (int i = 0; i < nf; i++) | |
1062 { | |
1063 Cell c = map.contents (kv[i]); | |
1064 | |
1065 const octave_value *p = c.data (); | |
1066 | |
1067 mwIndex k = 0; | |
1068 for (mwIndex j = i; j < ntot; j += nf) | |
1069 elts[j] = new mxArray (p[k++]); | |
1070 } | |
1071 | |
1072 return retval; | |
1073 } | |
1074 | |
1075 DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct); | |
1076 | |
1077 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct"); | |
1078 | |
1079 octave_value | |
1080 octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add) | |
1081 { | |
1082 assert (idx.length () == 1); | |
1083 | |
1084 std::string nm = idx(0).string_value (); | |
1085 | |
1086 octave_value retval = map.getfield (nm); | |
1087 | |
1088 if (! auto_add && retval.is_undefined ()) | |
1089 error ("structure has no member `%s'", nm.c_str ()); | |
1090 | |
1091 return retval; | |
1092 } | |
1093 | |
1094 octave_value | |
1095 octave_scalar_struct::subsref (const std::string& type, | |
1096 const std::list<octave_value_list>& idx) | |
1097 { | |
1098 octave_value retval; | |
1099 | |
1100 if (type[0] == '.') | |
1101 { | |
1102 int skip = 1; | |
1103 | |
1104 retval = dotref (idx.front ()); | |
1105 | |
1106 if (idx.size () > 1) | |
1107 retval = retval.next_subsref (type, idx, skip); | |
1108 } | |
1109 else | |
1110 retval = to_array ().subsref (type, idx); | |
1111 | |
1112 return retval; | |
1113 } | |
1114 | |
1115 octave_value_list | |
1116 octave_scalar_struct::subsref (const std::string& type, | |
1117 const std::list<octave_value_list>& idx, | |
1118 int nargout) | |
1119 { | |
1120 octave_value_list retval; | |
1121 | |
1122 if (type[0] == '.') | |
1123 { | |
1124 int skip = 1; | |
1125 | |
1126 retval(0) = dotref (idx.front ()); | |
1127 | |
1128 if (idx.size () > 1) | |
1129 retval = retval(0).next_subsref (nargout, type, idx, skip); | |
1130 } | |
1131 else | |
1132 retval = to_array ().subsref (type, idx, nargout); | |
1133 | |
1134 return retval; | |
1135 } | |
1136 | |
1137 octave_value | |
1138 octave_scalar_struct::subsref (const std::string& type, | |
1139 const std::list<octave_value_list>& idx, | |
1140 bool auto_add) | |
1141 { | |
1142 octave_value retval; | |
1143 | |
1144 if (type[0] == '.') | |
1145 { | |
1146 int skip = 1; | |
1147 | |
1148 retval = dotref (idx.front (), auto_add); | |
1149 | |
1150 if (idx.size () > 1) | |
1151 retval = retval.next_subsref (auto_add, type, idx, skip); | |
1152 } | |
1153 else | |
1154 retval = to_array ().subsref (type, idx, auto_add); | |
1155 | |
1156 return retval; | |
1157 } | |
1158 | |
1159 /* | |
1160 %!test | |
1161 %! x(1).a.a = 1; x(2).a.a = 2; | |
1162 %! assert (size (x), [1, 2]); | |
1163 %! assert (x(1).a.a, 1); | |
1164 %! assert (x(2).a.a, 2); | |
1165 */ | |
1166 | |
1167 octave_value | |
1168 octave_scalar_struct::numeric_conv (const octave_value& val, | |
1169 const std::string& type) | |
1170 { | |
1171 octave_value retval; | |
1172 | |
1173 if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) | |
1174 retval = octave_map (); | |
1175 else | |
1176 retval = val; | |
1177 | |
1178 return retval; | |
1179 } | |
1180 | |
1181 octave_value | |
1182 octave_scalar_struct::subsasgn (const std::string& type, | |
1183 const std::list<octave_value_list>& idx, | |
1184 const octave_value& rhs) | |
1185 { | |
1186 octave_value retval; | |
1187 | |
1188 if (idx.front ().empty ()) | |
1189 { | |
1190 error ("missing index in indexed assignment"); | |
1191 return retval; | |
1192 } | |
1193 | |
1194 if (type[0] == '.') | |
1195 { | |
1196 int n = type.length (); | |
1197 | |
1198 octave_value t_rhs = rhs; | |
1199 | |
1200 octave_value_list key_idx = idx.front (); | |
1201 | |
1202 assert (key_idx.length () == 1); | |
1203 | |
1204 std::string key = key_idx(0).string_value (); | |
1205 | |
1206 if (n > 1) | |
1207 { | |
1208 std::list<octave_value_list> next_idx (idx); | |
1209 | |
1210 next_idx.erase (next_idx.begin ()); | |
1211 | |
1212 std::string next_type = type.substr (1); | |
1213 | |
1214 octave_value tmp; | |
1215 octave_map::iterator pkey = map.seek (key); | |
1216 if (pkey != map.end ()) | |
1217 { | |
1218 map.contents (pkey).make_unique (); | |
1219 tmp = map.contents (pkey); | |
1220 } | |
1221 | |
1222 if (! error_state) | |
1223 { | |
1224 if (! tmp.is_defined () || tmp.is_zero_by_zero ()) | |
1225 { | |
1226 tmp = octave_value::empty_conv (next_type, rhs); | |
1227 tmp.make_unique (); // probably a no-op. | |
1228 } | |
1229 else | |
1230 // optimization: ignore the copy still stored inside our map. | |
1231 tmp.make_unique (1); | |
1232 | |
1233 if (! error_state) | |
1234 t_rhs = tmp.subsasgn (next_type, next_idx, rhs); | |
1235 } | |
1236 } | |
1237 | |
1238 if (! error_state) | |
1239 map.setfield (key, t_rhs.storable_value ()); | |
1240 else | |
1241 gripe_failed_assignment (); | |
1242 } | |
1243 else | |
1244 { | |
1245 // Forward this case to octave_struct. | |
1246 octave_value tmp (new octave_struct (octave_map (map))); | |
1247 retval = tmp.subsasgn (type, idx, rhs); | |
1248 } | |
1249 | |
1250 return retval; | |
1251 } | |
1252 | |
1253 octave_value | |
1254 octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok) | |
1255 { | |
1256 // octave_map handles indexing itself. | |
1257 return octave_map (map).index (idx, resize_ok); | |
1258 } | |
1259 | |
1260 size_t | |
1261 octave_scalar_struct::byte_size (void) const | |
1262 { | |
1263 // Neglect the size of the fieldnames. | |
1264 | |
1265 size_t retval = 0; | |
1266 | |
1267 for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) | |
1268 { | |
1269 std::string key = map.key (p); | |
1270 | |
1271 octave_value val = octave_value (map.contents (p)); | |
1272 | |
1273 retval += val.byte_size (); | |
1274 } | |
1275 | |
1276 return retval; | |
1277 } | |
1278 | |
1279 void | |
1280 octave_scalar_struct::print (std::ostream& os, bool) const | |
1281 { | |
1282 print_raw (os); | |
1283 } | |
1284 | |
1285 void | |
1286 octave_scalar_struct::print_raw (std::ostream& os, bool) const | |
1287 { | |
1288 unwind_protect frame; | |
1289 | |
1290 frame.protect_var (Vstruct_levels_to_print); | |
1291 | |
1292 if (Vstruct_levels_to_print >= 0) | |
1293 { | |
1294 bool print_keys_only = Vstruct_levels_to_print-- == 0; | |
1295 | |
1296 indent (os); | |
1297 os << "{"; | |
1298 newline (os); | |
1299 | |
1300 increment_indent_level (); | |
1301 | |
1302 octave_idx_type n = 1; | |
1303 | |
1304 if (n != 1 || print_keys_only) | |
1305 { | |
1306 indent (os); | |
1307 dim_vector dv = dims (); | |
1308 os << dv.str () << " struct array containing the fields:"; | |
1309 newline (os); | |
1310 newline (os); | |
1311 | |
1312 increment_indent_level (); | |
1313 } | |
1314 | |
1315 string_vector key_list = map.fieldnames (); | |
1316 | |
1317 for (octave_idx_type i = 0; i < key_list.length (); i++) | |
1318 { | |
1319 std::string key = key_list[i]; | |
1320 | |
1321 Cell val = map.contents (key); | |
1322 | |
1323 octave_value tmp = (n == 1) ? val(0) : octave_value (val, true); | |
1324 | |
1325 if (n != 1 || print_keys_only) | |
1326 { | |
1327 indent (os); | |
1328 os << key; | |
1329 if (n == 1) | |
1330 { | |
1331 dim_vector dv = tmp.dims (); | |
1332 os << ": " << dv.str () << " " << tmp.type_name (); | |
1333 } | |
1334 newline (os); | |
1335 } | |
1336 else | |
1337 tmp.print_with_name (os, key); | |
1338 } | |
1339 | |
1340 if (n != 1 || print_keys_only) | |
1341 decrement_indent_level (); | |
1342 | |
1343 decrement_indent_level (); | |
1344 | |
1345 indent (os); | |
1346 os << "}"; | |
1347 newline (os); | |
1348 } | |
1349 else | |
1350 { | |
1351 indent (os); | |
1352 os << "<structure>"; | |
1353 newline (os); | |
1354 } | |
1355 } | |
1356 | |
1357 bool | |
1358 octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const | |
1359 { | |
1360 bool retval = false; | |
1361 | |
1362 indent (os); | |
1363 | |
1364 if (Vstruct_levels_to_print < 0) | |
1365 os << name << " = "; | |
1366 else | |
1367 { | |
1368 os << name << " ="; | |
1369 newline (os); | |
1370 retval = true; | |
1371 } | |
1372 | |
1373 return retval; | |
1374 } | |
1375 | |
1376 bool | |
1377 octave_scalar_struct::save_ascii (std::ostream& os) | |
1378 { | |
1379 octave_map m = map_value (); | |
1380 | |
1381 octave_idx_type nf = m.nfields (); | |
1382 | |
1383 const dim_vector dv = dims (); | |
1384 | |
1385 os << "# ndims: " << dv.length () << "\n"; | |
1386 | |
1387 for (int i = 0; i < dv.length (); i++) | |
1388 os << " " << dv (i); | |
1389 os << "\n"; | |
1390 | |
1391 os << "# length: " << nf << "\n"; | |
1392 | |
1393 // Iterating over the list of keys will preserve the order of the | |
1394 // fields. | |
1395 string_vector keys = m.fieldnames (); | |
1396 | |
1397 for (octave_idx_type i = 0; i < nf; i++) | |
1398 { | |
1399 std::string key = keys(i); | |
1400 | |
1401 octave_value val = map.contents (key); | |
1402 | |
1403 bool b = save_ascii_data (os, val, key, false, 0); | |
1404 | |
1405 if (! b) | |
1406 return os; | |
1407 } | |
1408 | |
1409 return true; | |
1410 } | |
1411 | |
1412 bool | |
1413 octave_scalar_struct::load_ascii (std::istream& is) | |
1414 { | |
1415 bool success = true; | |
1416 octave_idx_type len = 0; | |
1417 | |
1418 if (extract_keyword (is, "length", len, true) && len >= 0) | |
1419 { | |
1420 if (len > 0) | |
1421 { | |
1422 octave_scalar_map m; | |
1423 | |
1424 for (octave_idx_type j = 0; j < len; j++) | |
1425 { | |
1426 octave_value t2; | |
1427 bool dummy; | |
1428 | |
1429 // recurse to read cell elements | |
1430 std::string nm | |
1431 = read_ascii_data (is, std::string (), dummy, t2, j); | |
1432 | |
1433 if (!is) | |
1434 break; | |
1435 | |
1436 if (error_state) | |
1437 { | |
1438 error ("load: internal error loading struct elements"); | |
1439 return false; | |
1440 } | |
1441 | |
1442 m.setfield (nm, t2); | |
1443 } | |
1444 | |
1445 if (is) | |
1446 map = m; | |
1447 else | |
1448 { | |
1449 error ("load: failed to load structure"); | |
1450 success = false; | |
1451 } | |
1452 } | |
1453 else if (len == 0) | |
1454 map = octave_scalar_map (); | |
1455 else | |
1456 panic_impossible (); | |
1457 } | |
1458 else { | |
1459 error ("load: failed to extract number of elements in structure"); | |
1460 success = false; | |
1461 } | |
1462 | |
1463 return success; | |
1464 } | |
1465 | |
1466 bool | |
1467 octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats) | |
1468 { | |
1469 octave_map m = map_value (); | |
1470 | |
1471 octave_idx_type nf = m.nfields (); | |
1472 | |
1473 int32_t len = nf; | |
1474 os.write (reinterpret_cast<char *> (&len), 4); | |
1475 | |
1476 // Iterating over the list of keys will preserve the order of the | |
1477 // fields. | |
1478 string_vector keys = m.fieldnames (); | |
1479 | |
1480 for (octave_idx_type i = 0; i < nf; i++) | |
1481 { | |
1482 std::string key = keys(i); | |
1483 | |
1484 octave_value val = map.contents (key); | |
1485 | |
1486 bool b = save_binary_data (os, val, key, "", 0, save_as_floats); | |
1487 | |
1488 if (! b) | |
1489 return os; | |
1490 } | |
1491 | |
1492 return true; | |
1493 } | |
1494 | |
1495 bool | |
1496 octave_scalar_struct::load_binary (std::istream& is, bool swap, | |
1497 oct_mach_info::float_format fmt) | |
1498 { | |
1499 bool success = true; | |
1500 int32_t len; | |
1501 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
1502 return false; | |
1503 if (swap) | |
1504 swap_bytes<4> (&len); | |
1505 | |
1506 dim_vector dv (1, 1); | |
1507 | |
1508 if (len > 0) | |
1509 { | |
1510 octave_scalar_map m; | |
1511 | |
1512 for (octave_idx_type j = 0; j < len; j++) | |
1513 { | |
1514 octave_value t2; | |
1515 bool dummy; | |
1516 std::string doc; | |
1517 | |
1518 // recurse to read cell elements | |
1519 std::string nm = read_binary_data (is, swap, fmt, std::string (), | |
1520 dummy, t2, doc); | |
1521 | |
1522 if (!is) | |
1523 break; | |
1524 | |
1525 if (error_state) | |
1526 { | |
1527 error ("load: internal error loading struct elements"); | |
1528 return false; | |
1529 } | |
1530 | |
1531 m.setfield (nm, t2); | |
1532 } | |
1533 | |
1534 if (is) | |
1535 map = m; | |
1536 else | |
1537 { | |
1538 error ("load: failed to load structure"); | |
1539 success = false; | |
1540 } | |
1541 } | |
1542 else if (len == 0) | |
1543 map = octave_scalar_map (); | |
1544 else | |
1545 success = false; | |
1546 | |
1547 return success; | |
1548 } | |
1549 | |
1550 #if defined (HAVE_HDF5) | |
1551 | |
1552 bool | |
1553 octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) | |
1554 { | |
1555 hid_t data_hid = -1; | |
1556 | |
1557 #if HAVE_HDF5_18 | |
1558 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); | |
1559 #else | |
1560 data_hid = H5Gcreate (loc_id, name, 0); | |
1561 #endif | |
1562 if (data_hid < 0) return false; | |
1563 | |
1564 // recursively add each element of the structure to this group | |
1565 octave_scalar_map m = scalar_map_value (); | |
1566 | |
1567 octave_idx_type nf = m.nfields (); | |
1568 | |
1569 // Iterating over the list of keys will preserve the order of the | |
1570 // fields. | |
1571 string_vector keys = m.fieldnames (); | |
1572 | |
1573 for (octave_idx_type i = 0; i < nf; i++) | |
1574 { | |
1575 std::string key = keys(i); | |
1576 | |
1577 octave_value val = map.contents (key); | |
1578 | |
1579 bool retval2 = add_hdf5_data (data_hid, val, key, "", false, | |
1580 save_as_floats); | |
1581 | |
1582 if (! retval2) | |
1583 break; | |
1584 } | |
1585 | |
1586 H5Gclose (data_hid); | |
1587 | |
1588 return true; | |
1589 } | |
1590 | |
1591 bool | |
1592 octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name) | |
1593 { | |
1594 bool retval = false; | |
1595 | |
1596 hdf5_callback_data dsub; | |
1597 | |
1598 herr_t retval2 = 0; | |
1599 octave_scalar_map m; | |
1600 int current_item = 0; | |
1601 hsize_t num_obj = 0; | |
1602 #if HAVE_HDF5_18 | |
1603 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); | |
1604 #else | |
1605 hid_t group_id = H5Gopen (loc_id, name); | |
1606 #endif | |
1607 H5Gget_num_objs (group_id, &num_obj); | |
1608 H5Gclose (group_id); | |
1609 | |
1610 // FIXME -- fields appear to be sorted alphabetically on loading. | |
1611 // Why is that happening? | |
1612 | |
1613 while (current_item < static_cast<int> (num_obj) | |
1614 && (retval2 = H5Giterate (loc_id, name, ¤t_item, | |
1615 hdf5_read_next_data, &dsub)) > 0) | |
1616 { | |
1617 octave_value t2 = dsub.tc; | |
1618 | |
1619 if (error_state) | |
1620 { | |
1621 error ("load: internal error loading struct elements"); | |
1622 return false; | |
1623 } | |
1624 | |
1625 m.setfield (dsub.name, t2); | |
1626 | |
1627 } | |
1628 | |
1629 if (retval2 >= 0) | |
1630 { | |
1631 map = m; | |
1632 retval = true; | |
1633 } | |
1634 | |
1635 return retval; | |
1636 } | |
1637 | |
1638 #endif | |
1639 | |
1640 mxArray * | |
1641 octave_scalar_struct::as_mxArray (void) const | |
1642 { | |
1643 int nf = nfields (); | |
1644 string_vector kv = map_keys (); | |
1645 | |
1646 OCTAVE_LOCAL_BUFFER (const char *, f, nf); | |
1647 | |
1648 for (int i = 0; i < nf; i++) | |
1649 f[i] = kv[i].c_str (); | |
1650 | |
1651 mxArray *retval = new mxArray (dims (), nf, f); | |
1652 | |
1653 mxArray **elts = static_cast<mxArray **> (retval->get_data ()); | |
1654 | |
1655 mwSize nel = numel (); | |
1656 | |
1657 mwSize ntot = nf * nel; | |
1658 | |
1659 for (int i = 0; i < nf; i++) | |
1660 { | |
1661 Cell c = map.contents (kv[i]); | |
1662 | |
1663 const octave_value *p = c.data (); | |
1664 | |
1665 mwIndex k = 0; | |
1666 for (mwIndex j = i; j < ntot; j += nf) | |
1667 elts[j] = new mxArray (p[k++]); | |
1668 } | |
1669 | |
1670 return retval; | |
1671 } | |
1672 | |
1673 | |
1674 octave_value | |
1675 octave_scalar_struct::to_array (void) | |
1676 { | |
1677 return new octave_struct (octave_map (map)); | |
1678 } | |
1679 | |
1680 /* | |
1681 %!shared x | |
1682 %! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3; | |
1683 %!assert(struct('a',1,'b',3),x(1)) | |
1684 %!assert(isempty(x([]))) | |
1685 %!assert(isempty(struct('a',{},'b',{}))) | |
1686 %!assert(struct('a',{1,2},'b',{3,3}),x) | |
1687 %!assert(struct('a',{1,2},'b',3),x) | |
1688 %!assert(struct('a',{1,2},'b',{3}),x) | |
1689 %!assert(struct('b',3,'a',{1,2}),x) | |
1690 %!assert(struct('b',{3},'a',{1,2}),x) | |
1691 %!test x=struct([]); | |
1692 %!assert(size(x),[0,0]); | |
1693 %!assert(isstruct(x)); | |
1694 %!assert(isempty(fieldnames(x))); | |
1695 %!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4") | |
1696 %!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs"); | |
1697 %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs"); | |
1698 */ | |
1699 | |
696 DEFUN (struct, args, , | 1700 DEFUN (struct, args, , |
697 "-*- texinfo -*-\n\ | 1701 "-*- texinfo -*-\n\ |
698 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\ | 1702 @deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\ |
699 \n\ | 1703 \n\ |
700 Create a structure and initialize its value.\n\ | 1704 Create a structure and initialize its value.\n\ |
720 // Note that struct () creates a 1x1 struct with no fields for | 1724 // Note that struct () creates a 1x1 struct with no fields for |
721 // compatibility with Matlab. | 1725 // compatibility with Matlab. |
722 | 1726 |
723 if (nargin == 1 && args(0).is_object ()) | 1727 if (nargin == 1 && args(0).is_object ()) |
724 { | 1728 { |
725 Octave_map m = args(0).map_value (); | 1729 octave_map m = args(0).map_value (); |
726 retval = octave_value (new octave_struct (m)); | 1730 retval = octave_value (new octave_struct (m)); |
727 | 1731 |
728 return retval; | 1732 return retval; |
729 } | 1733 } |
730 | 1734 |
734 Cell fields; | 1738 Cell fields; |
735 | 1739 |
736 if (nargin == 2) | 1740 if (nargin == 2) |
737 { | 1741 { |
738 if (args(1).is_cellstr ()) | 1742 if (args(1).is_cellstr ()) |
739 retval = Octave_map (args(0).dims (), args(1).cell_value ()); | 1743 retval = octave_map (args(0).dims (), args(1).cellstr_value ()); |
740 else | 1744 else |
741 error ("struct: expecting cell array of field names as second argument"); | 1745 error ("struct: expecting cell array of field names as second argument"); |
742 } | 1746 } |
743 else | 1747 else |
744 retval = Octave_map (args(0).dims ()); | 1748 retval = octave_map (args(0).dims ()); |
745 | 1749 |
746 return retval; | 1750 return retval; |
747 } | 1751 } |
748 | 1752 |
749 // Check for "field", VALUE pairs. | 1753 // Check for "field", VALUE pairs. |
786 } | 1790 } |
787 } | 1791 } |
788 | 1792 |
789 // Create the return value. | 1793 // Create the return value. |
790 | 1794 |
791 Octave_map map (dims); | 1795 octave_map map (dims); |
792 | 1796 |
793 for (int i = 0; i < nargin; i+= 2) | 1797 for (int i = 0; i < nargin; i+= 2) |
794 { | 1798 { |
795 // Get key. | 1799 // Get key. |
796 | 1800 |
817 | 1821 |
818 if (error_state) | 1822 if (error_state) |
819 return retval; | 1823 return retval; |
820 | 1824 |
821 if (scalar (c.dims ())) | 1825 if (scalar (c.dims ())) |
822 map.assign (key, Cell (dims, c(0))); | 1826 map.setfield (key, Cell (dims, c(0))); |
823 else | 1827 else |
824 map.assign (key, c); | 1828 map.setfield (key, c); |
825 } | 1829 } |
826 else | 1830 else |
827 map.assign (key, Cell (dims, args(i+1))); | 1831 map.setfield (key, Cell (dims, args(i+1))); |
828 | 1832 |
829 if (error_state) | 1833 if (error_state) |
830 return retval; | 1834 return retval; |
831 } | 1835 } |
832 | 1836 |
866 { | 1870 { |
867 octave_value arg = args(0); | 1871 octave_value arg = args(0); |
868 | 1872 |
869 if (arg.is_map () || arg.is_object ()) | 1873 if (arg.is_map () || arg.is_object ()) |
870 { | 1874 { |
871 Octave_map m = arg.map_value (); | 1875 octave_map m = arg.map_value (); |
872 | 1876 |
873 string_vector keys = m.keys (); | 1877 string_vector keys = m.fieldnames (); |
874 | 1878 |
875 if (keys.length () == 0) | 1879 if (keys.length () == 0) |
876 retval = Cell (0, 1); | 1880 retval = Cell (0, 1); |
877 else | 1881 else |
878 retval = Cell (m.keys ()); | 1882 retval = Cell (keys); |
879 } | 1883 } |
880 else | 1884 else |
881 gripe_wrong_type_arg ("fieldnames", args(0)); | 1885 gripe_wrong_type_arg ("fieldnames", args(0)); |
882 } | 1886 } |
883 else | 1887 else |
909 { | 1913 { |
910 retval = false; | 1914 retval = false; |
911 | 1915 |
912 if (args(0).is_map ()) | 1916 if (args(0).is_map ()) |
913 { | 1917 { |
914 Octave_map m = args(0).map_value (); | 1918 octave_map m = args(0).map_value (); |
915 | 1919 |
916 // FIXME -- should this work for all types that can do | 1920 // FIXME -- should this work for all types that can do |
917 // structure reference operations? | 1921 // structure reference operations? |
918 | 1922 |
919 if (args(1).is_string ()) | 1923 if (args(1).is_string ()) |
920 { | 1924 { |
921 std::string key = args(1).string_value (); | 1925 std::string key = args(1).string_value (); |
922 | 1926 |
923 retval = m.contains (key) != 0; | 1927 retval = m.isfield (key); |
924 } | 1928 } |
925 else if (args(1).is_cell ()) | 1929 else if (args(1).is_cell ()) |
926 { | 1930 { |
927 Cell c = args(1).cell_value (); | 1931 Cell c = args(1).cell_value (); |
928 boolMatrix bm (c.dims ()); | 1932 boolNDArray bm (c.dims ()); |
929 octave_idx_type n = bm.numel (); | 1933 octave_idx_type n = bm.numel (); |
930 | 1934 |
931 for (octave_idx_type i = 0; i < n; i++) | 1935 for (octave_idx_type i = 0; i < n; i++) |
932 { | 1936 { |
933 if (c(i).is_string ()) | 1937 if (c(i).is_string ()) |
934 { | 1938 { |
935 std::string key = c(i).string_value (); | 1939 std::string key = c(i).string_value (); |
936 | 1940 |
937 bm(i) = m.contains (key) != 0; | 1941 bm(i) = m.isfield (key); |
938 } | 1942 } |
939 else | 1943 else |
940 bm(i) = false; | 1944 bm(i) = false; |
941 } | 1945 } |
942 | 1946 |
1131 } | 2135 } |
1132 | 2136 |
1133 // All initializing is done, we can start moving | 2137 // All initializing is done, we can start moving |
1134 // values. | 2138 // values. |
1135 | 2139 |
1136 Octave_map map; | 2140 octave_map map; |
1137 | 2141 |
1138 // If field is a cell array then we use all | 2142 // If field is a cell array then we use all |
1139 // elements in array, on the other hand when | 2143 // elements in array, on the other hand when |
1140 // field is a character array the number of | 2144 // field is a character array the number of |
1141 // elements is equals the number of rows. | 2145 // elements is equals the number of rows. |
1205 break; | 2209 break; |
1206 } | 2210 } |
1207 | 2211 |
1208 map.reshape (value_dv); | 2212 map.reshape (value_dv); |
1209 | 2213 |
1210 map.assign (field_str, c_value); | 2214 map.setfield (field_str, c_value); |
1211 } | 2215 } |
1212 | 2216 |
1213 if (! error_state) | 2217 if (! error_state) |
1214 retval = map; | 2218 retval = map; |
1215 } | 2219 } |
1258 | 2262 |
1259 int nargin = args.length (); | 2263 int nargin = args.length (); |
1260 | 2264 |
1261 if (nargin == 2) | 2265 if (nargin == 2) |
1262 { | 2266 { |
1263 Octave_map m = args(0).map_value (); | 2267 octave_map m = args(0).map_value (); |
1264 | 2268 |
1265 octave_value_list fval = Fcellstr (args(1), 1); | 2269 octave_value_list fval = Fcellstr (args(1), 1); |
1266 | 2270 |
1267 if (! error_state) | 2271 if (! error_state) |
1268 { | 2272 { |
1270 | 2274 |
1271 for (int i = 0; i < fcell.numel (); i++) | 2275 for (int i = 0; i < fcell.numel (); i++) |
1272 { | 2276 { |
1273 std::string key = fcell(i).string_value (); | 2277 std::string key = fcell(i).string_value (); |
1274 | 2278 |
1275 if (m.contains (key)) | 2279 if (m.isfield (key)) |
1276 m.del (key); | 2280 m.rmfield (key); |
1277 else | 2281 else |
1278 { | 2282 { |
1279 error ("rmfield: structure does not contain field %s", | 2283 error ("rmfield: structure does not contain field %s", |
1280 key.c_str ()); | 2284 key.c_str ()); |
1281 | 2285 |
1300 %! y = rmfield (x, {"a", "f"}); | 2304 %! y = rmfield (x, {"a", "f"}); |
1301 %! assert (fieldnames (y), {"d"; "b"; "c"}); | 2305 %! assert (fieldnames (y), {"d"; "b"; "c"}); |
1302 %! assert (size (y), [1, 6]); | 2306 %! assert (size (y), [1, 6]); |
1303 */ | 2307 */ |
1304 | 2308 |
1305 bool | |
1306 octave_struct::save_ascii (std::ostream& os) | |
1307 { | |
1308 Octave_map m = map_value (); | |
1309 | |
1310 octave_idx_type nf = m.nfields (); | |
1311 | |
1312 const dim_vector dv = dims (); | |
1313 | |
1314 os << "# ndims: " << dv.length () << "\n"; | |
1315 | |
1316 for (int i = 0; i < dv.length (); i++) | |
1317 os << " " << dv (i); | |
1318 os << "\n"; | |
1319 | |
1320 os << "# length: " << nf << "\n"; | |
1321 | |
1322 // Iterating over the list of keys will preserve the order of the | |
1323 // fields. | |
1324 string_vector keys = m.keys (); | |
1325 | |
1326 for (octave_idx_type i = 0; i < nf; i++) | |
1327 { | |
1328 std::string key = keys(i); | |
1329 | |
1330 octave_value val = map.contents (key); | |
1331 | |
1332 bool b = save_ascii_data (os, val, key, false, 0); | |
1333 | |
1334 if (! b) | |
1335 return os; | |
1336 } | |
1337 | |
1338 return true; | |
1339 } | |
1340 | |
1341 bool | |
1342 octave_struct::load_ascii (std::istream& is) | |
1343 { | |
1344 octave_idx_type len = 0; | |
1345 dim_vector dv (1, 1); | |
1346 bool success = true; | |
1347 | |
1348 // KLUGE: earlier Octave versions did not save extra dimensions with struct, | |
1349 // and as a result did not preserve dimensions for empty structs. | |
1350 // The default dimensions were 1x1, which we want to preserve. | |
1351 string_vector keywords(2); | |
1352 | |
1353 keywords[0] = "ndims"; | |
1354 keywords[1] = "length"; | |
1355 | |
1356 std::string kw; | |
1357 | |
1358 if (extract_keyword (is, keywords, kw, len, true)) | |
1359 { | |
1360 if (kw == keywords[0]) | |
1361 { | |
1362 int mdims = std::max (static_cast<int> (len), 2); | |
1363 dv.resize (mdims); | |
1364 for (int i = 0; i < mdims; i++) | |
1365 is >> dv(i); | |
1366 | |
1367 success = extract_keyword (is, keywords[1], len); | |
1368 } | |
1369 } | |
1370 else | |
1371 success = false; | |
1372 | |
1373 if (success && len >= 0) | |
1374 { | |
1375 if (len > 0) | |
1376 { | |
1377 Octave_map m (dv); | |
1378 | |
1379 for (octave_idx_type j = 0; j < len; j++) | |
1380 { | |
1381 octave_value t2; | |
1382 bool dummy; | |
1383 | |
1384 // recurse to read cell elements | |
1385 std::string nm | |
1386 = read_ascii_data (is, std::string (), dummy, t2, j); | |
1387 | |
1388 if (!is) | |
1389 break; | |
1390 | |
1391 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
1392 | |
1393 if (error_state) | |
1394 { | |
1395 error ("load: internal error loading struct elements"); | |
1396 return false; | |
1397 } | |
1398 | |
1399 m.assign (nm, tcell); | |
1400 } | |
1401 | |
1402 if (is) | |
1403 map = m; | |
1404 else | |
1405 { | |
1406 error ("load: failed to load structure"); | |
1407 success = false; | |
1408 } | |
1409 } | |
1410 else if (len == 0 ) | |
1411 map = Octave_map (dv); | |
1412 else | |
1413 panic_impossible (); | |
1414 } | |
1415 else { | |
1416 error ("load: failed to extract number of elements in structure"); | |
1417 success = false; | |
1418 } | |
1419 | |
1420 return success; | |
1421 } | |
1422 | |
1423 bool | |
1424 octave_struct::save_binary (std::ostream& os, bool& save_as_floats) | |
1425 { | |
1426 Octave_map m = map_value (); | |
1427 | |
1428 octave_idx_type nf = m.nfields (); | |
1429 | |
1430 dim_vector d = dims (); | |
1431 if (d.length () < 1) | |
1432 return false; | |
1433 | |
1434 // Use negative value for ndims | |
1435 int32_t di = - d.length(); | |
1436 os.write (reinterpret_cast<char *> (&di), 4); | |
1437 for (int i = 0; i < d.length (); i++) | |
1438 { | |
1439 di = d(i); | |
1440 os.write (reinterpret_cast<char *> (&di), 4); | |
1441 } | |
1442 | |
1443 int32_t len = nf; | |
1444 os.write (reinterpret_cast<char *> (&len), 4); | |
1445 | |
1446 // Iterating over the list of keys will preserve the order of the | |
1447 // fields. | |
1448 string_vector keys = m.keys (); | |
1449 | |
1450 for (octave_idx_type i = 0; i < nf; i++) | |
1451 { | |
1452 std::string key = keys(i); | |
1453 | |
1454 octave_value val = map.contents (key); | |
1455 | |
1456 bool b = save_binary_data (os, val, key, "", 0, save_as_floats); | |
1457 | |
1458 if (! b) | |
1459 return os; | |
1460 } | |
1461 | |
1462 return true; | |
1463 } | |
1464 | |
1465 bool | |
1466 octave_struct::load_binary (std::istream& is, bool swap, | |
1467 oct_mach_info::float_format fmt) | |
1468 { | |
1469 bool success = true; | |
1470 int32_t len; | |
1471 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
1472 return false; | |
1473 if (swap) | |
1474 swap_bytes<4> (&len); | |
1475 | |
1476 dim_vector dv (1, 1); | |
1477 | |
1478 if (len < 0) | |
1479 { | |
1480 // We have explicit dimensions. | |
1481 int mdims = -len; | |
1482 | |
1483 int32_t di; | |
1484 dv.resize (mdims); | |
1485 | |
1486 for (int i = 0; i < mdims; i++) | |
1487 { | |
1488 if (! is.read (reinterpret_cast<char *> (&di), 4)) | |
1489 return false; | |
1490 if (swap) | |
1491 swap_bytes<4> (&di); | |
1492 dv(i) = di; | |
1493 } | |
1494 | |
1495 if (! is.read (reinterpret_cast<char *> (&len), 4)) | |
1496 return false; | |
1497 if (swap) | |
1498 swap_bytes<4> (&len); | |
1499 } | |
1500 | |
1501 if (len > 0) | |
1502 { | |
1503 Octave_map m (dv); | |
1504 | |
1505 for (octave_idx_type j = 0; j < len; j++) | |
1506 { | |
1507 octave_value t2; | |
1508 bool dummy; | |
1509 std::string doc; | |
1510 | |
1511 // recurse to read cell elements | |
1512 std::string nm = read_binary_data (is, swap, fmt, std::string (), | |
1513 dummy, t2, doc); | |
1514 | |
1515 if (!is) | |
1516 break; | |
1517 | |
1518 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
1519 | |
1520 if (error_state) | |
1521 { | |
1522 error ("load: internal error loading struct elements"); | |
1523 return false; | |
1524 } | |
1525 | |
1526 m.assign (nm, tcell); | |
1527 } | |
1528 | |
1529 if (is) | |
1530 map = m; | |
1531 else | |
1532 { | |
1533 error ("load: failed to load structure"); | |
1534 success = false; | |
1535 } | |
1536 } | |
1537 else if (len == 0) | |
1538 map = Octave_map (dv); | |
1539 else | |
1540 success = false; | |
1541 | |
1542 return success; | |
1543 } | |
1544 | |
1545 #if defined (HAVE_HDF5) | |
1546 | |
1547 bool | |
1548 octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) | |
1549 { | |
1550 hid_t data_hid = -1; | |
1551 | |
1552 #if HAVE_HDF5_18 | |
1553 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); | |
1554 #else | |
1555 data_hid = H5Gcreate (loc_id, name, 0); | |
1556 #endif | |
1557 if (data_hid < 0) return false; | |
1558 | |
1559 // recursively add each element of the structure to this group | |
1560 Octave_map m = map_value (); | |
1561 | |
1562 octave_idx_type nf = m.nfields (); | |
1563 | |
1564 // Iterating over the list of keys will preserve the order of the | |
1565 // fields. | |
1566 string_vector keys = m.keys (); | |
1567 | |
1568 for (octave_idx_type i = 0; i < nf; i++) | |
1569 { | |
1570 std::string key = keys(i); | |
1571 | |
1572 octave_value val = map.contents (key); | |
1573 | |
1574 bool retval2 = add_hdf5_data (data_hid, val, key, "", false, | |
1575 save_as_floats); | |
1576 | |
1577 if (! retval2) | |
1578 break; | |
1579 } | |
1580 | |
1581 H5Gclose (data_hid); | |
1582 | |
1583 return true; | |
1584 } | |
1585 | |
1586 bool | |
1587 octave_struct::load_hdf5 (hid_t loc_id, const char *name) | |
1588 { | |
1589 bool retval = false; | |
1590 | |
1591 hdf5_callback_data dsub; | |
1592 | |
1593 herr_t retval2 = 0; | |
1594 Octave_map m (dim_vector (1, 1)); | |
1595 int current_item = 0; | |
1596 hsize_t num_obj = 0; | |
1597 #if HAVE_HDF5_18 | |
1598 hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); | |
1599 #else | |
1600 hid_t group_id = H5Gopen (loc_id, name); | |
1601 #endif | |
1602 H5Gget_num_objs (group_id, &num_obj); | |
1603 H5Gclose (group_id); | |
1604 | |
1605 // FIXME -- fields appear to be sorted alphabetically on loading. | |
1606 // Why is that happening? | |
1607 | |
1608 while (current_item < static_cast<int> (num_obj) | |
1609 && (retval2 = H5Giterate (loc_id, name, ¤t_item, | |
1610 hdf5_read_next_data, &dsub)) > 0) | |
1611 { | |
1612 octave_value t2 = dsub.tc; | |
1613 | |
1614 Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); | |
1615 | |
1616 if (error_state) | |
1617 { | |
1618 error ("load: internal error loading struct elements"); | |
1619 return false; | |
1620 } | |
1621 | |
1622 m.assign (dsub.name, tcell); | |
1623 | |
1624 } | |
1625 | |
1626 if (retval2 >= 0) | |
1627 { | |
1628 map = m; | |
1629 retval = true; | |
1630 } | |
1631 | |
1632 return retval; | |
1633 } | |
1634 | |
1635 #endif | |
1636 | |
1637 mxArray * | |
1638 octave_struct::as_mxArray (void) const | |
1639 { | |
1640 int nf = nfields (); | |
1641 string_vector kv = map_keys (); | |
1642 | |
1643 OCTAVE_LOCAL_BUFFER (const char *, f, nf); | |
1644 | |
1645 for (int i = 0; i < nf; i++) | |
1646 f[i] = kv[i].c_str (); | |
1647 | |
1648 mxArray *retval = new mxArray (dims (), nf, f); | |
1649 | |
1650 mxArray **elts = static_cast<mxArray **> (retval->get_data ()); | |
1651 | |
1652 mwSize nel = numel (); | |
1653 | |
1654 mwSize ntot = nf * nel; | |
1655 | |
1656 for (int i = 0; i < nf; i++) | |
1657 { | |
1658 Cell c = map.contents (kv[i]); | |
1659 | |
1660 const octave_value *p = c.data (); | |
1661 | |
1662 mwIndex k = 0; | |
1663 for (mwIndex j = i; j < ntot; j += nf) | |
1664 elts[j] = new mxArray (p[k++]); | |
1665 } | |
1666 | |
1667 return retval; | |
1668 } |