GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ov-cell.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1999-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <istream>
31#include <ostream>
32#include <sstream>
33#include <vector>
34#include <queue>
35
36#include "Array-util.h"
37#include "byte-swap.h"
38#include "lo-utils.h"
39#include "quit.h"
40#include "oct-locbuf.h"
41
42#include "builtin-defun-decls.h"
43#include "defun.h"
44#include "error.h"
45#include "mxarray.h"
46#include "ov-cell.h"
47#include "ovl.h"
48#include "oct-hdf5.h"
49#include "unwind-prot.h"
50#include "utils.h"
51#include "ov-fcn-handle.h"
52#include "ov-re-mat.h"
53#include "ov-scalar.h"
54#include "pr-output.h"
55#include "ov-scalar.h"
56#include "errwarn.h"
57
58#include "ls-oct-text.h"
59#include "ls-oct-binary.h"
60#include "ls-hdf5.h"
61#include "ls-utils.h"
62
63
65
66void
67octave_cell::break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame)
68{
69 for (octave_idx_type i = 0; i < m_matrix.numel (); i++)
70 m_matrix(i).break_closure_cycles (frame);
71}
72
75{
76 octave_value_list retval;
77
78 switch (type)
79 {
80 case '(':
81 retval(0) = do_index_op (idx);
82 break;
83
84 case '{':
85 {
86 if (idx.empty ())
87 error ("invalid empty index expression {}, use {:} instead");
88
89 octave_value tmp = do_index_op (idx);
90
91 Cell tcell = tmp.cell_value ();
92
93 if (tcell.numel () == 1)
94 retval(0) = tcell(0, 0);
95 else
96 {
97 // Return a comma-separated list.
98 retval = octave_value (octave_value_list (tcell));
99 }
100 }
101 break;
102
103 case '.':
104 {
105 std::string nm = type_name ();
106 error ("%s cannot be indexed with %c", nm.c_str (), type);
107 }
108 break;
109
110 default:
111 error ("unexpected: index not '(', '{', or '.' in octave_cell::simple_subsref - please report this bug");
112 }
113
114 return retval;
115}
116
118octave_cell::subsref (const std::string& type,
119 const std::list<octave_value_list>& idx,
120 int nargout)
121{
122 octave_value_list retval;
123
124 switch (type[0])
125 {
126 case '(':
127 retval(0) = do_index_op (idx.front ());
128 break;
129
130 case '{':
131 {
132 if (idx.front ().empty ())
133 error ("invalid empty index expression {}, use {:} instead");
134
135 octave_value tmp = do_index_op (idx.front ());
136
137 Cell tcell = tmp.cell_value ();
138
139 if (tcell.numel () == 1)
140 retval(0) = tcell(0, 0);
141 else
142 {
143 // Return a comma-separated list.
144 retval = octave_value (octave_value_list (tcell));
145 }
146 }
147 break;
148
149 case '.':
150 {
151 std::string nm = type_name ();
152 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
153 }
154 break;
155
156 default:
157 error ("unexpected: index not '(', '{', or '.' in octave_cell::subsref - please report this bug");
158 }
159
160 // FIXME: perhaps there should be an
161 // octave_value_list::next_subsref member function? See also
162 // octave_user_function::subsref.
163
164 if (idx.size () > 1)
165 retval = retval(0).next_subsref (nargout, type, idx);
166
167 return retval;
168}
169
171octave_cell::subsref (const std::string& type,
172 const std::list<octave_value_list>& idx,
173 bool auto_add)
174{
175 octave_value retval;
176
177 switch (type[0])
178 {
179 case '(':
180 retval = do_index_op (idx.front (), auto_add);
181 break;
182
183 case '{':
184 {
185 octave_value tmp = do_index_op (idx.front (), auto_add);
186
187 const Cell tcell = tmp.cell_value ();
188
189 if (tcell.numel () == 1)
190 retval = tcell(0, 0);
191 else
192 {
193 // Return a comma-separated list.
194 retval = octave_value (octave_value_list (tcell));
195 }
196 }
197 break;
198
199 case '.':
200 {
201 std::string nm = type_name ();
202 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
203 }
204 break;
205
206 default:
207 error ("unexpected: index not '(', '{', or '.' in octave_cell::subsref - please report this bug");
208 }
209
210 // FIXME: perhaps there should be an
211 // octave_value_list::next_subsref member function? See also
212 // octave_user_function::subsref.
213
214 if (idx.size () > 1)
215 retval = retval.next_subsref (auto_add, type, idx);
216
217 return retval;
218}
219
221octave_cell::subsasgn (const std::string& type,
222 const std::list<octave_value_list>& idx,
223 const octave_value& rhs)
224{
225 octave_value retval;
226
227 int n = type.length ();
228
229 octave_value t_rhs = rhs;
230
231 clear_cellstr_cache ();
232
233 if (idx.front ().empty ())
234 error ("missing index in indexed assignment");
235
236 if (n > 1)
237 {
238 switch (type[0])
239 {
240 case '(':
241 {
242 if (isempty () && type[1] == '.')
243 {
244 // Allow conversion of empty cell array to some other
245 // type in cases like
246 //
247 // x = {}; x(i).f = rhs
248
249 octave_value tmp = octave_value::empty_conv (type, rhs);
250
251 return tmp.subsasgn (type, idx, rhs);
252 }
253 else
254 {
255 octave_value tmp = do_index_op (idx.front (), true);
256
257 if (! tmp.is_defined ())
258 tmp = octave_value::empty_conv (type.substr (1), rhs);
259
260 std::list<octave_value_list> next_idx (idx);
261
262 next_idx.erase (next_idx.begin ());
263
264 tmp.make_unique ();
265
266 t_rhs = tmp.subsasgn (type.substr (1), next_idx, rhs);
267 }
268 }
269 break;
270
271 case '{':
272 {
274 Cell tmpc = m_matrix.index (idx.front (), true);
275
276 std::list<octave_value_list> next_idx (idx);
277
278 next_idx.erase (next_idx.begin ());
279
280 std::string next_type = type.substr (1);
281
282 if (tmpc.numel () != 1)
284
285 octave_value tmp = tmpc(0);
286 tmpc = Cell ();
287
288 if (! tmp.is_defined () || tmp.is_zero_by_zero ())
289 {
290 tmp = octave_value::empty_conv (type.substr (1), rhs);
291 tmp.make_unique (); // probably a no-op.
292 }
293 else
294 // optimization: ignore copy still stored inside array.
295 tmp.make_unique (1);
296
297 t_rhs = tmp.subsasgn (next_type, next_idx, rhs);
298 }
299 break;
300
301 case '.':
302 {
303 if (! isempty ())
304 {
305 std::string nm = type_name ();
306 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
307 }
308
309 // Do nothing; the next branch will handle it.
310 }
311 break;
312
313 default:
314 error ("unexpected: index not '(', '{', or '.' in octave_cell::subsasgn - please report this bug");
315 }
316 }
317
318 switch (type[0])
319 {
320 case '(':
321 {
322 octave_value_list i = idx.front ();
323
324 if (t_rhs.iscell ())
326 else if (t_rhs.isnull ())
328 else
330
331 m_count++;
332 retval = octave_value (this);
333 }
334 break;
335
336 case '{':
337 {
338 octave_value_list idxf = idx.front ();
339
340 if (t_rhs.is_cs_list ())
341 {
342 Cell tmp_cell = Cell (t_rhs.list_value ());
343
344 // Inquire the proper shape of the RHS.
345
346 dim_vector didx = dims ().redim (idxf.length ());
347 for (octave_idx_type k = 0; k < idxf.length (); k++)
348 if (! idxf(k).is_magic_colon ()) didx(k) = idxf(k).numel ();
349
350 if (didx.numel () == tmp_cell.numel ())
351 tmp_cell = tmp_cell.reshape (didx);
352
353 octave_base_matrix<Cell>::assign (idxf, tmp_cell);
354 }
355 else if (idxf.all_scalars ()
356 || do_index_op (idxf, true).numel () == 1)
357 // Regularize a null matrix if stored into a cell.
359 Cell (t_rhs.storable_value ()));
360 else
362
363 m_count++;
364 retval = octave_value (this);
365 }
366 break;
367
368 case '.':
369 {
370 if (! isempty ())
371 {
372 std::string nm = type_name ();
373 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
374 }
375
376 // Allow conversion of empty cell array to some other
377 // type in cases like
378 //
379 // x = {}; x.f = rhs
380
381 octave_value tmp = octave_value::empty_conv (type, rhs);
382
383 return tmp.subsasgn (type, idx, rhs);
384 }
385 break;
386
387 default:
388 error ("unexpected: index not '(', '{', or '.' in octave_cell::subsasgn - please report this bug");
389 }
390
391 return retval;
392}
393
394bool
396{
397 bool retval;
398 if (m_cellstr_cache.get ())
399 retval = true;
400 else
401 {
402 retval = m_matrix.iscellstr ();
403 // Allocate empty cache to mark that this is indeed a cellstr.
404 if (retval)
405 m_cellstr_cache.reset (new Array<std::string> ());
406 }
407
408 return retval;
409}
410
411void
413{
414 clear_cellstr_cache ();
416}
417
418void
420{
421 clear_cellstr_cache ();
423}
424
425void
427{
428 clear_cellstr_cache ();
430}
431
432std::size_t
434{
435 std::size_t retval = 0;
436
437 for (octave_idx_type i = 0; i < numel (); i++)
438 retval += m_matrix(i).byte_size ();
439
440 return retval;
441}
442
445{
446 octave_value retval;
447
448 if (! iscellstr ())
449 error ("sort: only cell arrays of character strings may be sorted");
450
452
453 tmp = tmp.sort (dim, mode);
454
455 // We already have the cache.
456 retval = new octave_cell (tmp);
457
458 return retval;
459}
460
463 sortmode mode) const
464{
465 octave_value retval;
466
467 if (! iscellstr ())
468 error ("sort: only cell arrays of character strings may be sorted");
469
471
472 tmp = tmp.sort (sidx, dim, mode);
473
474 // We already have the cache.
475 retval = new octave_cell (tmp);
476
477 return retval;
478}
479
482{
483 sortmode retval = UNSORTED;
484
485 if (! iscellstr ())
486 error ("issorted: A is not a cell array of strings");
487
489
490 retval = tmp.issorted (mode);
491
492 return retval;
493}
494
497{
499
500 if (! iscellstr ())
501 error ("sortrows: only cell arrays of character strings may be sorted");
502
504
505 retval = tmp.sort_rows_idx (mode);
506
507 return retval;
508}
509
512{
513 sortmode retval = UNSORTED;
514
515 if (! iscellstr ())
516 error ("issorted: A is not a cell array of strings");
517
519
520 retval = tmp.is_sorted_rows (mode);
521
522 return retval;
523}
524
525bool
527{
528 error ("invalid conversion from cell array to logical value");
529}
530
533{
535}
536
539{
540 string_vector retval;
541
542 octave_idx_type nel = numel ();
543
544 int n_elts = 0;
545
546 octave_idx_type max_len = 0;
547
548 std::queue<string_vector> strvec_queue;
549
550 for (octave_idx_type i = 0; i < nel; i++)
551 {
553
554 octave_idx_type s_len = s.numel ();
555
556 n_elts += s_len ? s_len : 1;
557
558 octave_idx_type s_max_len = s.max_length ();
559
560 if (s_max_len > max_len)
561 max_len = s_max_len;
562
563 strvec_queue.push (s);
564 }
565
566 retval = string_vector (n_elts);
567
568 octave_idx_type k = 0;
569
570 for (octave_idx_type i = 0; i < nel; i++)
571 {
572 const string_vector s = strvec_queue.front ();
573 strvec_queue.pop ();
574
575 octave_idx_type s_len = s.numel ();
576
577 if (s_len)
578 {
579 for (octave_idx_type j = 0; j < s_len; j++)
580 {
581 std::string t = s[j];
582 int t_len = t.length ();
583
584 if (pad && max_len > t_len)
585 t += std::string (max_len - t_len, ' ');
586
587 retval[k++] = t;
588 }
589 }
590 else if (pad)
591 retval[k++] = std::string (max_len, ' ');
592 else
593 retval[k++] = "";
594 }
595
596 return retval;
597}
598
601{
602 if (! iscellstr ())
603 error ("invalid conversion from cell array to array of strings");
604
605 if (m_cellstr_cache->isempty ())
606 *m_cellstr_cache = m_matrix.cellstr_value ();
607
608 return *m_cellstr_cache;
609}
610
611bool
613{
614 return true;
615}
616
617void
618octave_cell::print (std::ostream& os, bool)
619{
620 print_raw (os);
621}
622
623void
624octave_cell::print_raw (std::ostream& os, bool) const
625{
626 int nd = m_matrix.ndims ();
627
628 if (nd == 2)
629 {
630 octave_idx_type nr = rows ();
631 octave_idx_type nc = columns ();
632
633 if (nr > 0 && nc > 0)
634 {
635 indent (os);
636 os << '{';
637 newline (os);
638
640
641 for (octave_idx_type j = 0; j < nc; j++)
642 {
643 for (octave_idx_type i = 0; i < nr; i++)
644 {
645 octave_quit ();
646
647 std::ostringstream buf;
648 buf << '[' << i+1 << ',' << j+1 << ']';
649
650 octave_value val = m_matrix(i, j);
651
652 val.print_with_name (os, buf.str ());
653 }
654 }
655
657
658 indent (os);
659 os << '}';
660 newline (os);
661 }
662 else
663 {
664 indent (os);
665 os << "{}";
667 os << '(' << nr << 'x' << nc << ')';
668 newline (os);
669 }
670 }
671 else
672 {
673 indent (os);
674 const dim_vector& dv = m_matrix.dims ();
675 os << '{' << dv.str () << " Cell Array}";
676 newline (os);
677 }
678}
679
680bool
681octave_cell::print_name_tag (std::ostream& os, const std::string& name) const
682{
683 bool retval = false;
684
685 indent (os);
686
687 if (isempty () || ndims () > 2)
688 os << name << " = ";
689 else
690 {
691 os << name << " =";
692 newline (os);
693 retval = true;
694 }
695
696 return retval;
697}
698
699void
700octave_cell::short_disp (std::ostream& os) const
701{
702 // octave_base_matrix<octave_value>::short_disp is not appropriate for
703 // cell arrays.
704
706}
707
708#define CELL_ELT_TAG "<cell-element>"
709
710bool
711octave_cell::save_ascii (std::ostream& os)
712{
713 const dim_vector& dv = dims ();
714 if (dv.ndims () > 2)
715 {
716 os << "# ndims: " << dv.ndims () << "\n";
717
718 for (int i = 0; i < dv.ndims (); i++)
719 os << ' ' << dv(i);
720 os << "\n";
721
722 Cell tmp = cell_value ();
723
724 for (octave_idx_type i = 0; i < dv.numel (); i++)
725 {
726 octave_value o_val = tmp.elem (i);
727
728 // Recurse to save sub-value.
729 bool b = save_text_data (os, o_val, CELL_ELT_TAG, false, 0);
730
731 if (! b)
732 return ! os.fail ();
733 }
734 }
735 else
736 {
737 // Keep this case, rather than use generic code above for backward
738 // compatibility. Makes load_ascii much more complex!!
739 os << "# rows: " << rows () << "\n"
740 << "# columns: " << columns () << "\n";
741
742 Cell tmp = cell_value ();
743
744 for (octave_idx_type j = 0; j < tmp.cols (); j++)
745 {
746 for (octave_idx_type i = 0; i < tmp.rows (); i++)
747 {
748 octave_value o_val = tmp.elem (i, j);
749
750 // Recurse to save sub-value.
751 bool b = save_text_data (os, o_val, CELL_ELT_TAG, false, 0);
752
753 if (! b)
754 return ! os.fail ();
755 }
756
757 os << "\n";
758 }
759 }
760
761 return true;
762}
763
764bool
765octave_cell::load_ascii (std::istream& is)
766{
767 clear_cellstr_cache ();
768
769 string_vector keywords(2);
770
771 keywords[0] = "ndims";
772 keywords[1] = "rows";
773
774 std::string kw;
775 octave_idx_type val = 0;
776
777 if (! extract_keyword (is, keywords, kw, val, true))
778 error ("load: failed to extract number of rows and columns");
779
780 if (kw == "ndims")
781 {
782 int mdims = static_cast<int> (val);
783
784 if (mdims < 0)
785 error ("load: failed to extract number of rows and columns");
786
787 dim_vector dv;
788 dv.resize (mdims);
789
790 for (int i = 0; i < mdims; i++)
791 is >> dv(i);
792
793 Cell tmp(dv);
794
795 for (octave_idx_type i = 0; i < dv.numel (); i++)
796 {
797 octave_value t2;
798 bool dummy;
799
800 // recurse to read cell elements
801 std::string nm = read_text_data (is, "",
802 dummy, t2, i);
803
804 if (nm != CELL_ELT_TAG)
805 error ("load: cell array element had unexpected name");
806
807 if (is)
808 tmp.elem (i) = t2;
809 }
810
811 if (! is)
812 error ("load: failed to load matrix constant");
813
814 m_matrix = tmp;
815 }
816 else if (kw == "rows")
817 {
818 octave_idx_type nr = val;
819 octave_idx_type nc = 0;
820
821 if (nr < 0 || ! extract_keyword (is, "columns", nc) || nc < 0)
822 error ("load: failed to extract number of rows and columns for cell array");
823
824 if (nr > 0 && nc > 0)
825 {
826 Cell tmp (nr, nc);
827
828 for (octave_idx_type j = 0; j < nc; j++)
829 {
830 for (octave_idx_type i = 0; i < nr; i++)
831 {
832 octave_value t2;
833 bool dummy;
834
835 // recurse to read cell elements
836 std::string nm = read_text_data (is, "",
837 dummy, t2, i);
838
839 if (nm != CELL_ELT_TAG)
840 error ("load: cell array element had unexpected name");
841
842 if (is)
843 tmp.elem (i, j) = t2;
844 }
845 }
846
847 if (! is)
848 error ("load: failed to load cell element");
849
850 m_matrix = tmp;
851 }
852 else if (nr == 0 || nc == 0)
853 m_matrix = Cell (nr, nc);
854 else
855 error ("unexpected dimensions in octave_cell::load_ascii - please report this bug");
856 }
857 else
858 error ("unexpected dimensions keyword (= '%s') octave_cell::load_ascii - please report this bug", kw.c_str ());
859
860 return true;
861}
862
863bool
864octave_cell::save_binary (std::ostream& os, bool save_as_floats)
865{
866 const dim_vector& dv = dims ();
867 if (dv.ndims () < 1)
868 return false;
869
870 // Use negative value for ndims
871 int32_t di = - dv.ndims ();
872 os.write (reinterpret_cast<char *> (&di), 4);
873 for (int i = 0; i < dv.ndims (); i++)
874 {
875 di = dv(i);
876 os.write (reinterpret_cast<char *> (&di), 4);
877 }
878
879 Cell tmp = cell_value ();
880
881 for (octave_idx_type i = 0; i < dv.numel (); i++)
882 {
883 octave_value o_val = tmp.elem (i);
884
885 // Recurse to save sub-value.
886 bool b = save_binary_data (os, o_val, CELL_ELT_TAG, "", 0,
887 save_as_floats);
888
889 if (! b)
890 return false;
891 }
892
893 return true;
894}
895
896bool
897octave_cell::load_binary (std::istream& is, bool swap,
898 octave::mach_info::float_format fmt)
899{
900 clear_cellstr_cache ();
901
902 int32_t mdims;
903 if (! is.read (reinterpret_cast<char *> (&mdims), 4))
904 return false;
905 if (swap)
906 swap_bytes<4> (&mdims);
907 if (mdims >= 0)
908 return false;
909
910 mdims = -mdims;
911 int32_t di;
912 dim_vector dv;
913 dv.resize (mdims);
914
915 for (int i = 0; i < mdims; i++)
916 {
917 if (! is.read (reinterpret_cast<char *> (&di), 4))
918 return false;
919 if (swap)
920 swap_bytes<4> (&di);
921 dv(i) = di;
922 }
923
924 // Convert an array with a single dimension to be a row vector.
925 // Octave should never write files like this, other software
926 // might.
927
928 if (mdims == 1)
929 {
930 mdims = 2;
931 dv.resize (mdims);
932 dv(1) = dv(0);
933 dv(0) = 1;
934 }
935
936 octave_idx_type nel = dv.numel ();
937 Cell tmp(dv);
938
939 for (octave_idx_type i = 0; i < nel; i++)
940 {
941 octave_value t2;
942 bool dummy;
943 std::string doc;
944
945 // recurse to read cell elements
946 std::string nm = read_binary_data (is, swap, fmt, "",
947 dummy, t2, doc);
948
949 if (nm != CELL_ELT_TAG)
950 error ("load: cell array element had unexpected name");
951
952 if (is)
953 tmp.elem (i) = t2;
954 }
955
956 if (! is)
957 error ("load: failed to load matrix constant");
958
959 m_matrix = tmp;
960
961 return true;
962}
963
964const void *
966{
967 clear_cellstr_cache ();
968 return m_matrix.data ();
969}
970
971bool
972octave_cell::save_hdf5 (octave_hdf5_id loc_id, const char *name,
973 bool save_as_floats)
974{
975#if defined (HAVE_HDF5)
976
977 const dim_vector& dv = dims ();
978 int empty = save_hdf5_empty (loc_id, name, dv);
979 if (empty)
980 return (empty > 0);
981
982 hsize_t rank = dv.ndims ();
983 hid_t space_hid, data_hid, size_hid;
984 space_hid = data_hid = size_hid = -1;
985
986#if defined (HAVE_HDF5_18)
987 data_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
989#else
990 data_hid = H5Gcreate (loc_id, name, 0);
991#endif
992
993 if (data_hid < 0)
994 return false;
995
996 // Have to save cell array shape, since can't have a
997 // dataset of groups....
998
999 space_hid = H5Screate_simple (1, &rank, nullptr);
1000
1001 if (space_hid < 0)
1002 {
1003 H5Gclose (data_hid);
1004 return false;
1005 }
1006
1007 OCTAVE_LOCAL_BUFFER (octave_idx_type, hdims, rank);
1008
1009 // Octave uses column-major, while HDF5 uses row-major ordering
1010 for (hsize_t i = 0; i < rank; i++)
1011 hdims[i] = dv(rank-i-1);
1012
1013#if defined (HAVE_HDF5_18)
1014 size_hid = H5Dcreate (data_hid, "dims", H5T_NATIVE_IDX, space_hid,
1017#else
1018 size_hid = H5Dcreate (data_hid, "dims", H5T_NATIVE_IDX, space_hid,
1020#endif
1021 if (size_hid < 0)
1022 {
1023 H5Sclose (space_hid);
1024 H5Gclose (data_hid);
1025 return false;
1026 }
1027
1028 if (H5Dwrite (size_hid, H5T_NATIVE_IDX, octave_H5S_ALL, octave_H5S_ALL,
1029 octave_H5P_DEFAULT, hdims) < 0)
1030 {
1031 H5Dclose (size_hid);
1032 H5Sclose (space_hid);
1033 H5Gclose (data_hid);
1034 return false;
1035 }
1036
1037 H5Dclose (size_hid);
1038 H5Sclose (space_hid);
1039
1040 // Recursively add each element of the cell to this group.
1041
1042 Cell tmp = cell_value ();
1043
1044 octave_idx_type nel = dv.numel ();
1045
1046 for (octave_idx_type i = 0; i < nel; i++)
1047 {
1048 std::ostringstream buf;
1049 int digits = static_cast<int> (std::floor (::log10 (static_cast<double>
1050 (nel)) + 1.0));
1051 buf << '_' << std::setw (digits) << std::setfill ('0') << i;
1052 std::string s = buf.str ();
1053
1054 if (! add_hdf5_data (data_hid, tmp.elem (i), s.c_str (), "", false,
1055 save_as_floats))
1056 {
1057 H5Gclose (data_hid);
1058 return false;
1059 }
1060 }
1061
1062 H5Gclose (data_hid);
1063
1064 return true;
1065
1066#else
1067 octave_unused_parameter (loc_id);
1068 octave_unused_parameter (name);
1069 octave_unused_parameter (save_as_floats);
1070
1071 warn_save ("hdf5");
1072
1073 return false;
1074#endif
1075}
1076
1077bool
1078octave_cell::load_hdf5 (octave_hdf5_id loc_id, const char *name)
1079{
1080 bool retval = false;
1081
1082#if defined (HAVE_HDF5)
1083
1084 clear_cellstr_cache ();
1085
1086 dim_vector dv;
1087 int empty = load_hdf5_empty (loc_id, name, dv);
1088 if (empty > 0)
1089 m_matrix.resize (dv);
1090 if (empty)
1091 return (empty > 0);
1092
1093#if defined (HAVE_HDF5_18)
1094 hid_t group_id = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
1095#else
1096 hid_t group_id = H5Gopen (loc_id, name);
1097#endif
1098
1099 if (group_id < 0)
1100 return false;
1101
1102#if defined (HAVE_HDF5_18)
1103 hid_t data_hid = H5Dopen (group_id, "dims", octave_H5P_DEFAULT);
1104#else
1105 hid_t data_hid = H5Dopen (group_id, "dims");
1106#endif
1107 hid_t space_hid = H5Dget_space (data_hid);
1108 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
1109 if (rank != 1)
1110 {
1111 H5Dclose (data_hid);
1112 H5Gclose (group_id);
1113 return false;
1114 }
1115
1116 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
1117 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
1118
1119 H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
1120
1121 // Octave uses column-major, while HDF5 uses row-major ordering.
1122
1123 dv.resize (hdims[0]);
1124
1125 OCTAVE_LOCAL_BUFFER (octave_idx_type, tmp, hdims[0]);
1126
1127 if (H5Dread (data_hid, H5T_NATIVE_IDX, octave_H5S_ALL, octave_H5S_ALL,
1128 octave_H5P_DEFAULT, tmp) < 0)
1129 {
1130 H5Dclose (data_hid);
1131 H5Gclose (group_id);
1132 return false;
1133 }
1134
1135 H5Dclose (data_hid);
1136 H5Gclose (group_id);
1137
1138 for (hsize_t i = 0, j = hdims[0] - 1; i < hdims[0]; i++, j--)
1139 dv(j) = tmp[i];
1140
1141 hdf5_callback_data dsub;
1142
1143 herr_t retval2 = -1;
1144
1145 Cell m (dv);
1146
1147 int current_item = 0;
1148
1149 hsize_t num_obj = 0;
1150#if defined (HAVE_HDF5_18)
1151 group_id = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
1152#else
1153 group_id = H5Gopen (loc_id, name);
1154#endif
1155 H5Gget_num_objs (group_id, &num_obj);
1156 H5Gclose (group_id);
1157
1158 for (octave_idx_type i = 0; i < dv.numel (); i++)
1159 {
1160
1161 if (current_item >= static_cast<int> (num_obj))
1162 retval2 = -1;
1163 else
1164 retval2 = hdf5_h5g_iterate (loc_id, name, &current_item, &dsub);
1165
1166 if (retval2 <= 0)
1167 break;
1168
1169 octave_value ov = dsub.tc;
1170 m.elem (i) = ov;
1171
1172 }
1173
1174 if (retval2 >= 0)
1175 {
1176 m_matrix = m;
1177 retval = true;
1178 }
1179
1180#else
1181 octave_unused_parameter (loc_id);
1182 octave_unused_parameter (name);
1183
1184 warn_load ("hdf5");
1185#endif
1186
1187 return retval;
1188}
1189
1191
1192DEFUN (iscell, args, ,
1193 doc: /* -*- texinfo -*-
1194@deftypefn {} {@var{tf} =} iscell (@var{x})
1195Return true if @var{x} is a cell array object.
1196@seealso{ismatrix, isstruct, iscellstr, isa}
1197@end deftypefn */)
1198{
1199 if (args.length () != 1)
1200 print_usage ();
1201
1202 return ovl (args(0).iscell ());
1203}
1204
1205DEFUN (cell, args, ,
1206 doc: /* -*- texinfo -*-
1207@deftypefn {} {@var{C} =} cell (@var{n})
1208@deftypefnx {} {@var{C} =} cell (@var{m}, @var{n})
1209@deftypefnx {} {@var{C} =} cell (@var{m}, @var{n}, @var{k}, @dots{})
1210@deftypefnx {} {@var{C} =} cell ([@var{m} @var{n} @dots{}])
1211Create a new cell array object.
1212
1213If invoked with a single scalar integer argument, return a square
1214@nospell{NxN} cell array. If invoked with two or more scalar integer
1215arguments, or a vector of integer values, return an array with the given
1216dimensions.
1217@seealso{cellstr, mat2cell, num2cell, struct2cell}
1218@end deftypefn */)
1219{
1220 int nargin = args.length ();
1221
1222 dim_vector dims;
1223
1224 switch (nargin)
1225 {
1226 case 0:
1227 dims = dim_vector (0, 0);
1228 break;
1229
1230 case 1:
1231 if (args(0).iscell ())
1232 return args(0); // shortcut path for input which is already a Cell
1233 else
1234 get_dimensions (args(0), "cell", dims);
1235 break;
1236
1237 default:
1238 {
1239 dims.resize (nargin);
1240
1241 for (int i = 0; i < nargin; i++)
1242 dims(i) = (args(i).isempty ()
1243 ? 0 : args(i).strict_idx_type_value ("cell: dimension must be a scalar integer"));
1244 }
1245 break;
1246 }
1247
1249
1250 check_dimensions (dims, "cell");
1251
1252 return ovl (Cell (dims));
1253}
1254
1255/*
1256## Note: Matlab compatibility requires using 0 for negative dimensions.
1257%!assert (size (cell (2, -3)), [2, 0])
1258
1259%!test <*63132>
1260%! x = {1, 3};
1261%! y = cell (x);
1262%! assert (x, y);
1263%! x = cell (0, 3);
1264%! y = cell (x);
1265%! assert (x, y);
1266
1267## This might work on some system someday, but for now, who has a system
1268## where a 16 yottabyte array can be allocated? See bug #50934.
1269%!error <out of memory> cell (1e24, 1)
1270*/
1271
1272DEFUN (iscellstr, args, ,
1273 doc: /* -*- texinfo -*-
1274@deftypefn {} {@var{tf} =} iscellstr (@var{cell})
1275Return true if every element of the cell array @var{cell} is a character
1276string.
1277@seealso{ischar, isstring}
1278@end deftypefn */)
1279{
1280 if (args.length () != 1)
1281 print_usage ();
1282
1283 return ovl (args(0).iscellstr ());
1284}
1285
1286DEFUN (cellstr, args, ,
1287 doc: /* -*- texinfo -*-
1288@deftypefn {} {@var{cstr} =} cellstr (@var{strmat})
1289Create a new cell array object from the elements of the string array
1290@var{strmat}.
1291
1292Each row of @var{strmat} becomes an element of @var{cstr}. Any trailing
1293spaces in a row are deleted before conversion.
1294
1295To convert back from a cellstr to a character array use @code{char}.
1296@seealso{cell, char}
1297@end deftypefn */)
1298{
1299 if (args.length () != 1)
1300 print_usage ();
1301
1302 octave_value_list tmp = Fiscellstr (args, 1);
1303
1304 if (tmp(0).is_true ())
1305 return ovl (args(0));
1306 else
1307 {
1308 string_vector s = args(0).xstring_vector_value ("cellstr: argument STRING must be a 2-D character array");
1309
1310 return ovl (s.isempty () ? Cell (octave_value (""))
1311 : Cell (s, true));
1312 }
1313}
1314
1315DEFUN (struct2cell, args, ,
1316 doc: /* -*- texinfo -*-
1317@deftypefn {} {@var{c} =} struct2cell (@var{s})
1318Create a new cell array from the objects stored in the struct object.
1319
1320If @var{f} is the number of fields in the structure, the resulting cell
1321array will have a dimension vector corresponding to
1322@code{[@var{f} size(@var{s})]}. For example:
1323
1324@example
1325@group
1326s = struct ("name", @{"Peter", "Hannah", "Robert"@},
1327 "age", @{23, 16, 3@});
1328c = struct2cell (s)
1329 @result{} c = @{2x1x3 Cell Array@}
1330c(1,1,:)(:)
1331 @result{}
1332 @{
1333 [1,1] = Peter
1334 [2,1] = Hannah
1335 [3,1] = Robert
1336 @}
1337c(2,1,:)(:)
1338 @result{}
1339 @{
1340 [1,1] = 23
1341 [2,1] = 16
1342 [3,1] = 3
1343 @}
1344@end group
1345@end example
1346
1347@seealso{cell2struct, namedargs2cell, fieldnames}
1348@end deftypefn */)
1349{
1350 if (args.length () != 1)
1351 print_usage ();
1352
1353 const octave_map m = args(0).xmap_value ("struct2cell: argument S must be a structure");
1354
1355 const dim_vector m_dv = m.dims ();
1356
1357 octave_idx_type num_fields = m.nfields ();
1358
1359 // The resulting dim_vector should have dimensions:
1360 // [numel(fields) size(struct)]
1361 // except if the struct is a column vector.
1362
1363 dim_vector result_dv;
1364 if (m_dv(m_dv.ndims () - 1) == 1)
1365 result_dv.resize (m_dv.ndims ());
1366 else
1367 result_dv.resize (m_dv.ndims () + 1); // Add 1 for the fields.
1368
1369 result_dv(0) = num_fields;
1370
1371 for (int i = 1; i < result_dv.ndims (); i++)
1372 result_dv(i) = m_dv(i-1);
1373
1374 Cell c (result_dv);
1375
1376 octave_idx_type n_elts = m.numel ();
1377
1378 // Fill c in one sweep. Note that thanks to octave_map structure,
1379 // we don't need a key lookup at all.
1380 for (octave_idx_type j = 0; j < n_elts; j++)
1381 for (octave_idx_type i = 0; i < num_fields; i++)
1382 c.xelem (i, j) = m.contents(i)(j);
1383
1384 return ovl (c);
1385}
1386
1387/*
1388%!test
1389%! keys = cellstr (char (floor (rand (11,10)*24+65)))';
1390%! vals = cellfun (@(x) mat2cell (rand (19,1), ones (19,1), 1), ...
1391%! mat2cell ([1:11]', ones (11,1), 1), "uniformoutput", false)';
1392%! s = struct ([keys; vals]{:});
1393%! t = cell2struct ([vals{:}], keys, 2);
1394%! assert (s, t);
1395%! assert (struct2cell (s), [vals{:}]');
1396%! assert (fieldnames (s), keys');
1397*/
1398
1399OCTAVE_END_NAMESPACE(octave)
1400
1401mxArray *
1402octave_cell::as_mxArray (bool interleaved) const
1403{
1404 mxArray *retval = new mxArray (interleaved, dims ());
1405
1406 mxArray **elts = static_cast<mxArray **> (retval->get_data ());
1407
1408 mwSize nel = numel ();
1409
1410 const octave_value *p = m_matrix.data ();
1411
1412 for (mwIndex i = 0; i < nel; i++)
1413 elts[i] = new mxArray (interleaved, p[i]);
1414
1415 return retval;
1416}
1417
1420{
1421 switch (umap)
1422 {
1423#define FORWARD_MAPPER(UMAP) \
1424 case umap_ ## UMAP: \
1425 return m_matrix.UMAP ()
1426
1427 FORWARD_MAPPER (xisalnum);
1428 FORWARD_MAPPER (xisalpha);
1429 FORWARD_MAPPER (xisascii);
1430 FORWARD_MAPPER (xiscntrl);
1431 FORWARD_MAPPER (xisdigit);
1432 FORWARD_MAPPER (xisgraph);
1433 FORWARD_MAPPER (xislower);
1434 FORWARD_MAPPER (xisprint);
1435 FORWARD_MAPPER (xispunct);
1436 FORWARD_MAPPER (xisspace);
1437 FORWARD_MAPPER (xisupper);
1438 FORWARD_MAPPER (xisxdigit);
1439 FORWARD_MAPPER (xtolower);
1440 FORWARD_MAPPER (xtoupper);
1441
1442 default:
1443 return octave_base_value::map (umap);
1444 }
1445}
void swap_bytes< 4 >(void *ptr)
Definition byte-swap.h:63
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
std::size_t byte_size() const
Size of the specified dimension.
Definition Array.h:503
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:563
int ndims() const
Size of the specified dimension.
Definition Array.h:679
octave_idx_type rows() const
Definition Array.h:463
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Array< octave_idx_type > sort_rows_idx(sortmode mode=ASCENDING) const
Sort by rows returns only indices.
octave_idx_type cols() const
Definition Array.h:473
void make_unique()
Definition Array.h:220
Array< T, Alloc > sort(int dim=0, sortmode mode=ASCENDING) const
Size of the specified dimension.
const T * data() const
Size of the specified dimension.
Definition Array.h:665
sortmode issorted(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
sortmode is_sorted_rows(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
Definition Cell.h:41
Cell reshape(const dim_vector &new_dims) const
Definition Cell.h:117
Cell index(const octave_value_list &idx, bool resize_ok=false) const
Definition Cell.cc:171
Array< std::string > cellstr_value() const
Definition Cell.cc:145
string_vector string_vector_value() const
Definition Cell.cc:158
bool iscellstr() const
Definition Cell.cc:126
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
std::string str(char sep='x') const
Definition dim-vector.cc:68
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
void chop_trailing_singletons()
Definition dim-vector.h:160
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:253
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
void * get_data() const
Definition mxarray.h:482
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
void delete_elements(const octave_value_list &idx)
octave_idx_type numel() const
dim_vector dims() const
void assign(const octave_value_list &idx, const MT &rhs)
octave_idx_type rows() const
Definition ov-base.h:384
octave_idx_type columns() const
Definition ov-base.h:391
virtual void short_disp(std::ostream &os) const
Definition ov-base.h:761
void increment_indent_level() const
Definition ov-base.h:939
void indent(std::ostream &os) const
Definition ov-base.cc:1358
void newline(std::ostream &os) const
Definition ov-base.cc:1377
virtual octave_value map(unary_mapper_t) const
Definition ov-base.cc:1170
octave::refcount< octave_idx_type > m_count
Definition ov-base.h:958
void warn_load(const char *type) const
Definition ov-base.cc:1152
virtual bool is_magic_colon() const
Definition ov-base.h:477
void decrement_indent_level() const
Definition ov-base.h:942
bool isempty() const
Definition ov-base.h:429
friend class octave_value
Definition ov-base.h:278
void warn_save(const char *type) const
Definition ov-base.cc:1161
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition ov-cell.cc:221
void short_disp(std::ostream &os) const
Definition ov-cell.cc:700
bool is_true() const
Definition ov-cell.cc:526
octave_value map(unary_mapper_t umap) const
Definition ov-cell.cc:1419
std::size_t byte_size() const
Definition ov-cell.cc:433
sortmode is_sorted_rows(sortmode mode=UNSORTED) const
Definition ov-cell.cc:511
void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition ov-cell.cc:618
bool print_as_scalar() const
Definition ov-cell.cc:612
octave_value sort(octave_idx_type dim=0, sortmode mode=ASCENDING) const
Definition ov-cell.cc:444
const void * mex_get_data() const
Definition ov-cell.cc:965
Array< std::string > cellstr_value() const
Definition ov-cell.cc:600
bool save_binary(std::ostream &os, bool save_as_floats)
Definition ov-cell.cc:864
bool print_name_tag(std::ostream &os, const std::string &name) const
Definition ov-cell.cc:681
bool save_ascii(std::ostream &os)
Definition ov-cell.cc:711
std::string type_name() const
Definition ov-cell.h:194
Cell cell_value() const
Definition ov-cell.h:138
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition ov-cell.cc:1078
octave_value_list simple_subsref(char type, octave_value_list &idx, int nargout)
Definition ov-cell.cc:74
void break_closure_cycles(const std::shared_ptr< octave::stack_frame > &frame)
Definition ov-cell.cc:67
void delete_elements(const octave_value_list &idx)
Definition ov-cell.cc:426
bool load_ascii(std::istream &is)
Definition ov-cell.cc:765
string_vector string_vector_value(bool pad=false) const
Definition ov-cell.cc:538
Array< octave_idx_type > sort_rows_idx(sortmode mode=ASCENDING) const
Definition ov-cell.cc:496
void assign(const octave_value_list &idx, const Cell &rhs)
Definition ov-cell.cc:412
bool iscellstr() const
Definition ov-cell.cc:395
sortmode issorted(sortmode mode=UNSORTED) const
Definition ov-cell.cc:481
mxArray * as_mxArray(bool interleaved) const
Definition ov-cell.cc:1402
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition ov-cell.h:75
octave_value_list list_value() const
Definition ov-cell.cc:532
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
Definition ov-cell.cc:624
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition ov-cell.cc:972
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition ov-cell.cc:897
octave_cell()
Definition ov-cell.h:55
octave_idx_type nfields() const
Definition oct-map.h:323
dim_vector dims() const
Definition oct-map.h:409
const Cell & contents(const_iterator p) const
Definition oct-map.h:310
octave_idx_type numel() const
Definition oct-map.h:368
bool all_scalars() const
Definition ovl.cc:188
bool empty() const
Definition ovl.h:113
octave_idx_type length() const
Definition ovl.h:111
octave_value_list list_value() const
Cell cell_value() const
void print_with_name(std::ostream &os, const std::string &name) const
Definition ov.h:1345
void make_unique()
Definition ov.h:352
static octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
bool is_defined() const
Definition ov.h:592
octave_value storable_value() const
bool is_zero_by_zero() const
Definition ov.h:556
bool iscell() const
Definition ov.h:604
bool isnull() const
Definition ov.h:679
octave_idx_type length() const
bool is_cs_list() const
Definition ov.h:670
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
octave_idx_type max_length() const
Definition str-vec.h:77
bool isempty() const
Definition str-vec.h:100
octave_idx_type numel() const
Definition str-vec.h:98
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
void error(const char *fmt,...)
Definition error.cc:1003
void err_indexed_cs_list()
Definition errwarn.cc:65
void err_nonbraced_cs_list_assignment()
Definition errwarn.cc:89
int save_hdf5_empty(octave_hdf5_id loc_id, const char *name, const dim_vector &d)
Definition ls-hdf5.cc:1254
int load_hdf5_empty(octave_hdf5_id loc_id, const char *name, dim_vector &d)
Definition ls-hdf5.cc:1311
octave_hdf5_err hdf5_h5g_iterate(octave_hdf5_id loc_id, const char *name, int *idx, void *operator_data)
Definition ls-hdf5.cc:1064
bool add_hdf5_data(octave_hdf5_id loc_id, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
Definition ls-hdf5.cc:1411
std::string read_binary_data(std::istream &is, bool swap, octave::mach_info::float_format fmt, const std::string &filename, bool &global, octave_value &tc, std::string &doc)
bool save_binary_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
std::string read_text_data(std::istream &is, const std::string &filename, bool &global, octave_value &tc, octave_idx_type count, const bool do_name_validation)
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
bool save_text_data(std::ostream &os, const octave_value &val_arg, const std::string &name, bool mark_global, int precision)
#define CELL_ELT_TAG
Definition ls-oct-text.h:42
bool is_true(const std::string &s)
int64_t octave_hdf5_id
#define H5T_NATIVE_IDX
Definition oct-hdf5.h:42
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
sortmode
Definition oct-sort.h:97
@ UNSORTED
Definition oct-sort.h:97
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition ov-base.h:246
octave_value_list Fiscellstr(const octave_value_list &args, int)
Definition ov-cell.cc:1278
#define FORWARD_MAPPER(UMAP)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
bool Vprint_empty_dimensions
Definition pr-output.cc:71
octave_value tc
Definition ls-hdf5.h:121
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition utils.cc:1377
void check_dimensions(dim_vector &dim, const char *warnfor)
Definition utils.cc:1358