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