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
oct-map.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1995-2013 John W. Eaton
4 Copyright (C) 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 "error.h"
29 #include "str-vec.h"
30 
31 #include "oct-map.h"
32 #include "utils.h"
33 
35  : rep (new fields_rep)
36 {
37  octave_idx_type n = fields.numel ();
38  for (octave_idx_type i = 0; i < n; i++)
39  (*rep)[fields(i)] = i;
40 }
41 
42 octave_fields::octave_fields (const char * const *fields)
43  : rep (new fields_rep)
44 {
45  octave_idx_type n = 0;
46  while (*fields)
47  (*rep)[std::string (*fields++)] = n++;
48 }
49 
50 bool
51 octave_fields::isfield (const std::string& field) const
52 {
53  return rep->find (field) != rep->end ();
54 }
55 
57 octave_fields::getfield (const std::string& field) const
58 {
59  fields_rep::iterator p = rep->find (field);
60  return (p != rep->end ()) ? p->second : -1;
61 }
62 
64 octave_fields::getfield (const std::string& field)
65 {
66  fields_rep::iterator p = rep->find (field);
67  if (p != rep->end ())
68  return p->second;
69  else
70  {
71  make_unique ();
72  octave_idx_type n = rep->size ();
73  return (*rep)[field] = n;
74  }
75 }
76 
78 octave_fields::rmfield (const std::string& field)
79 {
80  fields_rep::iterator p = rep->find (field);
81  if (p == rep->end ())
82  return -1;
83  else
84  {
85  octave_idx_type n = p->second;
86  make_unique ();
87  rep->erase (field);
88  for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
89  {
90  if (q->second >= n)
91  q->second--;
92  }
93 
94  return n;
95  }
96 }
97 
98 void
100 {
101  octave_idx_type n = rep->size ();
102  perm.clear (n, 1);
103 
104  make_unique ();
105  octave_idx_type i = 0;
106  for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
107  {
108  octave_idx_type j = q->second;
109  q->second = i;
110  perm(i++) = j;
111  }
112 }
113 
114 bool
116  octave_idx_type* perm) const
117 {
118  bool retval = true;
119 
120  iterator p = begin (), q = other.begin ();
121  for (; p != end () && q != other.end (); p++, q++)
122  {
123  if (p->first == q->first)
124  perm[p->second] = q->second;
125  else
126  {
127  retval = false;
128  break;
129  }
130  }
131 
132  retval = (p == end () && q == other.end ());
133 
134  return retval;
135 }
136 
137 bool
139  Array<octave_idx_type>& perm) const
140 {
141  octave_idx_type n = nfields ();
142  if (perm.length () != n)
143  perm.clear (1, n);
144 
145  return equal_up_to_order (other, perm.fortran_vec ());
146 }
147 
150 {
151  octave_idx_type n = nfields ();
152  string_vector retval(n);
153 
154  for (iterator p = begin (); p != end (); p++)
155  retval.xelem (p->second) = p->first;
156 
157  return retval;
158 }
159 
161 octave_scalar_map::getfield (const std::string& k) const
162 {
163  octave_idx_type idx = xkeys.getfield (k);
164  return (idx >= 0) ? xvals[idx] : octave_value ();
165 }
166 
167 void
168 octave_scalar_map::setfield (const std::string& k, const octave_value& val)
169 {
170  octave_idx_type idx = xkeys.getfield (k);
171  if (idx < static_cast<octave_idx_type> (xvals.size ()))
172  xvals[idx] = val;
173  else
174  xvals.push_back (val);
175 }
176 
177 void
178 octave_scalar_map::rmfield (const std::string& k)
179 {
180  octave_idx_type idx = xkeys.rmfield (k);
181  if (idx >= 0)
182  xvals.erase (xvals.begin () + idx);
183 }
184 
187 {
189  return orderfields (perm);
190 }
191 
194 {
195  octave_scalar_map retval (xkeys);
196  retval.xkeys.orderfields (perm);
197 
198  octave_idx_type nf = nfields ();
199  for (octave_idx_type i = 0; i < nf; i++)
200  retval.xvals[i] = xvals[perm.xelem (i)];
201 
202  return retval;
203 }
204 
207  Array<octave_idx_type>& perm) const
208 {
209  if (xkeys.is_same (other.xkeys))
210  return *this;
211  else
212  {
213  octave_scalar_map retval (other.xkeys);
214  if (other.xkeys.equal_up_to_order (xkeys, perm))
215  {
216  octave_idx_type nf = nfields ();
217  for (octave_idx_type i = 0; i < nf; i++)
218  retval.xvals[i] = xvals[perm.xelem (i)];
219  }
220  else
221  error ("orderfields: structs must have same fields up to order");
222 
223  return retval;
224  }
225 }
226 
228 octave_scalar_map::contents (const std::string& k) const
229 {
230  return getfield (k);
231 }
232 
234 octave_scalar_map::contents (const std::string& k)
235 {
236  octave_idx_type idx = xkeys.getfield (k);
237  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
238  xvals.resize (idx+1);
239  return xvals[idx];
240 }
241 
243  : xkeys (m.xkeys), xvals (), dimensions (1, 1)
244 {
245  octave_idx_type nf = m.nfields ();
246  xvals.reserve (nf);
247  for (octave_idx_type i = 0; i < nf; i++)
248  {
249  xvals.push_back (Cell (dimensions));
250  xvals[i].xelem (0) = m.xvals[i];
251  }
252 }
253 
255  : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ())
256 {
257  for (iterator p = begin (); p != end (); p++)
258  contents(p) = m.contents (key (p));
259 
261 }
262 
263 Cell
264 octave_map::getfield (const std::string& k) const
265 {
266  octave_idx_type idx = xkeys.getfield (k);
267  return (idx >= 0) ? xvals[idx] : Cell ();
268 }
269 
270 void
271 octave_map::setfield (const std::string& k, const Cell& val)
272 {
273  if (nfields () == 0)
274  dimensions = val.dims ();
275 
276  if (val.dims () == dimensions)
277  {
278  octave_idx_type idx = xkeys.getfield (k);
279  if (idx < static_cast<octave_idx_type> (xvals.size ()))
280  xvals[idx] = val;
281  else
282  xvals.push_back (val);
283  }
284  else
285  error ("octave_map::setfield: internal error");
286 }
287 
288 void
289 octave_map::rmfield (const std::string& k)
290 {
291  octave_idx_type idx = xkeys.rmfield (k);
292  if (idx >= 0)
293  xvals.erase (xvals.begin () + idx);
294 }
295 
298 {
300  return orderfields (perm);
301 }
302 
305 {
306  octave_map retval (xkeys);
307  retval.xkeys.orderfields (perm);
308 
309  octave_idx_type nf = nfields ();
310  for (octave_idx_type i = 0; i < nf; i++)
311  retval.xvals[i] = xvals[perm.xelem (i)];
312 
313  return retval;
314 }
315 
318  Array<octave_idx_type>& perm) const
319 {
320  if (xkeys.is_same (other.xkeys))
321  return *this;
322  else
323  {
324  octave_map retval (other.xkeys);
325  if (other.xkeys.equal_up_to_order (xkeys, perm))
326  {
327  octave_idx_type nf = nfields ();
328  for (octave_idx_type i = 0; i < nf; i++)
329  retval.xvals[i] = xvals[perm.xelem (i)];
330  }
331  else
332  error ("orderfields: structs must have same fields up to order");
333 
334  return retval;
335  }
336 }
337 
338 Cell
339 octave_map::contents (const std::string& k) const
340 {
341  return getfield (k);
342 }
343 
344 Cell&
345 octave_map::contents (const std::string& k)
346 {
347  octave_idx_type idx = xkeys.getfield (k);
348  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
349  xvals.push_back (Cell (dimensions)); // auto-set correct dims.
350  return xvals[idx];
351 }
352 
353 void
355  octave_idx_type idx) const
356 {
357  octave_idx_type nf = nfields ();
358  for (octave_idx_type i = 0; i < nf; i++)
359  dest.xvals[i] = xvals[i](idx);
360 }
361 
364 {
365  octave_scalar_map retval (xkeys);
366 
367  // Optimize this so that there is just one check.
368  extract_scalar (retval, compute_index (n, dimensions));
369 
370  return retval;
371 }
372 
375 {
376  octave_scalar_map retval (xkeys);
377 
378  // Optimize this so that there is just one check.
379  extract_scalar (retval, compute_index (i, j, dimensions));
380 
381  return retval;
382 }
383 
386 {
387  octave_scalar_map retval (xkeys);
388 
389  // Optimize this so that there is just one check.
390  extract_scalar (retval, compute_index (ra_idx, dimensions));
391 
392  return retval;
393 }
394 
397 {
398  octave_scalar_map retval (xkeys);
399 
400  extract_scalar (retval, n);
401 
402  return retval;
403 }
404 
405 bool
407  const octave_scalar_map& rhs)
408 {
409  bool retval = false;
410 
411  octave_idx_type nf = nfields ();
412  if (rhs.xkeys.is_same (xkeys))
413  {
414  for (octave_idx_type i = 0; i < nf; i++)
415  xvals[i](n) = rhs.xvals[i];
416 
417  retval = true;
418  }
419  else
420  {
422  if (xkeys.equal_up_to_order (rhs.xkeys, perm))
423  {
424  for (octave_idx_type i = 0; i < nf; i++)
425  xvals[i](n) = rhs.xvals[perm[i]];
426 
427  retval = true;
428  }
429  }
430 
431  return retval;
432 }
433 
436 {
437  octave_map retval (*this);
438  octave_idx_type nf = nfields ();
439 
440  retval.dimensions = dimensions.squeeze ();
441 
442  for (octave_idx_type i = 0; i < nf; i++)
443  retval.xvals[i] = xvals[i].squeeze ();
444 
445  retval.optimize_dimensions ();
446 
447  return retval;
448 }
449 
450 /*
451 ## test preservation of xkeys by squeeze
452 %!test
453 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
454 %! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
455 */
456 
458 octave_map::permute (const Array<int>& vec, bool inv) const
459 {
460  octave_map retval (xkeys);
461  octave_idx_type nf = nfields ();
462 
463  for (octave_idx_type i = 0; i < nf; i++)
464  retval.xvals[i] = xvals[i].permute (vec, inv);
465 
466  // FIXME:
467  // There is no dim_vector::permute for technical reasons.
468  // We pick the dim vector from results if possible, otherwise use a dummy
469  // array to get it. Need (?) a better solution to this problem.
470  if (nf > 0)
471  retval.dimensions = retval.xvals[0].dims ();
472  else
473  {
474  Array<char> dummy (dimensions);
475  dummy = dummy.permute (vec, inv);
476  retval.dimensions = dummy.dims ();
477  }
478 
479  retval.optimize_dimensions ();
480 
481  return retval;
482 }
483 
484 /*
485 ## test preservation of key order by permute
486 %!test
487 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
488 %! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
489 */
490 
493 {
494  assert (ndims () == 2);
495 
496  octave_map retval (xkeys);
497 
498  retval.dimensions = dim_vector (dimensions (1), dimensions (0));
499 
500  octave_idx_type nf = nfields ();
501  for (octave_idx_type i = 0; i < nf; i++)
502  retval.xvals[i] = xvals[i].transpose ();
503 
504  retval.optimize_dimensions ();
505 
506  return retval;
507 }
508 
509 /*
510 ## test preservation of key order by transpose
511 %!test
512 %! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
513 %! assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
514 %! assert (fieldnames (x'), {"d"; "a"; "f"});
515 %! assert (fieldnames (x.'), {"d"; "a"; "f"});
516 */
517 
520 {
521  octave_map retval (xkeys);
522  retval.dimensions = dv;
523 
524  octave_idx_type nf = nfields ();
525  if (nf > 0)
526  {
527  retval.xvals.reserve (nf);
528  for (octave_idx_type i = 0; i < nf; i++)
529  retval.xvals[i] = xvals[i].reshape (dv);
530  }
531  else
532  {
533  // FIXME: Do it with a dummy array, to reuse error message.
534  // Need (?) a better solution.
535  Array<char> dummy (dimensions);
536  dummy.reshape (dv);
537  }
538 
539  retval.optimize_dimensions ();
540 
541  return retval;
542 }
543 
544 /*
545 ## test preservation of key order by reshape
546 %!test
547 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
548 %! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
549 */
550 
551 void
552 octave_map::resize (const dim_vector& dv, bool fill)
553 {
554  octave_idx_type nf = nfields ();
555  if (nf > 0)
556  {
557  for (octave_idx_type i = 0; i < nf; i++)
558  {
559  if (fill)
560  xvals[i].resize (dv, Matrix ());
561  else
562  xvals[i].resize (dv);
563  }
564  }
565  else
566  {
567  // FIXME: Do it with a dummy array, to reuse error message.
568  // Need (?) a better solution.
569  Array<char> dummy (dimensions);
570  dummy.resize (dv);
571  }
572 
573  dimensions = dv;
575 }
576 
577 void
579  const octave_scalar_map *map_list,
580  octave_map& retval)
581 {
582  octave_idx_type nf = retval.nfields ();
583  retval.xvals.reserve (nf);
584 
585  dim_vector& rd = retval.dimensions;
586  rd.resize (dim+1, 1);
587  rd(0) = rd(1) = 1;
588  rd(dim) = n;
589 
590  for (octave_idx_type j = 0; j < nf; j++)
591  {
592  retval.xvals.push_back (Cell (rd));
593  assert (retval.xvals[j].numel () == n);
594  for (octave_idx_type i = 0; i < n; i++)
595  retval.xvals[j].xelem (i) = map_list[i].xvals[j];
596  }
597 }
598 
599 void
600 octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
601  octave_map& retval)
602 {
603  octave_idx_type nf = retval.nfields ();
604  retval.xvals.reserve (nf);
605 
606  OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n);
607 
608  for (octave_idx_type j = 0; j < nf; j++)
609  {
610  for (octave_idx_type i = 0; i < n; i++)
611  field_list[i] = map_list[i].xvals[j];
612 
613  retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list));
614  if (j == 0)
615  retval.dimensions = retval.xvals[j].dims ();
616  }
617 }
618 
619 // This is just a wrapper.
621  const octave_scalar_map& src,
622  octave_scalar_map& dest,
624 {
625  dest = src.orderfields (ref, perm);
626 }
627 
628 // In non-scalar case, we also promote empty structs without fields.
629 void permute_to_correct_order1 (const octave_map& ref, const octave_map& src,
630  octave_map& dest, Array<octave_idx_type>& perm)
631 {
632  if (src.nfields () == 0 && src.is_empty ())
633  dest = octave_map (src.dims (), ref.keys ());
634  else
635  dest = src.orderfields (ref, perm);
636 }
637 
638 template <class map>
639 static void
641  octave_idx_type idx, const map *map_list,
642  map *new_map_list)
643 {
644  new_map_list[idx] = map_list[idx];
645 
646  Array<octave_idx_type> perm (dim_vector (1, nf));
647 
648  for (octave_idx_type i = 0; i < n; i++)
649  {
650  if (i == idx)
651  continue;
652 
653  permute_to_correct_order1 (map_list[idx], map_list[i], new_map_list[i],
654  perm);
655 
656  if (error_state)
657  {
658  // Use liboctave exception to be consistent.
659  (*current_liboctave_error_handler)
660  ("cat: field names mismatch in concatenating structs");
661  break;
662  }
663  }
664 }
665 
666 
668 octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list)
669 {
670  octave_map retval;
671 
672  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
673  if (dim == -1 || dim == -2)
674  dim = -dim - 1;
675  else if (dim < 0)
676  (*current_liboctave_error_handler)
677  ("cat: invalid dimension");
678 
679  if (n == 1)
680  retval = map_list[0];
681  else if (n > 1)
682  {
683  octave_idx_type idx, nf = 0;
684  for (idx = 0; idx < n; idx++)
685  {
686  nf = map_list[idx].nfields ();
687  if (nf > 0)
688  {
689  retval.xkeys = map_list[idx].xkeys;
690  break;
691  }
692  }
693 
694  if (nf > 0)
695  {
696  // Try the fast case.
697  bool all_same = true;
698  for (octave_idx_type i = 0; i < n; i++)
699  {
700  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
701  if (! all_same)
702  break;
703  }
704 
705  if (all_same)
706  do_cat (dim, n, map_list, retval);
707  else
708  {
709  // permute all structures to common order.
710  OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
711 
712  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
713 
714  do_cat (dim, n, new_map_list, retval);
715  }
716 
717  }
718  else
719  {
720  dim_vector& rd = retval.dimensions;
721  rd.resize (dim+1, 1);
722  rd(0) = rd(1) = 1;
723  rd(dim) = n;
724  }
725 
726  retval.optimize_dimensions ();
727  }
728 
729  return retval;
730 }
731 
733 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
734 {
735  octave_map retval;
736 
737  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
738  if (dim == -1 || dim == -2)
739  dim = -dim - 1;
740  else if (dim < 0)
741  (*current_liboctave_error_handler)
742  ("cat: invalid dimension");
743 
744  if (n == 1)
745  retval = map_list[0];
746  else if (n > 1)
747  {
748  octave_idx_type idx, nf = 0;
749 
750  for (idx = 0; idx < n; idx++)
751  {
752  nf = map_list[idx].nfields ();
753  if (nf > 0)
754  {
755  retval.xkeys = map_list[idx].xkeys;
756  break;
757  }
758  }
759 
760  // Try the fast case.
761  bool all_same = true;
762 
763  if (nf > 0)
764  {
765  for (octave_idx_type i = 0; i < n; i++)
766  {
767  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
768 
769  if (! all_same)
770  break;
771  }
772  }
773 
774  if (all_same && nf > 0)
775  do_cat (dim, n, map_list, retval);
776  else
777  {
778  if (nf > 0)
779  {
780  // permute all structures to correct order.
781  OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
782 
783  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
784 
785  do_cat (dim, n, new_map_list, retval);
786  }
787  else
788  {
789  dim_vector dv = map_list[0].dimensions;
790 
791  for (octave_idx_type i = 1; i < n; i++)
792  {
793  if (! dv.concat (map_list[i].dimensions, dim))
794  {
795  error ("dimension mismatch in struct concatenation");
796  return retval;
797  }
798  }
799 
800  retval.dimensions = dv;
801  }
802  }
803 
804  retval.optimize_dimensions ();
805  }
806 
807  return retval;
808 }
809 
810 /*
811 ## test preservation of key order by concatenation
812 %!test
813 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
814 %! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
815 %! assert (fieldnames ([x; y]), {"d"; "a"; "f"});
816 
817 %!test
818 %! s = struct ();
819 %! sr = [s,s];
820 %! sc = [s;s];
821 %! sm = [s,s;s,s];
822 %! assert (nfields (sr), 0);
823 %! assert (nfields (sc), 0);
824 %! assert (nfields (sm), 0);
825 %! assert (size (sr), [1, 2]);
826 %! assert (size (sc), [2, 1]);
827 %! assert (size (sm), [2, 2]);
828 */
829 
831 octave_map::index (const idx_vector& i, bool resize_ok) const
832 {
833  octave_map retval (xkeys);
834  octave_idx_type nf = nfields ();
835 
836  for (octave_idx_type k = 0; k < nf; k++)
837  retval.xvals[k] = xvals[k].index (i, resize_ok);
838 
839  if (nf > 0)
840  retval.dimensions = retval.xvals[0].dims ();
841  else
842  {
843  // Use dummy array. FIXME: Need(?) a better solution.
844  Array<char> dummy (dimensions);
845  dummy = dummy.index (i, resize_ok);
846  retval.dimensions = dummy.dims ();
847  }
848 
849  retval.optimize_dimensions ();
850 
851  return retval;
852 }
853 
856  bool resize_ok) const
857 {
858  octave_map retval (xkeys);
859  octave_idx_type nf = nfields ();
860 
861  for (octave_idx_type k = 0; k < nf; k++)
862  retval.xvals[k] = xvals[k].index (i, j, resize_ok);
863 
864  if (nf > 0)
865  retval.dimensions = retval.xvals[0].dims ();
866  else
867  {
868  // Use dummy array. FIXME: Need(?) a better solution.
869  Array<char> dummy (dimensions);
870  dummy = dummy.index (i, j, resize_ok);
871  retval.dimensions = dummy.dims ();
872  }
873 
874  retval.optimize_dimensions ();
875 
876  return retval;
877 }
878 
880 octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
881 {
882  octave_map retval (xkeys);
883  octave_idx_type nf = nfields ();
884 
885  for (octave_idx_type k = 0; k < nf; k++)
886  retval.xvals[k] = xvals[k].index (ia, resize_ok);
887 
888  if (nf > 0)
889  retval.dimensions = retval.xvals[0].dims ();
890  else
891  {
892  // Use dummy array. FIXME: Need(?) a better solution.
893  Array<char> dummy (dimensions);
894  dummy = dummy.index (ia, resize_ok);
895  retval.dimensions = dummy.dims ();
896  }
897 
898  retval.optimize_dimensions ();
899 
900  return retval;
901 }
902 
904 octave_map::index (const octave_value_list& idx, bool resize_ok) const
905 {
906  octave_idx_type n_idx = idx.length ();
907  octave_map retval;
908 
909  switch (n_idx)
910  {
911  case 1:
912  {
913  idx_vector i = idx(0).index_vector ();
914 
915  if (! error_state)
916  retval = index (i, resize_ok);
917  }
918  break;
919 
920  case 2:
921  {
922  idx_vector i = idx(0).index_vector ();
923 
924  if (! error_state)
925  {
926  idx_vector j = idx(1).index_vector ();
927 
928  retval = index (i, j, resize_ok);
929  }
930  }
931  break;
932 
933  default:
934  {
935  Array<idx_vector> ia (dim_vector (n_idx, 1));
936 
937  for (octave_idx_type i = 0; i < n_idx; i++)
938  {
939  ia(i) = idx(i).index_vector ();
940 
941  if (error_state)
942  break;
943  }
944 
945  if (! error_state)
946  retval = index (ia, resize_ok);
947  }
948  break;
949  }
950 
951  return retval;
952 }
953 
954 // Perhaps one day these will be optimized. Right now, they just call index.
957 {
958  return index (idx_vector::colon, k);
959 }
960 
963 {
964  static Array<idx_vector> ia (dim_vector (3, 1), idx_vector::colon);
965 
966  ia(2) = k;
967  return index (ia);
968 }
969 
970 void
972 {
973  if (rhs.xkeys.is_same (xkeys))
974  {
975  octave_idx_type nf = nfields ();
976 
977  for (octave_idx_type k = 0; k < nf; k++)
978  xvals[k].assign (i, rhs.xvals[k], Matrix ());
979 
980  if (nf > 0)
981  dimensions = xvals[0].dims ();
982  else
983  {
984  // Use dummy array. FIXME: Need(?) a better solution.
985  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
986  dummy.assign (i, rhs_dummy);;
987  dimensions = dummy.dims ();
988  }
989 
991  }
992  else if (nfields () == 0)
993  {
994  octave_map tmp (dimensions, rhs.xkeys);
995  tmp.assign (i, rhs);
996  *this = tmp;
997  }
998  else
999  {
1001  octave_map rhs1 = rhs.orderfields (*this, perm);
1002  if (! error_state)
1003  {
1004  assert (rhs1.xkeys.is_same (xkeys));
1005  assign (i, rhs1);
1006  }
1007  else
1008  error ("incompatible fields in struct assignment");
1009  }
1010 }
1011 
1012 void
1014  const octave_map& rhs)
1015 {
1016  if (rhs.xkeys.is_same (xkeys))
1017  {
1018  octave_idx_type nf = nfields ();
1019 
1020  for (octave_idx_type k = 0; k < nf; k++)
1021  xvals[k].assign (i, j, rhs.xvals[k], Matrix ());
1022 
1023  if (nf > 0)
1024  dimensions = xvals[0].dims ();
1025  else
1026  {
1027  // Use dummy array. FIXME: Need(?) a better solution.
1028  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1029  dummy.assign (i, j, rhs_dummy);;
1030  dimensions = dummy.dims ();
1031  }
1032 
1034  }
1035  else if (nfields () == 0)
1036  {
1037  octave_map tmp (dimensions, rhs.xkeys);
1038  tmp.assign (i, j, rhs);
1039  *this = tmp;
1040  }
1041  else
1042  {
1044  octave_map rhs1 = rhs.orderfields (*this, perm);
1045  if (! error_state)
1046  {
1047  assert (rhs1.xkeys.is_same (xkeys));
1048  assign (i, j, rhs1);
1049  }
1050  else
1051  error ("incompatible fields in struct assignment");
1052  }
1053 }
1054 
1055 void
1057  const octave_map& rhs)
1058 {
1059  if (rhs.xkeys.is_same (xkeys))
1060  {
1061  octave_idx_type nf = nfields ();
1062 
1063  for (octave_idx_type k = 0; k < nf; k++)
1064  xvals[k].assign (ia, rhs.xvals[k], Matrix ());
1065 
1066  if (nf > 0)
1067  dimensions = xvals[0].dims ();
1068  else
1069  {
1070  // Use dummy array. FIXME: Need(?) a better solution.
1071  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1072  dummy.assign (ia, rhs_dummy);;
1073  dimensions = dummy.dims ();
1074  }
1075 
1077  }
1078  else if (nfields () == 0)
1079  {
1080  octave_map tmp (dimensions, rhs.xkeys);
1081  tmp.assign (ia, rhs);
1082  *this = tmp;
1083  }
1084  else
1085  {
1087  octave_map rhs1 = rhs.orderfields (*this, perm);
1088  if (! error_state)
1089  {
1090  assert (rhs1.xkeys.is_same (xkeys));
1091  assign (ia, rhs1);
1092  }
1093  else
1094  error ("incompatible fields in struct assignment");
1095  }
1096 }
1097 
1098 void
1100 {
1101  octave_idx_type n_idx = idx.length ();
1102 
1103  switch (n_idx)
1104  {
1105  case 1:
1106  {
1107  idx_vector i = idx(0).index_vector ();
1108 
1109  if (! error_state)
1110  assign (i, rhs);
1111  }
1112  break;
1113 
1114  case 2:
1115  {
1116  idx_vector i = idx(0).index_vector ();
1117 
1118  if (! error_state)
1119  {
1120  idx_vector j = idx(1).index_vector ();
1121 
1122  assign (i, j, rhs);
1123  }
1124  }
1125  break;
1126 
1127  default:
1128  {
1129  Array<idx_vector> ia (dim_vector (n_idx, 1));
1130 
1131  for (octave_idx_type i = 0; i < n_idx; i++)
1132  {
1133  ia(i) = idx(i).index_vector ();
1134 
1135  if (error_state)
1136  break;
1137  }
1138 
1139  if (! error_state)
1140  assign (ia, rhs);
1141  }
1142  break;
1143  }
1144 }
1145 
1146 void
1147 octave_map::assign (const octave_value_list& idx, const std::string& k,
1148  const Cell& rhs)
1149 {
1150  Cell tmp;
1151  iterator p = seek (k);
1152  Cell& ref = p != end () ? contents (p) : tmp;
1153 
1154  if (&ref == &tmp)
1155  ref = Cell (dimensions);
1156 
1157  ref.assign (idx, rhs);
1158 
1159  if (! error_state && ref.dims () != dimensions)
1160  {
1161  dimensions = ref.dims ();
1162 
1163  octave_idx_type nf = nfields ();
1164  for (octave_idx_type i = 0; i < nf; i++)
1165  {
1166  if (&xvals[i] != &ref)
1167  xvals[i].resize (dimensions, Matrix ());
1168  }
1169 
1171  }
1172 
1173  if (! error_state && &ref == &tmp)
1174  setfield (k, tmp);
1175 }
1176 
1177 /*
1178 %!test
1179 %! rhs.b = 1;
1180 %! a(3) = rhs;
1181 %! assert ({a.b}, {[], [], 1})
1182 */
1183 
1184 void
1186 {
1187  octave_idx_type nf = nfields ();
1188  for (octave_idx_type k = 0; k < nf; k++)
1189  xvals[k].delete_elements (i);
1190 
1191  if (nf > 0)
1192  dimensions = xvals[0].dims ();
1193  else
1194  {
1195  // Use dummy array. FIXME: Need(?) a better solution.
1196  Array<char> dummy (dimensions);
1197  dummy.delete_elements (i);
1198  dimensions = dummy.dims ();
1199  }
1200 
1202 }
1203 
1204 void
1206 {
1207  octave_idx_type nf = nfields ();
1208  for (octave_idx_type k = 0; k < nf; k++)
1209  xvals[k].delete_elements (dim, i);
1210 
1211  if (nf > 0)
1212  dimensions = xvals[0].dims ();
1213  else
1214  {
1215  // Use dummy array. FIXME: Need(?) a better solution.
1216  Array<char> dummy (dimensions);
1217  dummy.delete_elements (dim, i);
1218  dimensions = dummy.dims ();
1219  }
1220 
1222 }
1223 
1224 void
1226 {
1227  octave_idx_type nf = nfields ();
1228  for (octave_idx_type k = 0; k < nf; k++)
1229  xvals[k].delete_elements (ia);
1230 
1231  if (nf > 0)
1232  dimensions = xvals[0].dims ();
1233  else
1234  {
1235  // Use dummy array. FIXME: Need(?) a better solution.
1236  Array<char> dummy (dimensions);
1237  dummy.delete_elements (ia);
1238  dimensions = dummy.dims ();
1239  }
1240 
1242 }
1243 
1244 void
1246 {
1247  octave_idx_type n_idx = idx.length ();
1248 
1249  Array<idx_vector> ia (dim_vector (n_idx, 1));
1250 
1251  for (octave_idx_type i = 0; i < n_idx; i++)
1252  {
1253  ia(i) = idx(i).index_vector ();
1254 
1255  if (error_state)
1256  break;
1257  }
1258 
1259  if (! error_state)
1260  delete_elements (ia);
1261 }
1262 
1263 /*
1264 ## test preservation of key order by indexing
1265 %!test
1266 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
1267 %! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
1268 */
1269 
1270 octave_map
1272 {
1273  if (nfields () == rb.nfields ())
1274  {
1275  for (const_iterator pa = begin (); pa != end (); pa++)
1276  {
1277  const_iterator pb = rb.seek (key(pa));
1278 
1279  if (pb == rb.end ())
1280  {
1281  error ("field name mismatch in structure concatenation");
1282  break;
1283  }
1284 
1285  contents(pa).insert (rb.contents (pb), ra_idx);
1286  }
1287  }
1288  else
1289  {
1290  dim_vector dv = dims ();
1291 
1292  if (dv.all_zero ())
1293  *this = rb;
1294  else if (! rb.dims ().all_zero ())
1295  error ("invalid structure concatenation");
1296  }
1297 
1298  return *this;
1299 }
1300 
1301 void
1303 {
1304  octave_idx_type nf = nfields ();
1305 
1306  for (octave_idx_type i = 0; i < nf; i++)
1307  {
1309  {
1310  error ("internal error: dimension mismatch across fields in struct");
1311  break;
1312  }
1313  }
1314 
1315 }
1316 
1317 Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals)
1318  : map (), key_list (), dimensions (dv)
1319 {
1320  Cell c (dv);
1321 
1322  if (key_vals.is_cellstr ())
1323  {
1324  for (octave_idx_type i = 0; i < key_vals.numel (); i++)
1325  {
1326  std::string k = key_vals(i).string_value ();
1327  map[k] = c;
1328  key_list.push_back (k);
1329  }
1330  }
1331  else
1332  error ("Octave_map: expecting keys to be cellstr");
1333 }
1334 
1336  : map (), key_list (), dimensions (m.dims ())
1337 {
1338  for (octave_map::const_iterator p = m.begin (); p != m.end (); p++)
1339  map[m.key (p)] = m.contents (p);
1340  const string_vector mkeys = m.fieldnames ();
1341  for (octave_idx_type i = 0; i < mkeys.numel (); i++)
1342  key_list.push_back (mkeys(i));
1343 }
1344 
1345 Octave_map
1347 {
1348  Octave_map retval (dims ().squeeze ());
1349 
1350  for (const_iterator pa = begin (); pa != end (); pa++)
1351  {
1352  Cell tmp = contents (pa).squeeze ();
1353 
1354  if (error_state)
1355  break;
1356 
1357  retval.assign (key (pa), tmp);
1358  }
1359 
1360  // Preserve order of keys.
1361  retval.key_list = key_list;
1362 
1363  return retval;
1364 }
1365 
1366 Octave_map
1367 Octave_map::permute (const Array<int>& vec, bool inv) const
1368 {
1369  Octave_map retval (dims ());
1370 
1371  for (const_iterator pa = begin (); pa != end (); pa++)
1372  {
1373  Cell tmp = contents (pa).permute (vec, inv);
1374 
1375  if (error_state)
1376  break;
1377 
1378  retval.assign (key (pa), tmp);
1379  }
1380 
1381  // Preserve order of keys.
1382  retval.key_list = key_list;
1383 
1384  return retval;
1385 }
1386 
1387 Cell&
1388 Octave_map::contents (const std::string& k)
1389 {
1391 
1392  return map[k];
1393 }
1394 
1395 Cell
1396 Octave_map::contents (const std::string& k) const
1397 {
1398  const_iterator p = seek (k);
1399 
1400  return p != end () ? p->second : Cell ();
1401 }
1402 
1403 int
1404 Octave_map::intfield (const std::string& k, int def_val) const
1405 {
1406  int retval = def_val;
1407 
1408  Cell c = contents (k);
1409 
1410  if (! c.is_empty ())
1411  retval = c(0).int_value ();
1412 
1413  return retval;
1414 }
1415 
1416 std::string
1417 Octave_map::stringfield (const std::string& k,
1418  const std::string& def_val) const
1419 {
1420  std::string retval = def_val;
1421 
1422  Cell c = contents (k);
1423 
1424  if (! c.is_empty ())
1425  retval = c(0).string_value ();
1426 
1427  return retval;
1428 }
1429 
1431 Octave_map::keys (void) const
1432 {
1433  assert (static_cast<size_t>(nfields ()) == key_list.size ());
1434 
1435  return string_vector (key_list);
1436 }
1437 
1438 Octave_map
1440 {
1441  assert (ndims () == 2);
1442 
1443  dim_vector dv = dims ();
1444 
1445  octave_idx_type nr = dv(0);
1446  octave_idx_type nc = dv(1);
1447 
1448  dim_vector new_dims (nc, nr);
1449 
1450  Octave_map retval (new_dims);
1451 
1452  for (const_iterator p = begin (); p != end (); p++)
1453  retval.assign (key(p), Cell (contents(p).transpose ()));
1454 
1455  // Preserve order of keys.
1456  retval.key_list = key_list;
1457 
1458  return retval;
1459 }
1460 
1461 Octave_map
1462 Octave_map::reshape (const dim_vector& new_dims) const
1463 {
1464  Octave_map retval;
1465 
1466  if (new_dims != dims ())
1467  {
1468  for (const_iterator p = begin (); p != end (); p++)
1469  retval.assign (key(p), contents(p).reshape (new_dims));
1470 
1471  retval.dimensions = new_dims;
1472 
1473  // Preserve order of keys.
1474  retval.key_list = key_list;
1475  }
1476  else
1477  retval = *this;
1478 
1479  return retval;
1480 }
1481 
1482 void
1483 Octave_map::resize (const dim_vector& dv, bool fill)
1484 {
1485  if (dv != dims ())
1486  {
1487  if (nfields () == 0)
1488  dimensions = dv;
1489  else
1490  {
1491  for (const_iterator p = begin (); p != end (); p++)
1492  {
1493  Cell tmp = contents(p);
1494 
1495  if (fill)
1496  tmp.resize (dv, Matrix ());
1497  else
1498  tmp.resize (dv);
1499 
1500  dimensions = dv;
1501 
1502  assign (key(p), tmp);
1503  }
1504  }
1505  }
1506 }
1507 
1508 Octave_map
1510 {
1511  Octave_map retval;
1512 
1513  if (nfields () == rb.nfields ())
1514  {
1515  for (const_iterator pa = begin (); pa != end (); pa++)
1516  {
1517  const_iterator pb = rb.seek (key(pa));
1518 
1519  if (pb == rb.end ())
1520  {
1521  error ("field name mismatch in structure concatenation");
1522  break;
1523  }
1524 
1525  retval.assign (key(pa),
1526  contents(pa).insert (rb.contents(pb), ra_idx));
1527  }
1528 
1529  // Preserve order of keys.
1530  retval.key_list = key_list;
1531  }
1532  else
1533  {
1534  dim_vector dv = dims ();
1535 
1536  if (dv.all_zero ())
1537  retval = rb;
1538  else
1539  {
1540  dv = rb.dims ();
1541 
1542  if (dv.all_zero ())
1543  retval = *this;
1544  else
1545  error ("invalid structure concatenation");
1546  }
1547  }
1548 
1549  return retval;
1550 }
1551 
1552 static bool
1553 keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys)
1554 {
1555  bool retval = false;
1556 
1557  keys = string_vector ();
1558 
1559  if (a.nfields () == 0)
1560  {
1561  keys = b.keys ();
1562  retval = true;
1563  }
1564  else
1565  {
1566  string_vector a_keys = a.keys ().sort ();
1567  string_vector b_keys = b.keys ().sort ();
1568 
1569  octave_idx_type a_len = a_keys.length ();
1570  octave_idx_type b_len = b_keys.length ();
1571 
1572  if (a_len == b_len)
1573  {
1574  for (octave_idx_type i = 0; i < a_len; i++)
1575  {
1576  if (a_keys[i] != b_keys[i])
1577  goto done;
1578  }
1579 
1580  keys = a_keys;
1581  retval = true;
1582  }
1583  }
1584 
1585 done:
1586  return retval;
1587 }
1588 
1589 Octave_map&
1591 {
1592  string_vector t_keys = keys ();
1593  octave_idx_type len = t_keys.length ();
1594 
1595  if (len > 0)
1596  {
1597  for (octave_idx_type i = 0; i < len; i++)
1598  {
1599  std::string k = t_keys[i];
1600 
1601  contents(k).delete_elements (idx);
1602 
1603  if (error_state)
1604  break;
1605  }
1606 
1607  if (!error_state)
1608  dimensions = contents(t_keys[0]).dims ();
1609  }
1610 
1611  return *this;
1612 }
1613 
1614 Octave_map&
1616 {
1617  string_vector t_keys;
1618 
1619  if (keys_ok (*this, rhs, t_keys))
1620  {
1621  octave_idx_type len = t_keys.length ();
1622 
1623  if (len == 0)
1624  {
1625  Cell tmp_lhs (dims ());
1626  Cell tmp_rhs (rhs.dims ());
1627 
1628  tmp_lhs.assign (idx, tmp_rhs, Matrix ());
1629 
1630  if (! error_state)
1631  resize (tmp_lhs.dims ());
1632  else
1633  error ("size mismatch in structure assignment");
1634  }
1635  else
1636  {
1637  for (octave_idx_type i = 0; i < len; i++)
1638  {
1639  std::string k = t_keys[i];
1640 
1641  Cell t_rhs = rhs.contents (k);
1642 
1643  assign (idx, k, t_rhs);
1644 
1645  if (error_state)
1646  break;
1647  }
1648  }
1649  }
1650  else
1651  error ("field name mismatch in structure assignment");
1652 
1653  return *this;
1654 }
1655 
1656 Octave_map&
1657 Octave_map::assign (const octave_value_list& idx, const std::string& k,
1658  const Cell& rhs)
1659 {
1660  Cell tmp;
1661 
1662  if (contains (k))
1663  tmp = map[k];
1664  else
1665  tmp = Cell (dimensions);
1666 
1667  tmp.assign (idx, rhs);
1668 
1669  if (! error_state)
1670  {
1671  dim_vector tmp_dims = tmp.dims ();
1672 
1673  if (tmp_dims != dimensions)
1674  {
1675  for (iterator p = begin (); p != end (); p++)
1676  contents(p).resize (tmp_dims, Matrix ());
1677 
1678  dimensions = tmp_dims;
1679  }
1680 
1682 
1683  map[k] = tmp;
1684  }
1685 
1686  return *this;
1687 }
1688 
1689 Octave_map&
1690 Octave_map::assign (const std::string& k, const octave_value& rhs)
1691 {
1692  if (nfields () == 0)
1693  {
1695 
1696  map[k] = Cell (rhs);
1697 
1698  dimensions = dim_vector (1, 1);
1699  }
1700  else
1701  {
1702  dim_vector dv = dims ();
1703 
1704  if (dv.all_ones ())
1705  {
1707 
1708  map[k] = Cell (rhs);
1709  }
1710  else
1711  error ("invalid structure assignment");
1712  }
1713 
1714  return *this;
1715 }
1716 
1717 Octave_map&
1718 Octave_map::assign (const std::string& k, const Cell& rhs)
1719 {
1720  if (nfields () == 0)
1721  {
1723 
1724  map[k] = rhs;
1725 
1726  dimensions = rhs.dims ();
1727  }
1728  else
1729  {
1730  if (dims () == rhs.dims ())
1731  {
1733 
1734  map[k] = rhs;
1735  }
1736  else
1737  error ("invalid structure assignment");
1738  }
1739 
1740  return *this;
1741 }
1742 
1743 Octave_map
1744 Octave_map::index (const octave_value_list& idx, bool resize_ok) const
1745 {
1746  Octave_map retval;
1747 
1748  octave_idx_type n_idx = idx.length ();
1749 
1750  if (n_idx > 0)
1751  {
1752  Array<idx_vector> ra_idx (dim_vector (n_idx, 1));
1753 
1754  for (octave_idx_type i = 0; i < n_idx; i++)
1755  {
1756  ra_idx(i) = idx(i).index_vector ();
1757  if (error_state)
1758  break;
1759  }
1760 
1761  if (! error_state)
1762  {
1763  for (const_iterator p = begin (); p != end (); p++)
1764  {
1765  Cell tmp = contents (p);
1766 
1767  tmp = tmp.Array<octave_value>::index (ra_idx, resize_ok);
1768 
1769  if (error_state)
1770  break;
1771 
1772  retval.assign (key(p), tmp);
1773  }
1774 
1775  // Preserve order of keys.
1776  retval.key_list = key_list;
1777  }
1778  }
1779  else
1780  retval = *this;
1781 
1782  return retval;
1783 }