GNU Octave  4.0.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-2015 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 "Array-util.h"
29 #include "error.h"
30 #include "oct-locbuf.h"
31 #include "str-vec.h"
32 
33 #include "oct-map.h"
34 #include "utils.h"
35 
37  : rep (new fields_rep)
38 {
39  octave_idx_type n = fields.numel ();
40  for (octave_idx_type i = 0; i < n; i++)
41  (*rep)[fields(i)] = i;
42 }
43 
44 octave_fields::octave_fields (const char * const *fields)
45  : rep (new fields_rep)
46 {
47  octave_idx_type n = 0;
48  while (*fields)
49  (*rep)[std::string (*fields++)] = n++;
50 }
51 
52 bool
53 octave_fields::isfield (const std::string& field) const
54 {
55  return rep->find (field) != rep->end ();
56 }
57 
59 octave_fields::getfield (const std::string& field) const
60 {
61  fields_rep::iterator p = rep->find (field);
62  return (p != rep->end ()) ? p->second : -1;
63 }
64 
66 octave_fields::getfield (const std::string& field)
67 {
68  fields_rep::iterator p = rep->find (field);
69  if (p != rep->end ())
70  return p->second;
71  else
72  {
73  make_unique ();
74  octave_idx_type n = rep->size ();
75  return (*rep)[field] = n;
76  }
77 }
78 
80 octave_fields::rmfield (const std::string& field)
81 {
82  fields_rep::iterator p = rep->find (field);
83  if (p == rep->end ())
84  return -1;
85  else
86  {
87  octave_idx_type n = p->second;
88  make_unique ();
89  rep->erase (field);
90  for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
91  {
92  if (q->second >= n)
93  q->second--;
94  }
95 
96  return n;
97  }
98 }
99 
100 void
102 {
103  octave_idx_type n = rep->size ();
104  perm.clear (n, 1);
105 
106  make_unique ();
107  octave_idx_type i = 0;
108  for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++)
109  {
110  octave_idx_type j = q->second;
111  q->second = i;
112  perm(i++) = j;
113  }
114 }
115 
116 bool
118  octave_idx_type* perm) const
119 {
120  bool retval = true;
121 
122  iterator p = begin ();
123  iterator q = other.begin ();
124  for (; p != end () && q != other.end (); p++, q++)
125  {
126  if (p->first == q->first)
127  perm[p->second] = q->second;
128  else
129  {
130  retval = false;
131  break;
132  }
133  }
134 
135  retval = (p == end () && q == other.end ());
136 
137  return retval;
138 }
139 
140 bool
142  Array<octave_idx_type>& perm) const
143 {
144  octave_idx_type n = nfields ();
145  if (perm.length () != n)
146  perm.clear (1, n);
147 
148  return equal_up_to_order (other, perm.fortran_vec ());
149 }
150 
153 {
154  octave_idx_type n = nfields ();
155  string_vector retval(n);
156 
157  for (iterator p = begin (); p != end (); p++)
158  retval.xelem (p->second) = p->first;
159 
160  return retval;
161 }
162 
164 octave_scalar_map::getfield (const std::string& k) const
165 {
166  octave_idx_type idx = xkeys.getfield (k);
167  return (idx >= 0) ? xvals[idx] : octave_value ();
168 }
169 
170 void
171 octave_scalar_map::setfield (const std::string& k, const octave_value& val)
172 {
173  octave_idx_type idx = xkeys.getfield (k);
174  if (idx < static_cast<octave_idx_type> (xvals.size ()))
175  xvals[idx] = val;
176  else
177  xvals.push_back (val);
178 }
179 
180 void
181 octave_scalar_map::rmfield (const std::string& k)
182 {
183  octave_idx_type idx = xkeys.rmfield (k);
184  if (idx >= 0)
185  xvals.erase (xvals.begin () + idx);
186 }
187 
190 {
192  return orderfields (perm);
193 }
194 
197 {
198  octave_scalar_map retval (xkeys);
199  retval.xkeys.orderfields (perm);
200 
201  octave_idx_type nf = nfields ();
202  for (octave_idx_type i = 0; i < nf; i++)
203  retval.xvals[i] = xvals[perm.xelem (i)];
204 
205  return retval;
206 }
207 
210  Array<octave_idx_type>& perm) const
211 {
212  if (xkeys.is_same (other.xkeys))
213  return *this;
214  else
215  {
216  octave_scalar_map retval (other.xkeys);
217  if (other.xkeys.equal_up_to_order (xkeys, perm))
218  {
219  octave_idx_type nf = nfields ();
220  for (octave_idx_type i = 0; i < nf; i++)
221  retval.xvals[i] = xvals[perm.xelem (i)];
222  }
223  else
224  error ("orderfields: structs must have same fields up to order");
225 
226  return retval;
227  }
228 }
229 
231 octave_scalar_map::contents (const std::string& k) const
232 {
233  return getfield (k);
234 }
235 
237 octave_scalar_map::contents (const std::string& k)
238 {
239  octave_idx_type idx = xkeys.getfield (k);
240  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
241  xvals.resize (idx+1);
242  return xvals[idx];
243 }
244 
246  : xkeys (m.xkeys), xvals (), dimensions (1, 1)
247 {
248  octave_idx_type nf = m.nfields ();
249  xvals.reserve (nf);
250  for (octave_idx_type i = 0; i < nf; i++)
251  {
252  xvals.push_back (Cell (dimensions));
253  xvals[i].xelem (0) = m.xvals[i];
254  }
255 }
256 
257 Cell
258 octave_map::getfield (const std::string& k) const
259 {
260  octave_idx_type idx = xkeys.getfield (k);
261  return (idx >= 0) ? xvals[idx] : Cell ();
262 }
263 
264 void
265 octave_map::setfield (const std::string& k, const Cell& val)
266 {
267  if (nfields () == 0)
268  dimensions = val.dims ();
269 
270  if (val.dims () == dimensions)
271  {
272  octave_idx_type idx = xkeys.getfield (k);
273  if (idx < static_cast<octave_idx_type> (xvals.size ()))
274  xvals[idx] = val;
275  else
276  xvals.push_back (val);
277  }
278  else
279  error ("octave_map::setfield: internal error");
280 }
281 
282 void
283 octave_map::rmfield (const std::string& k)
284 {
285  octave_idx_type idx = xkeys.rmfield (k);
286  if (idx >= 0)
287  xvals.erase (xvals.begin () + idx);
288 }
289 
292 {
294  return orderfields (perm);
295 }
296 
299 {
300  octave_map retval (xkeys);
301  retval.xkeys.orderfields (perm);
302 
303  octave_idx_type nf = nfields ();
304  for (octave_idx_type i = 0; i < nf; i++)
305  retval.xvals[i] = xvals[perm.xelem (i)];
306 
307  return retval;
308 }
309 
312  Array<octave_idx_type>& perm) const
313 {
314  if (xkeys.is_same (other.xkeys))
315  return *this;
316  else
317  {
318  octave_map retval (other.xkeys);
319  if (other.xkeys.equal_up_to_order (xkeys, perm))
320  {
321  octave_idx_type nf = nfields ();
322  for (octave_idx_type i = 0; i < nf; i++)
323  retval.xvals[i] = xvals[perm.xelem (i)];
324  }
325  else
326  error ("orderfields: structs must have same fields up to order");
327 
328  return retval;
329  }
330 }
331 
332 Cell
333 octave_map::contents (const std::string& k) const
334 {
335  return getfield (k);
336 }
337 
338 Cell&
339 octave_map::contents (const std::string& k)
340 {
341  octave_idx_type idx = xkeys.getfield (k);
342  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
343  xvals.push_back (Cell (dimensions)); // auto-set correct dims.
344  return xvals[idx];
345 }
346 
347 void
349  octave_idx_type idx) const
350 {
351  octave_idx_type nf = nfields ();
352  for (octave_idx_type i = 0; i < nf; i++)
353  dest.xvals[i] = xvals[i](idx);
354 }
355 
358 {
359  octave_scalar_map retval (xkeys);
360 
361  // Optimize this so that there is just one check.
362  extract_scalar (retval, compute_index (n, dimensions));
363 
364  return retval;
365 }
366 
369 {
370  octave_scalar_map retval (xkeys);
371 
372  // Optimize this so that there is just one check.
373  extract_scalar (retval, compute_index (i, j, dimensions));
374 
375  return retval;
376 }
377 
380 {
381  octave_scalar_map retval (xkeys);
382 
383  // Optimize this so that there is just one check.
384  extract_scalar (retval, compute_index (ra_idx, dimensions));
385 
386  return retval;
387 }
388 
391 {
392  octave_scalar_map retval (xkeys);
393 
394  extract_scalar (retval, n);
395 
396  return retval;
397 }
398 
399 bool
401  const octave_scalar_map& rhs)
402 {
403  bool retval = false;
404 
405  octave_idx_type nf = nfields ();
406  if (rhs.xkeys.is_same (xkeys))
407  {
408  for (octave_idx_type i = 0; i < nf; i++)
409  xvals[i](n) = rhs.xvals[i];
410 
411  retval = true;
412  }
413  else
414  {
416  if (xkeys.equal_up_to_order (rhs.xkeys, perm))
417  {
418  for (octave_idx_type i = 0; i < nf; i++)
419  xvals[i](n) = rhs.xvals[perm[i]];
420 
421  retval = true;
422  }
423  }
424 
425  return retval;
426 }
427 
430 {
431  octave_map retval (*this);
432  octave_idx_type nf = nfields ();
433 
434  retval.dimensions = dimensions.squeeze ();
435 
436  for (octave_idx_type i = 0; i < nf; i++)
437  retval.xvals[i] = xvals[i].squeeze ();
438 
439  retval.optimize_dimensions ();
440 
441  return retval;
442 }
443 
444 /*
445 ## test preservation of xkeys by squeeze
446 %!test
447 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
448 %! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
449 */
450 
452 octave_map::permute (const Array<int>& vec, bool inv) const
453 {
454  octave_map retval (xkeys);
455  octave_idx_type nf = nfields ();
456 
457  for (octave_idx_type i = 0; i < nf; i++)
458  retval.xvals[i] = xvals[i].permute (vec, inv);
459 
460  // FIXME:
461  // There is no dim_vector::permute for technical reasons.
462  // We pick the dim vector from results if possible, otherwise use a dummy
463  // array to get it. Need (?) a better solution to this problem.
464  if (nf > 0)
465  retval.dimensions = retval.xvals[0].dims ();
466  else
467  {
468  Array<char> dummy (dimensions);
469  dummy = dummy.permute (vec, inv);
470  retval.dimensions = dummy.dims ();
471  }
472 
473  retval.optimize_dimensions ();
474 
475  return retval;
476 }
477 
478 /*
479 ## test preservation of key order by permute
480 %!test
481 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
482 %! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
483 */
484 
487 {
488  assert (ndims () == 2);
489 
490  octave_map retval (xkeys);
491 
492  retval.dimensions = dim_vector (dimensions (1), dimensions (0));
493 
494  octave_idx_type nf = nfields ();
495  for (octave_idx_type i = 0; i < nf; i++)
496  retval.xvals[i] = xvals[i].transpose ();
497 
498  retval.optimize_dimensions ();
499 
500  return retval;
501 }
502 
503 /*
504 ## test preservation of key order by transpose
505 %!test
506 %! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
507 %! assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
508 %! assert (fieldnames (x'), {"d"; "a"; "f"});
509 %! assert (fieldnames (x.'), {"d"; "a"; "f"});
510 */
511 
514 {
515  octave_map retval (xkeys);
516  retval.dimensions = dv;
517 
518  octave_idx_type nf = nfields ();
519  if (nf > 0)
520  {
521  retval.xvals.reserve (nf);
522  for (octave_idx_type i = 0; i < nf; i++)
523  retval.xvals[i] = xvals[i].reshape (dv);
524  }
525  else
526  {
527  // FIXME: Do it with a dummy array, to reuse error message.
528  // Need (?) a better solution.
529  Array<char> dummy (dimensions);
530  dummy.reshape (dv);
531  }
532 
533  retval.optimize_dimensions ();
534 
535  return retval;
536 }
537 
538 /*
539 ## test preservation of key order by reshape
540 %!test
541 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
542 %! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
543 */
544 
545 void
546 octave_map::resize (const dim_vector& dv, bool fill)
547 {
548  octave_idx_type nf = nfields ();
549  if (nf > 0)
550  {
551  for (octave_idx_type i = 0; i < nf; i++)
552  {
553  if (fill)
554  xvals[i].resize (dv, Matrix ());
555  else
556  xvals[i].resize (dv);
557  }
558  }
559  else
560  {
561  // FIXME: Do it with a dummy array, to reuse error message.
562  // Need (?) a better solution.
563  Array<char> dummy (dimensions);
564  dummy.resize (dv);
565  }
566 
567  dimensions = dv;
569 }
570 
571 void
573  const octave_scalar_map *map_list,
574  octave_map& retval)
575 {
576  octave_idx_type nf = retval.nfields ();
577  retval.xvals.reserve (nf);
578 
579  dim_vector& rd = retval.dimensions;
580  rd.resize (dim+1, 1);
581  rd(0) = rd(1) = 1;
582  rd(dim) = n;
583 
584  for (octave_idx_type j = 0; j < nf; j++)
585  {
586  retval.xvals.push_back (Cell (rd));
587  assert (retval.xvals[j].numel () == n);
588  for (octave_idx_type i = 0; i < n; i++)
589  retval.xvals[j].xelem (i) = map_list[i].xvals[j];
590  }
591 }
592 
593 void
594 octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
595  octave_map& retval)
596 {
597  octave_idx_type nf = retval.nfields ();
598  retval.xvals.reserve (nf);
599 
600  OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n);
601 
602  for (octave_idx_type j = 0; j < nf; j++)
603  {
604  for (octave_idx_type i = 0; i < n; i++)
605  field_list[i] = map_list[i].xvals[j];
606 
607  retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list));
608  if (j == 0)
609  retval.dimensions = retval.xvals[j].dims ();
610  }
611 }
612 
613 // This is just a wrapper.
615  const octave_scalar_map& src,
616  octave_scalar_map& dest,
618 {
619  dest = src.orderfields (ref, perm);
620 }
621 
622 // In non-scalar case, we also promote empty structs without fields.
623 void permute_to_correct_order1 (const octave_map& ref, const octave_map& src,
624  octave_map& dest, Array<octave_idx_type>& perm)
625 {
626  if (src.nfields () == 0 && src.is_empty ())
627  dest = octave_map (src.dims (), ref.keys ());
628  else
629  dest = src.orderfields (ref, perm);
630 }
631 
632 template <class map>
633 static void
635  octave_idx_type idx, const map *map_list,
636  map *new_map_list)
637 {
638  new_map_list[idx] = map_list[idx];
639 
640  Array<octave_idx_type> perm (dim_vector (1, nf));
641 
642  for (octave_idx_type i = 0; i < n; i++)
643  {
644  if (i == idx)
645  continue;
646 
647  permute_to_correct_order1 (map_list[idx], map_list[i], new_map_list[i],
648  perm);
649 
650  if (error_state)
651  {
652  // Use liboctave exception to be consistent.
653  (*current_liboctave_error_handler)
654  ("cat: field names mismatch in concatenating structs");
655  break;
656  }
657  }
658 }
659 
660 
662 octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list)
663 {
664  octave_map retval;
665 
666  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
667  if (dim == -1 || dim == -2)
668  dim = -dim - 1;
669  else if (dim < 0)
670  (*current_liboctave_error_handler)
671  ("cat: invalid dimension");
672 
673  if (n == 1)
674  retval = map_list[0];
675  else if (n > 1)
676  {
677  octave_idx_type idx, nf = 0;
678  for (idx = 0; idx < n; idx++)
679  {
680  nf = map_list[idx].nfields ();
681  if (nf > 0)
682  {
683  retval.xkeys = map_list[idx].xkeys;
684  break;
685  }
686  }
687 
688  if (nf > 0)
689  {
690  // Try the fast case.
691  bool all_same = true;
692  for (octave_idx_type i = 0; i < n; i++)
693  {
694  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
695  if (! all_same)
696  break;
697  }
698 
699  if (all_same)
700  do_cat (dim, n, map_list, retval);
701  else
702  {
703  // permute all structures to common order.
704  OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
705 
706  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
707 
708  do_cat (dim, n, new_map_list, retval);
709  }
710 
711  }
712  else
713  {
714  dim_vector& rd = retval.dimensions;
715  rd.resize (dim+1, 1);
716  rd(0) = rd(1) = 1;
717  rd(dim) = n;
718  }
719 
720  retval.optimize_dimensions ();
721  }
722 
723  return retval;
724 }
725 
727 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
728 {
729  octave_map retval;
730 
731  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
732  if (dim == -1 || dim == -2)
733  dim = -dim - 1;
734  else if (dim < 0)
735  (*current_liboctave_error_handler)
736  ("cat: invalid dimension");
737 
738  if (n == 1)
739  retval = map_list[0];
740  else if (n > 1)
741  {
742  octave_idx_type idx, nf = 0;
743 
744  for (idx = 0; idx < n; idx++)
745  {
746  nf = map_list[idx].nfields ();
747  if (nf > 0)
748  {
749  retval.xkeys = map_list[idx].xkeys;
750  break;
751  }
752  }
753 
754  // Try the fast case.
755  bool all_same = true;
756 
757  if (nf > 0)
758  {
759  for (octave_idx_type i = 0; i < n; i++)
760  {
761  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
762 
763  if (! all_same)
764  break;
765  }
766  }
767 
768  if (all_same && nf > 0)
769  do_cat (dim, n, map_list, retval);
770  else
771  {
772  if (nf > 0)
773  {
774  // permute all structures to correct order.
775  OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
776 
777  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
778 
779  do_cat (dim, n, new_map_list, retval);
780  }
781  else
782  {
783  dim_vector dv = map_list[0].dimensions;
784 
785  for (octave_idx_type i = 1; i < n; i++)
786  {
787  if (! dv.concat (map_list[i].dimensions, dim))
788  {
789  error ("dimension mismatch in struct concatenation");
790  return retval;
791  }
792  }
793 
794  retval.dimensions = dv;
795  }
796  }
797 
798  retval.optimize_dimensions ();
799  }
800 
801  return retval;
802 }
803 
804 /*
805 ## test preservation of key order by concatenation
806 %!test
807 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
808 %! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
809 %! assert (fieldnames ([x; y]), {"d"; "a"; "f"});
810 
811 %!test
812 %! s = struct ();
813 %! sr = [s,s];
814 %! sc = [s;s];
815 %! sm = [s,s;s,s];
816 %! assert (numfields (sr), 0);
817 %! assert (numfields (sc), 0);
818 %! assert (numfields (sm), 0);
819 %! assert (size (sr), [1, 2]);
820 %! assert (size (sc), [2, 1]);
821 %! assert (size (sm), [2, 2]);
822 */
823 
825 octave_map::index (const idx_vector& i, bool resize_ok) const
826 {
827  octave_map retval (xkeys);
828  octave_idx_type nf = nfields ();
829 
830  for (octave_idx_type k = 0; k < nf; k++)
831  retval.xvals[k] = xvals[k].index (i, resize_ok);
832 
833  if (nf > 0)
834  retval.dimensions = retval.xvals[0].dims ();
835  else
836  {
837  // Use dummy array. FIXME: Need(?) a better solution.
838  Array<char> dummy (dimensions);
839  dummy = dummy.index (i, resize_ok);
840  retval.dimensions = dummy.dims ();
841  }
842 
843  retval.optimize_dimensions ();
844 
845  return retval;
846 }
847 
850  bool resize_ok) const
851 {
852  octave_map retval (xkeys);
853  octave_idx_type nf = nfields ();
854 
855  for (octave_idx_type k = 0; k < nf; k++)
856  retval.xvals[k] = xvals[k].index (i, j, resize_ok);
857 
858  if (nf > 0)
859  retval.dimensions = retval.xvals[0].dims ();
860  else
861  {
862  // Use dummy array. FIXME: Need(?) a better solution.
863  Array<char> dummy (dimensions);
864  dummy = dummy.index (i, j, resize_ok);
865  retval.dimensions = dummy.dims ();
866  }
867 
868  retval.optimize_dimensions ();
869 
870  return retval;
871 }
872 
874 octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
875 {
876  octave_map retval (xkeys);
877  octave_idx_type nf = nfields ();
878 
879  for (octave_idx_type k = 0; k < nf; k++)
880  retval.xvals[k] = xvals[k].index (ia, resize_ok);
881 
882  if (nf > 0)
883  retval.dimensions = retval.xvals[0].dims ();
884  else
885  {
886  // Use dummy array. FIXME: Need(?) a better solution.
887  Array<char> dummy (dimensions);
888  dummy = dummy.index (ia, resize_ok);
889  retval.dimensions = dummy.dims ();
890  }
891 
892  retval.optimize_dimensions ();
893 
894  return retval;
895 }
896 
898 octave_map::index (const octave_value_list& idx, bool resize_ok) const
899 {
900  octave_idx_type n_idx = idx.length ();
901  octave_map retval;
902 
903  switch (n_idx)
904  {
905  case 1:
906  {
907  idx_vector i = idx(0).index_vector ();
908 
909  if (! error_state)
910  retval = index (i, resize_ok);
911  }
912  break;
913 
914  case 2:
915  {
916  idx_vector i = idx(0).index_vector ();
917 
918  if (! error_state)
919  {
920  idx_vector j = idx(1).index_vector ();
921 
922  retval = index (i, j, resize_ok);
923  }
924  }
925  break;
926 
927  default:
928  {
929  Array<idx_vector> ia (dim_vector (n_idx, 1));
930 
931  for (octave_idx_type i = 0; i < n_idx; i++)
932  {
933  ia(i) = idx(i).index_vector ();
934 
935  if (error_state)
936  break;
937  }
938 
939  if (! error_state)
940  retval = index (ia, resize_ok);
941  }
942  break;
943  }
944 
945  return retval;
946 }
947 
948 // Perhaps one day these will be optimized. Right now, they just call index.
951 {
952  return index (idx_vector::colon, k);
953 }
954 
957 {
958  static Array<idx_vector> ia (dim_vector (3, 1), idx_vector::colon);
959 
960  ia(2) = k;
961  return index (ia);
962 }
963 
964 void
966 {
967  if (rhs.xkeys.is_same (xkeys))
968  {
969  octave_idx_type nf = nfields ();
970 
971  for (octave_idx_type k = 0; k < nf; k++)
972  xvals[k].assign (i, rhs.xvals[k], Matrix ());
973 
974  if (nf > 0)
975  dimensions = xvals[0].dims ();
976  else
977  {
978  // Use dummy array. FIXME: Need(?) a better solution.
979  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
980  dummy.assign (i, rhs_dummy);;
981  dimensions = dummy.dims ();
982  }
983 
985  }
986  else if (nfields () == 0)
987  {
988  octave_map tmp (dimensions, rhs.xkeys);
989  tmp.assign (i, rhs);
990  *this = tmp;
991  }
992  else
993  {
995  octave_map rhs1 = rhs.orderfields (*this, perm);
996  if (! error_state)
997  {
998  assert (rhs1.xkeys.is_same (xkeys));
999  assign (i, rhs1);
1000  }
1001  else
1002  error ("incompatible fields in struct assignment");
1003  }
1004 }
1005 
1006 void
1008  const octave_map& rhs)
1009 {
1010  if (rhs.xkeys.is_same (xkeys))
1011  {
1012  octave_idx_type nf = nfields ();
1013 
1014  for (octave_idx_type k = 0; k < nf; k++)
1015  xvals[k].assign (i, j, rhs.xvals[k], Matrix ());
1016 
1017  if (nf > 0)
1018  dimensions = xvals[0].dims ();
1019  else
1020  {
1021  // Use dummy array. FIXME: Need(?) a better solution.
1022  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1023  dummy.assign (i, j, rhs_dummy);;
1024  dimensions = dummy.dims ();
1025  }
1026 
1028  }
1029  else if (nfields () == 0)
1030  {
1031  octave_map tmp (dimensions, rhs.xkeys);
1032  tmp.assign (i, j, rhs);
1033  *this = tmp;
1034  }
1035  else
1036  {
1038  octave_map rhs1 = rhs.orderfields (*this, perm);
1039  if (! error_state)
1040  {
1041  assert (rhs1.xkeys.is_same (xkeys));
1042  assign (i, j, rhs1);
1043  }
1044  else
1045  error ("incompatible fields in struct assignment");
1046  }
1047 }
1048 
1049 void
1051  const octave_map& rhs)
1052 {
1053  if (rhs.xkeys.is_same (xkeys))
1054  {
1055  octave_idx_type nf = nfields ();
1056 
1057  for (octave_idx_type k = 0; k < nf; k++)
1058  xvals[k].assign (ia, rhs.xvals[k], Matrix ());
1059 
1060  if (nf > 0)
1061  dimensions = xvals[0].dims ();
1062  else
1063  {
1064  // Use dummy array. FIXME: Need(?) a better solution.
1065  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1066  dummy.assign (ia, rhs_dummy);;
1067  dimensions = dummy.dims ();
1068  }
1069 
1071  }
1072  else if (nfields () == 0)
1073  {
1074  octave_map tmp (dimensions, rhs.xkeys);
1075  tmp.assign (ia, rhs);
1076  *this = tmp;
1077  }
1078  else
1079  {
1081  octave_map rhs1 = rhs.orderfields (*this, perm);
1082  if (! error_state)
1083  {
1084  assert (rhs1.xkeys.is_same (xkeys));
1085  assign (ia, rhs1);
1086  }
1087  else
1088  error ("incompatible fields in struct assignment");
1089  }
1090 }
1091 
1092 void
1094 {
1095  octave_idx_type n_idx = idx.length ();
1096 
1097  switch (n_idx)
1098  {
1099  case 1:
1100  {
1101  idx_vector i = idx(0).index_vector ();
1102 
1103  if (! error_state)
1104  assign (i, rhs);
1105  }
1106  break;
1107 
1108  case 2:
1109  {
1110  idx_vector i = idx(0).index_vector ();
1111 
1112  if (! error_state)
1113  {
1114  idx_vector j = idx(1).index_vector ();
1115 
1116  assign (i, j, rhs);
1117  }
1118  }
1119  break;
1120 
1121  default:
1122  {
1123  Array<idx_vector> ia (dim_vector (n_idx, 1));
1124 
1125  for (octave_idx_type i = 0; i < n_idx; i++)
1126  {
1127  ia(i) = idx(i).index_vector ();
1128 
1129  if (error_state)
1130  break;
1131  }
1132 
1133  if (! error_state)
1134  assign (ia, rhs);
1135  }
1136  break;
1137  }
1138 }
1139 
1140 void
1141 octave_map::assign (const octave_value_list& idx, const std::string& k,
1142  const Cell& rhs)
1143 {
1144  Cell tmp;
1145  iterator p = seek (k);
1146  Cell& ref = p != end () ? contents (p) : tmp;
1147 
1148  if (&ref == &tmp)
1149  ref = Cell (dimensions);
1150 
1151  ref.assign (idx, rhs);
1152 
1153  if (! error_state && ref.dims () != dimensions)
1154  {
1155  dimensions = ref.dims ();
1156 
1157  octave_idx_type nf = nfields ();
1158  for (octave_idx_type i = 0; i < nf; i++)
1159  {
1160  if (&xvals[i] != &ref)
1161  xvals[i].resize (dimensions, Matrix ());
1162  }
1163 
1165  }
1166 
1167  if (! error_state && &ref == &tmp)
1168  setfield (k, tmp);
1169 }
1170 
1171 /*
1172 %!test
1173 %! rhs.b = 1;
1174 %! a(3) = rhs;
1175 %! assert ({a.b}, {[], [], 1})
1176 */
1177 
1178 void
1180 {
1181  octave_idx_type nf = nfields ();
1182  for (octave_idx_type k = 0; k < nf; k++)
1183  xvals[k].delete_elements (i);
1184 
1185  if (nf > 0)
1186  dimensions = xvals[0].dims ();
1187  else
1188  {
1189  // Use dummy array. FIXME: Need(?) a better solution.
1190  Array<char> dummy (dimensions);
1191  dummy.delete_elements (i);
1192  dimensions = dummy.dims ();
1193  }
1194 
1196 }
1197 
1198 void
1200 {
1201  octave_idx_type nf = nfields ();
1202  for (octave_idx_type k = 0; k < nf; k++)
1203  xvals[k].delete_elements (dim, i);
1204 
1205  if (nf > 0)
1206  dimensions = xvals[0].dims ();
1207  else
1208  {
1209  // Use dummy array. FIXME: Need(?) a better solution.
1210  Array<char> dummy (dimensions);
1211  dummy.delete_elements (dim, i);
1212  dimensions = dummy.dims ();
1213  }
1214 
1216 }
1217 
1218 void
1220 {
1221  octave_idx_type nf = nfields ();
1222  for (octave_idx_type k = 0; k < nf; k++)
1223  xvals[k].delete_elements (ia);
1224 
1225  if (nf > 0)
1226  dimensions = xvals[0].dims ();
1227  else
1228  {
1229  // Use dummy array. FIXME: Need(?) a better solution.
1230  Array<char> dummy (dimensions);
1231  dummy.delete_elements (ia);
1232  dimensions = dummy.dims ();
1233  }
1234 
1236 }
1237 
1238 void
1240 {
1241  octave_idx_type n_idx = idx.length ();
1242 
1243  Array<idx_vector> ia (dim_vector (n_idx, 1));
1244 
1245  for (octave_idx_type i = 0; i < n_idx; i++)
1246  {
1247  ia(i) = idx(i).index_vector ();
1248 
1249  if (error_state)
1250  break;
1251  }
1252 
1253  if (! error_state)
1254  delete_elements (ia);
1255 }
1256 
1257 /*
1258 ## test preservation of key order by indexing
1259 %!test
1260 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
1261 %! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
1262 */
1263 
1264 octave_map
1266 {
1267  if (nfields () == rb.nfields ())
1268  {
1269  for (const_iterator pa = begin (); pa != end (); pa++)
1270  {
1271  const_iterator pb = rb.seek (key(pa));
1272 
1273  if (pb == rb.end ())
1274  {
1275  error ("field name mismatch in structure concatenation");
1276  break;
1277  }
1278 
1279  contents(pa).insert (rb.contents (pb), ra_idx);
1280  }
1281  }
1282  else
1283  {
1284  dim_vector dv = dims ();
1285 
1286  if (dv.all_zero ())
1287  *this = rb;
1288  else if (! rb.dims ().all_zero ())
1289  error ("invalid structure concatenation");
1290  }
1291 
1292  return *this;
1293 }
1294 
1295 void
1297 {
1298  octave_idx_type nf = nfields ();
1299 
1300  for (octave_idx_type i = 0; i < nf; i++)
1301  {
1303  {
1304  error ("internal error: dimension mismatch across fields in struct");
1305  break;
1306  }
1307  }
1308 
1309 }
1310 
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:178
string_vector keys(void) const
Definition: oct-map.h:339
octave_map column(octave_idx_type k) const
Definition: oct-map.cc:950
const Cell & contents(const_iterator p) const
Definition: oct-map.h:314
dim_vector dimensions
Definition: oct-map.h:461
octave_map orderfields(void) const
Definition: oct-map.cc:291
Definition: Cell.h:35
octave_idx_type nfields(void) const
Definition: oct-map.h:205
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:662
void delete_elements(const idx_vector &i)
Definition: oct-map.cc:1179
const octave_base_value const Array< octave_idx_type > & ra_idx
bool equal_up_to_order(const octave_fields &other, octave_idx_type *perm) const
Definition: oct-map.cc:117
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:348
Array< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Definition: Array.cc:441
static const idx_vector colon
Definition: idx-vector.h:492
octave_map page(octave_idx_type k) const
Definition: oct-map.cc:956
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:275
void delete_elements(const idx_vector &i)
Deleting elements.
Definition: Array.cc:1393
octave_idx_type length(void) const
Definition: oct-obj.h:89
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:192
const_iterator iterator
Definition: oct-map.h:302
bool is_same(const octave_fields &other) const
Definition: oct-map.h:140
static void permute_to_correct_order(octave_idx_type n, octave_idx_type nf, octave_idx_type idx, const map *map_list, map *new_map_list)
Definition: oct-map.cc:634
void resize(int n, int fill_value=0)
Definition: dim-vector.h:287
void assign(const octave_value_list &idx, const Cell &rhs, const octave_value &fill_val=Matrix())
Definition: Cell.cc:222
void error(const char *fmt,...)
Definition: error.cc:476
bool isfield(const std::string &name) const
Definition: oct-map.cc:53
octave_scalar_map orderfields(void) const
Definition: oct-map.cc:189
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:171
octave_map squeeze(void) const
Definition: oct-map.cc:429
const_iterator end(void) const
Definition: oct-map.h:104
octave_fields(void)
Definition: oct-map.h:62
std::vector< Cell > xvals
Definition: oct-map.h:460
Cell getfield(const std::string &key) const
Definition: oct-map.cc:258
octave_idx_type rmfield(const std::string &name)
Definition: oct-map.cc:80
const_iterator end(void) const
Definition: oct-map.h:305
octave_fields xkeys
Definition: oct-map.h:252
dim_vector squeeze(void) const
Definition: dim-vector.cc:112
void permute_to_correct_order1(const octave_scalar_map &ref, const octave_scalar_map &src, octave_scalar_map &dest, Array< octave_idx_type > &perm)
Definition: oct-map.cc:614
void extract_scalar(octave_scalar_map &dest, octave_idx_type index) const
Definition: oct-map.cc:348
void orderfields(Array< octave_idx_type > &perm)
Definition: oct-map.cc:101
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:177
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
std::vector< octave_value > xvals
Definition: oct-map.h:253
octave_fields xkeys
Definition: oct-map.h:459
octave_idx_type nfields(void) const
Definition: oct-map.h:327
string_vector fieldnames(void) const
Definition: oct-map.cc:152
void rmfield(const std::string &key)
Definition: oct-map.cc:181
int error_state
Definition: error.cc:101
octave_map permute(const Array< int > &vec, bool inv=false) const
Definition: oct-map.cc:452
bool fast_elem_insert(octave_idx_type n, const octave_scalar_map &rhs)
Definition: oct-map.cc:400
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1033
dim_vector dims(void) const
Definition: oct-map.h:400
void rmfield(const std::string &key)
Definition: oct-map.cc:283
std::string key(const_iterator p) const
Definition: oct-map.h:309
fields_rep * rep
Definition: oct-map.h:52
octave_scalar_map fast_elem_extract(octave_idx_type n) const
Definition: oct-map.cc:390
Cell & insert(const Cell &a, octave_idx_type r, octave_idx_type c)
Definition: Cell.cc:295
Definition: dMatrix.h:35
const_iterator begin(void) const
Definition: oct-map.h:304
bool all_zero(void) const
Definition: dim-vector.h:304
octave_map(void)
Definition: oct-map.h:275
void make_unique(void)
Definition: oct-map.h:72
void setfield(const std::string &key, const Cell &val)
Definition: oct-map.cc:265
T & xelem(octave_idx_type n)
Definition: Array.h:353
octave_idx_type nfields(void) const
Definition: oct-map.h:115
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:267
void clear(void)
Definition: Array.cc:84
int ndims(void) const
Definition: oct-map.h:402
const_iterator iterator
Definition: oct-map.h:101
const_iterator begin(void) const
Definition: oct-map.h:103
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:197
const_iterator seek(const std::string &k) const
Definition: oct-map.h:307
Array< T > reshape(octave_idx_type nr, octave_idx_type nc) const
Definition: Array.h:460
octave_map reshape(const dim_vector &dv) const
Definition: oct-map.cc:513
octave_scalar_map checkelem(octave_idx_type n) const
Definition: oct-map.cc:357
bool is_empty(void) const
Definition: oct-map.h:374
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:164
octave_idx_type index(const_iterator p) const
Definition: oct-map.h:311
void resize(const dim_vector &dv, bool fill=false)
Definition: oct-map.cc:546
void optimize_dimensions(void)
Definition: oct-map.cc:1296
octave_map concat(const octave_map &rb, const Array< octave_idx_type > &ra_idx)
Definition: oct-map.cc:1265
const T * fortran_vec(void) const
Definition: Array.h:481
octave_fields::const_iterator const_iterator
Definition: oct-map.h:301
static void do_cat(int dim, octave_idx_type n, const octave_scalar_map *map_list, octave_map &retval)
Definition: oct-map.cc:572
octave_idx_type getfield(const std::string &name) const
Definition: oct-map.cc:59
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:716
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
octave_map transpose(void) const
Definition: oct-map.cc:486