comparison libinterp/octave-value/ov-cell.cc @ 15195:2fc554ffbc28

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