GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-map.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1995-2018 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
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License 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 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (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 
38 {
39  static fields_rep nr;
40  return &nr;
41 }
42 
44  : rep (new fields_rep)
45 {
46  octave_idx_type n = fields.numel ();
47  for (octave_idx_type i = 0; i < n; i++)
48  (*rep)[fields(i)] = i;
49 }
50 
51 octave_fields::octave_fields (const char * const *fields)
52  : rep (new fields_rep)
53 {
54  octave_idx_type n = 0;
55  while (*fields)
56  (*rep)[std::string (*fields++)] = n++;
57 }
58 
59 bool
60 octave_fields::isfield (const std::string& field) const
61 {
62  return rep->find (field) != rep->end ();
63 }
64 
67 {
68  fields_rep::iterator p = rep->find (field);
69  return (p != rep->end ()) ? p->second : -1;
70 }
71 
74 {
75  fields_rep::iterator p = rep->find (field);
76  if (p != rep->end ())
77  return p->second;
78  else
79  {
80  make_unique ();
81  octave_idx_type n = rep->size ();
82  return (*rep)[field] = n;
83  }
84 }
85 
88 {
89  fields_rep::iterator p = rep->find (field);
90  if (p == rep->end ())
91  return -1;
92  else
93  {
94  octave_idx_type n = p->second;
95  make_unique ();
96  rep->erase (field);
97  for (auto& fld_idx : *rep)
98  {
99  if (fld_idx.second >= n)
100  fld_idx.second--;
101  }
102 
103  return n;
104  }
105 }
106 
107 void
109 {
110  octave_idx_type n = rep->size ();
111  perm.clear (n, 1);
112 
113  make_unique ();
114  octave_idx_type i = 0;
115  for (auto& fld_idx : *rep)
116  {
117  octave_idx_type j = fld_idx.second;
118  fld_idx.second = i;
119  perm(i++) = j;
120  }
121 }
122 
123 bool
125  octave_idx_type *perm) const
126 {
127  bool retval = true;
128 
129  iterator p = begin ();
130  iterator q = other.begin ();
131  for (; p != end () && q != other.end (); p++, q++)
132  {
133  if (p->first == q->first)
134  perm[p->second] = q->second;
135  else
136  {
137  retval = false;
138  break;
139  }
140  }
141 
142  retval = (p == end () && q == other.end ());
143 
144  return retval;
145 }
146 
147 bool
149  Array<octave_idx_type>& perm) const
150 {
151  octave_idx_type n = nfields ();
152  if (perm.numel () != n)
153  perm.clear (1, n);
154 
155  return equal_up_to_order (other, perm.fortran_vec ());
156 }
157 
160 {
161  octave_idx_type n = nfields ();
163 
164  for (auto& fld_idx : *this)
165  retval.xelem (fld_idx.second) = fld_idx.first;
166 
167  return retval;
168 }
169 
171  (const std::map<std::string, octave_value>& m)
172 {
173  size_t sz = m.size ();
174  xvals.resize (sz);
175  size_t i = 0;
176  for (const auto& k_v : m)
177  {
178  xkeys.getfield (k_v.first);
179  xvals[i++] = k_v.second;
180  }
181 }
182 
185 {
187  return (idx >= 0) ? xvals[idx] : octave_value ();
188 }
189 
190 void
192 {
194  if (idx < static_cast<octave_idx_type> (xvals.size ()))
195  xvals[idx] = val;
196  else
197  xvals.push_back (val);
198 }
199 
200 void
202 {
203  octave_idx_type idx = xkeys.rmfield (k);
204  if (idx >= 0)
205  xvals.erase (xvals.begin () + idx);
206 }
207 
210 {
212  return orderfields (perm);
213 }
214 
217 {
219  retval.xkeys.orderfields (perm);
220 
221  octave_idx_type nf = nfields ();
222  for (octave_idx_type i = 0; i < nf; i++)
223  retval.xvals[i] = xvals[perm.xelem (i)];
224 
225  return retval;
226 }
227 
230  Array<octave_idx_type>& perm) const
231 {
232  if (xkeys.is_same (other.xkeys))
233  return *this;
234  else
235  {
237  if (! other.xkeys.equal_up_to_order (xkeys, perm))
238  error ("orderfields: structs must have same fields up to order");
239 
240  octave_idx_type nf = nfields ();
241  for (octave_idx_type i = 0; i < nf; i++)
242  retval.xvals[i] = xvals[perm.xelem (i)];
243 
244  return retval;
245  }
246 }
247 
250 {
251  return getfield (k);
252 }
253 
256 {
258  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
259  xvals.resize (idx+1);
260  return xvals[idx];
261 }
262 
264  : xkeys (m.xkeys), xvals (), dimensions (1, 1)
265 {
266  octave_idx_type nf = m.nfields ();
267  xvals.reserve (nf);
268  for (octave_idx_type i = 0; i < nf; i++)
269  {
270  xvals.push_back (Cell (dimensions));
271  xvals[i].xelem (0) = m.xvals[i];
272  }
273 }
274 
275 Cell
277 {
279  return (idx >= 0) ? xvals[idx] : Cell ();
280 }
281 
282 void
284 {
285  if (nfields () == 0)
286  dimensions = val.dims ();
287 
288  if (val.dims () != dimensions)
289  error ("octave_map::setfield: internal error");
290 
292  if (idx < static_cast<octave_idx_type> (xvals.size ()))
293  xvals[idx] = val;
294  else
295  xvals.push_back (val);
296 }
297 
298 void
300 {
301  octave_idx_type idx = xkeys.rmfield (k);
302  if (idx >= 0)
303  xvals.erase (xvals.begin () + idx);
304 }
305 
308 {
310  return orderfields (perm);
311 }
312 
315 {
317  retval.xkeys.orderfields (perm);
318 
319  octave_idx_type nf = nfields ();
320  for (octave_idx_type i = 0; i < nf; i++)
321  retval.xvals[i] = xvals[perm.xelem (i)];
322 
323  return retval;
324 }
325 
328  Array<octave_idx_type>& perm) const
329 {
330  if (xkeys.is_same (other.xkeys))
331  return *this;
332  else
333  {
334  octave_map retval (other.xkeys);
335  if (! other.xkeys.equal_up_to_order (xkeys, perm))
336  error ("orderfields: structs must have same fields up to order");
337 
338  octave_idx_type nf = nfields ();
339  for (octave_idx_type i = 0; i < nf; i++)
340  retval.xvals[i] = xvals[perm.xelem (i)];
341 
342  return retval;
343  }
344 }
345 
346 Cell
348 {
349  return getfield (k);
350 }
351 
352 Cell&
354 {
356  if (idx >= static_cast<octave_idx_type> (xvals.size ()))
357  xvals.push_back (Cell (dimensions)); // auto-set correct dims.
358  return xvals[idx];
359 }
360 
361 void
363  octave_idx_type idx) const
364 {
365  octave_idx_type nf = nfields ();
366  for (octave_idx_type i = 0; i < nf; i++)
367  dest.xvals[i] = xvals[i](idx);
368 }
369 
372 {
374 
375  // Optimize this so that there is just one check.
377 
378  return retval;
379 }
380 
383 {
385 
386  // Optimize this so that there is just one check.
388 
389  return retval;
390 }
391 
394 {
396 
397  // Optimize this so that there is just one check.
399 
400  return retval;
401 }
402 
405 {
407 
408  extract_scalar (retval, n);
409 
410  return retval;
411 }
412 
413 bool
415  const octave_scalar_map& rhs)
416 {
417  bool retval = false;
418 
419  octave_idx_type nf = nfields ();
420  if (rhs.xkeys.is_same (xkeys))
421  {
422  for (octave_idx_type i = 0; i < nf; i++)
423  xvals[i](n) = rhs.xvals[i];
424 
425  retval = true;
426  }
427  else
428  {
430  if (xkeys.equal_up_to_order (rhs.xkeys, perm))
431  {
432  for (octave_idx_type i = 0; i < nf; i++)
433  xvals[i](n) = rhs.xvals[perm[i]];
434 
435  retval = true;
436  }
437  }
438 
439  return retval;
440 }
441 
444 {
445  octave_map retval (*this);
446  octave_idx_type nf = nfields ();
447 
448  retval.dimensions = dimensions.squeeze ();
449 
450  for (octave_idx_type i = 0; i < nf; i++)
451  retval.xvals[i] = xvals[i].squeeze ();
452 
453  retval.optimize_dimensions ();
454 
455  return retval;
456 }
457 
458 /*
459 ## test preservation of xkeys by squeeze
460 %!test
461 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
462 %! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"});
463 */
464 
466 octave_map::permute (const Array<int>& vec, bool inv) const
467 {
469  octave_idx_type nf = nfields ();
470 
471  for (octave_idx_type i = 0; i < nf; i++)
472  retval.xvals[i] = xvals[i].permute (vec, inv);
473 
474  // FIXME:
475  // There is no dim_vector::permute for technical reasons.
476  // We pick the dim vector from results if possible, otherwise use a dummy
477  // array to get it. Need (?) a better solution to this problem.
478  if (nf > 0)
479  retval.dimensions = retval.xvals[0].dims ();
480  else
481  {
482  Array<char> dummy (dimensions);
483  dummy = dummy.permute (vec, inv);
484  retval.dimensions = dummy.dims ();
485  }
486 
487  retval.optimize_dimensions ();
488 
489  return retval;
490 }
491 
492 /*
493 ## test preservation of key order by permute
494 %!test
495 %! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27;
496 %! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"});
497 */
498 
501 {
502  assert (ndims () == 2);
503 
505 
506  retval.dimensions = dim_vector (dimensions (1), dimensions (0));
507 
508  octave_idx_type nf = nfields ();
509  for (octave_idx_type i = 0; i < nf; i++)
510  retval.xvals[i] = xvals[i].transpose ();
511 
512  retval.optimize_dimensions ();
513 
514  return retval;
515 }
516 
517 /*
518 ## test preservation of key order by transpose
519 %!test
520 %! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
521 %! assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
522 %! assert (fieldnames (x'), {"d"; "a"; "f"});
523 %! assert (fieldnames (x.'), {"d"; "a"; "f"});
524 */
525 
528 {
530  retval.dimensions = dv;
531 
532  // When reshaping xvals the Array constructor chops trailing singletons,
533  // hence we need to do the same for the whole map.
534  retval.dimensions.chop_trailing_singletons ();
535 
536  octave_idx_type nf = nfields ();
537  if (nf > 0)
538  {
539  retval.xvals.reserve (nf);
540  for (octave_idx_type i = 0; i < nf; i++)
541  retval.xvals[i] = xvals[i].reshape (dv);
542  }
543  else
544  {
545  // FIXME: Do it with a dummy array, to reuse error message.
546  // Need (?) a better solution.
547  Array<char> dummy (dimensions);
548  dummy.reshape (dv);
549  }
550 
551  retval.optimize_dimensions ();
552 
553  return retval;
554 }
555 
556 /*
557 ## test preservation of key order by reshape
558 %!test
559 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
560 %! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
561 
562 ## test chopping of trailing singletons
563 %!test <51634>
564 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
565 %! reshape (x, 3, 8, 1, 1);
566 
567 %!test <46385>
568 %! M = repmat (struct ('a', ones(100), 'b', true), 1, 2);
569 %! M = repmat(M, 1, 2);
570 %! assert (size (M), [1, 4]);
571 
572 libinterp/corefcn/oct-map.cc
573 
574 */
575 
576 void
577 octave_map::resize (const dim_vector& dv, bool fill)
578 {
579  octave_idx_type nf = nfields ();
580  if (nf > 0)
581  {
582  for (octave_idx_type i = 0; i < nf; i++)
583  {
584  if (fill)
585  xvals[i].resize (dv, Matrix ());
586  else
587  xvals[i].resize (dv);
588  }
589  }
590  else
591  {
592  // FIXME: Do it with a dummy array, to reuse error message.
593  // Need (?) a better solution.
594  Array<char> dummy (dimensions);
595  dummy.resize (dv);
596  }
597 
598  dimensions = dv;
600 }
601 
602 void
604  const octave_scalar_map *map_list,
606 {
608  retval.xvals.reserve (nf);
609 
610  dim_vector& rd = retval.dimensions;
611  rd.resize (dim+1, 1);
612  rd(0) = rd(1) = 1;
613  rd(dim) = n;
614 
615  for (octave_idx_type j = 0; j < nf; j++)
616  {
617  retval.xvals.push_back (Cell (rd));
618  assert (retval.xvals[j].numel () == n);
619  for (octave_idx_type i = 0; i < n; i++)
620  retval.xvals[j].xelem (i) = map_list[i].xvals[j];
621  }
622 }
623 
624 void
625 octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
627 {
629  retval.xvals.reserve (nf);
630 
631  OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n);
632 
633  for (octave_idx_type j = 0; j < nf; j++)
634  {
635  for (octave_idx_type i = 0; i < n; i++)
636  field_list[i] = map_list[i].xvals[j];
637 
638  retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list));
639  if (j == 0)
640  retval.dimensions = retval.xvals[j].dims ();
641  }
642 }
643 
644 // This is just a wrapper.
646  const octave_scalar_map& src,
647  octave_scalar_map& dest,
649 {
650  dest = src.orderfields (ref, perm);
651 }
652 
653 // In non-scalar case, we also promote empty structs without fields.
654 void permute_to_correct_order1 (const octave_map& ref, const octave_map& src,
655  octave_map& dest, Array<octave_idx_type>& perm)
656 {
657  if (src.nfields () == 0 && src.isempty ())
658  dest = octave_map (src.dims (), ref.keys ());
659  else
660  dest = src.orderfields (ref, perm);
661 }
662 
663 template <typename map>
664 static void
666  octave_idx_type idx, const map *map_list,
667  map *new_map_list)
668 {
669  new_map_list[idx] = map_list[idx];
670 
671  Array<octave_idx_type> perm (dim_vector (1, nf));
672 
673  try
674  {
675  for (octave_idx_type i = 0; i < n; i++)
676  {
677  if (i == idx)
678  continue;
679 
680  permute_to_correct_order1 (map_list[idx], map_list[i],
681  new_map_list[i], perm);
682  }
683  }
684  catch (octave::execution_exception& e)
685  {
686  error (e, "cat: field names mismatch in concatenating structs");
687  }
688 }
689 
691 octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list)
692 {
694 
695  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
696  if (dim == -1 || dim == -2)
697  dim = -dim - 1;
698  else if (dim < 0)
699  error ("cat: invalid dimension");
700 
701  if (n == 1)
702  retval = map_list[0];
703  else if (n > 1)
704  {
705  octave_idx_type idx, nf = 0;
706  for (idx = 0; idx < n; idx++)
707  {
708  nf = map_list[idx].nfields ();
709  if (nf > 0)
710  {
711  retval.xkeys = map_list[idx].xkeys;
712  break;
713  }
714  }
715 
716  if (nf > 0)
717  {
718  // Try the fast case.
719  bool all_same = true;
720  for (octave_idx_type i = 0; i < n; i++)
721  {
722  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
723  if (! all_same)
724  break;
725  }
726 
727  if (all_same)
728  do_cat (dim, n, map_list, retval);
729  else
730  {
731  // permute all structures to common order.
732  OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
733 
734  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
735 
736  do_cat (dim, n, new_map_list, retval);
737  }
738 
739  }
740  else
741  {
742  dim_vector& rd = retval.dimensions;
743  rd.resize (dim+1, 1);
744  rd(0) = rd(1) = 1;
745  rd(dim) = n;
746  }
747 
748  retval.optimize_dimensions ();
749  }
750 
751  return retval;
752 }
753 
755 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
756 {
758 
759  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
760  if (dim == -1 || dim == -2)
761  dim = -dim - 1;
762  else if (dim < 0)
763  error ("cat: invalid dimension");
764 
765  if (n == 1)
766  retval = map_list[0];
767  else if (n > 1)
768  {
769  octave_idx_type idx, nf = 0;
770 
771  for (idx = 0; idx < n; idx++)
772  {
773  nf = map_list[idx].nfields ();
774  if (nf > 0)
775  {
776  retval.xkeys = map_list[idx].xkeys;
777  break;
778  }
779  }
780 
781  // Try the fast case.
782  bool all_same = true;
783 
784  if (nf > 0)
785  {
786  for (octave_idx_type i = 0; i < n; i++)
787  {
788  all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys);
789 
790  if (! all_same)
791  break;
792  }
793  }
794 
795  if (all_same && nf > 0)
796  do_cat (dim, n, map_list, retval);
797  else
798  {
799  if (nf > 0)
800  {
801  // permute all structures to correct order.
802  OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
803 
804  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
805 
806  do_cat (dim, n, new_map_list, retval);
807  }
808  else
809  {
810  dim_vector dv = map_list[0].dimensions;
811 
812  for (octave_idx_type i = 1; i < n; i++)
813  {
814  if (! dv.concat (map_list[i].dimensions, dim))
815  error ("dimension mismatch in struct concatenation");
816  }
817 
818  retval.dimensions = dv;
819  }
820  }
821 
822  retval.optimize_dimensions ();
823  }
824 
825  return retval;
826 }
827 
828 /*
829 ## test preservation of key order by concatenation
830 %!test
831 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
832 %! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
833 %! assert (fieldnames ([x; y]), {"d"; "a"; "f"});
834 
835 %!test
836 %! s = struct ();
837 %! sr = [s,s];
838 %! sc = [s;s];
839 %! sm = [s,s;s,s];
840 %! assert (numfields (sr), 0);
841 %! assert (numfields (sc), 0);
842 %! assert (numfields (sm), 0);
843 %! assert (size (sr), [1, 2]);
844 %! assert (size (sc), [2, 1]);
845 %! assert (size (sm), [2, 2]);
846 */
847 
849 octave_map::index (const idx_vector& i, bool resize_ok) const
850 {
852  octave_idx_type nf = nfields ();
853 
854  for (octave_idx_type k = 0; k < nf; k++)
855  retval.xvals[k] = xvals[k].index (i, resize_ok);
856 
857  if (nf > 0)
858  retval.dimensions = retval.xvals[0].dims ();
859  else
860  {
861  // Use dummy array. FIXME: Need(?) a better solution.
862  Array<char> dummy (dimensions);
863  dummy = dummy.index (i, resize_ok);
864  retval.dimensions = dummy.dims ();
865  }
866 
867  retval.optimize_dimensions ();
868 
869  return retval;
870 }
871 
874  bool resize_ok) const
875 {
877  octave_idx_type nf = nfields ();
878 
879  for (octave_idx_type k = 0; k < nf; k++)
880  retval.xvals[k] = xvals[k].index (i, j, 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 (i, j, resize_ok);
889  retval.dimensions = dummy.dims ();
890  }
891 
892  retval.optimize_dimensions ();
893 
894  return retval;
895 }
896 
898 octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
899 {
901  octave_idx_type nf = nfields ();
902 
903  for (octave_idx_type k = 0; k < nf; k++)
904  retval.xvals[k] = xvals[k].index (ia, resize_ok);
905 
906  if (nf > 0)
907  retval.dimensions = retval.xvals[0].dims ();
908  else
909  {
910  // Use dummy array. FIXME: Need(?) a better solution.
911  Array<char> dummy (dimensions);
912  dummy = dummy.index (ia, resize_ok);
913  retval.dimensions = dummy.dims ();
914  }
915 
916  retval.optimize_dimensions ();
917 
918  return retval;
919 }
920 
922 octave_map::index (const octave_value_list& idx, bool resize_ok) const
923 {
924  octave_idx_type n_idx = idx.length ();
926 
927  // If we catch an indexing error in index_vector, we flag an error in
928  // index k. Ensure it is the right value befor each idx_vector call.
929  // Same variable as used in the for loop in the default case.
930 
931  octave_idx_type k = 0;
932 
933  try
934  {
935  switch (n_idx)
936  {
937  case 1:
938  {
939  idx_vector i = idx(0).index_vector ();
940 
941  retval = index (i, resize_ok);
942  }
943  break;
944 
945  case 2:
946  {
947  idx_vector i = idx(0).index_vector ();
948 
949  k = 1;
950  idx_vector j = idx(1).index_vector ();
951 
952  retval = index (i, j, resize_ok);
953  }
954  break;
955 
956  default:
957  {
958  Array<idx_vector> ia (dim_vector (n_idx, 1));
959 
960  for (k = 0; k < n_idx; k++)
961  ia(k) = idx(k).index_vector ();
962 
963  retval = index (ia, resize_ok);
964  }
965  break;
966  }
967  }
968  catch (octave::index_exception& e)
969  {
970  // Rethrow to allow more info to be reported later.
971  e.set_pos_if_unset (n_idx, k+1);
972  throw;
973  }
974 
975  return retval;
976 }
977 
978 // Perhaps one day these will be optimized. Right now, they just call index.
981 {
982  return index (idx_vector::colon, k);
983 }
984 
987 {
988  static Array<idx_vector> ia (dim_vector (3, 1), idx_vector::colon);
989 
990  ia(2) = k;
991  return index (ia);
992 }
993 
994 void
996 {
997  if (rhs.xkeys.is_same (xkeys))
998  {
999  octave_idx_type nf = nfields ();
1000 
1001  for (octave_idx_type k = 0; k < nf; k++)
1002  xvals[k].assign (i, rhs.xvals[k], Matrix ());
1003 
1004  if (nf > 0)
1005  dimensions = xvals[0].dims ();
1006  else
1007  {
1008  // Use dummy array. FIXME: Need(?) a better solution.
1009  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1010  dummy.assign (i, rhs_dummy);;
1011  dimensions = dummy.dims ();
1012  }
1013 
1015  }
1016  else if (nfields () == 0)
1017  {
1018  octave_map tmp (dimensions, rhs.xkeys);
1019  tmp.assign (i, rhs);
1020  *this = tmp;
1021  }
1022  else
1023  {
1025  octave_map rhs1;
1026 
1027  try
1028  {
1029  rhs1 = rhs.orderfields (*this, perm);
1030  }
1031  catch (octave::execution_exception& e)
1032  {
1033  error (e, "incompatible fields in struct assignment");
1034  }
1035 
1036  assert (rhs1.xkeys.is_same (xkeys));
1037  assign (i, rhs1);
1038  }
1039 }
1040 
1041 void
1043  const octave_map& rhs)
1044 {
1045  if (rhs.xkeys.is_same (xkeys))
1046  {
1047  octave_idx_type nf = nfields ();
1048 
1049  for (octave_idx_type k = 0; k < nf; k++)
1050  xvals[k].assign (i, j, rhs.xvals[k], Matrix ());
1051 
1052  if (nf > 0)
1053  dimensions = xvals[0].dims ();
1054  else
1055  {
1056  // Use dummy array. FIXME: Need(?) a better solution.
1057  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1058  dummy.assign (i, j, rhs_dummy);;
1059  dimensions = dummy.dims ();
1060  }
1061 
1063  }
1064  else if (nfields () == 0)
1065  {
1066  octave_map tmp (dimensions, rhs.xkeys);
1067  tmp.assign (i, j, rhs);
1068  *this = tmp;
1069  }
1070  else
1071  {
1073  octave_map rhs1;
1074 
1075  try
1076  {
1077  rhs1 = rhs.orderfields (*this, perm);
1078  }
1079  catch (octave::execution_exception& e)
1080  {
1081  error (e, "incompatible fields in struct assignment");
1082  }
1083 
1084  assert (rhs1.xkeys.is_same (xkeys));
1085  assign (i, j, rhs1);
1086  }
1087 }
1088 
1089 void
1091  const octave_map& rhs)
1092 {
1093  if (rhs.xkeys.is_same (xkeys))
1094  {
1095  octave_idx_type nf = nfields ();
1096 
1097  for (octave_idx_type k = 0; k < nf; k++)
1098  xvals[k].assign (ia, rhs.xvals[k], Matrix ());
1099 
1100  if (nf > 0)
1101  dimensions = xvals[0].dims ();
1102  else
1103  {
1104  // Use dummy array. FIXME: Need(?) a better solution.
1105  Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions);
1106  dummy.assign (ia, rhs_dummy);;
1107  dimensions = dummy.dims ();
1108  }
1109 
1111  }
1112  else if (nfields () == 0)
1113  {
1114  octave_map tmp (dimensions, rhs.xkeys);
1115  tmp.assign (ia, rhs);
1116  *this = tmp;
1117  }
1118  else
1119  {
1121  octave_map rhs1;
1122 
1123  try
1124  {
1125  rhs1 = rhs.orderfields (*this, perm);
1126  }
1127  catch (octave::execution_exception& e)
1128  {
1129  error (e, "incompatible fields in struct assignment");
1130  }
1131 
1132  assert (rhs1.xkeys.is_same (xkeys));
1133  assign (ia, rhs1);
1134  }
1135 }
1136 
1137 void
1139 {
1140  octave_idx_type n_idx = idx.length ();
1141 
1142  // If we catch an indexing error in index_vector, we flag an error in
1143  // index k. Ensure it is the right value befor each idx_vector call.
1144  // Same variable as used in the for loop in the default case.
1145 
1146  octave_idx_type k = 0;
1147 
1148  try
1149  {
1150  switch (n_idx)
1151  {
1152  case 1:
1153  {
1154  idx_vector i = idx(0).index_vector ();
1155 
1156  assign (i, rhs);
1157  }
1158  break;
1159 
1160  case 2:
1161  {
1162  idx_vector i = idx(0).index_vector ();
1163 
1164  k = 1;
1165  idx_vector j = idx(1).index_vector ();
1166 
1167  assign (i, j, rhs);
1168  }
1169  break;
1170 
1171  default:
1172  {
1173  Array<idx_vector> ia (dim_vector (n_idx, 1));
1174 
1175  for (k = 0; k < n_idx; k++)
1176  ia(k) = idx(k).index_vector ();
1177 
1178  assign (ia, rhs);
1179  }
1180  break;
1181  }
1182  }
1183  catch (octave::index_exception& e)
1184  {
1185  // Rethrow to allow more info to be reported later.
1186  e.set_pos_if_unset (n_idx, k+1);
1187  throw;
1188  }
1189 }
1190 
1191 void
1193  const Cell& rhs)
1194 {
1195  Cell tmp;
1196  iterator p = seek (k);
1197  Cell& ref = (p != end () ? contents (p) : tmp);
1198 
1199  if (&ref == &tmp)
1200  ref = Cell (dimensions);
1201 
1202  ref.assign (idx, rhs);
1203 
1204  if (ref.dims () != dimensions)
1205  {
1206  dimensions = ref.dims ();
1207 
1208  octave_idx_type nf = nfields ();
1209  for (octave_idx_type i = 0; i < nf; i++)
1210  {
1211  if (&xvals[i] != &ref)
1212  xvals[i].resize (dimensions, Matrix ());
1213  }
1214 
1216  }
1217 
1218  if (&ref == &tmp)
1219  setfield (k, tmp);
1220 }
1221 
1222 /*
1223 %!test
1224 %! rhs.b = 1;
1225 %! a(3) = rhs;
1226 %! assert ({a.b}, {[], [], 1});
1227 */
1228 
1229 void
1231 {
1232  octave_idx_type nf = nfields ();
1233  for (octave_idx_type k = 0; k < nf; k++)
1234  xvals[k].delete_elements (i);
1235 
1236  if (nf > 0)
1237  dimensions = xvals[0].dims ();
1238  else
1239  {
1240  // Use dummy array. FIXME: Need(?) a better solution.
1241  Array<char> dummy (dimensions);
1242  dummy.delete_elements (i);
1243  dimensions = dummy.dims ();
1244  }
1245 
1247 }
1248 
1249 void
1251 {
1252  octave_idx_type nf = nfields ();
1253  for (octave_idx_type k = 0; k < nf; k++)
1254  xvals[k].delete_elements (dim, i);
1255 
1256  if (nf > 0)
1257  dimensions = xvals[0].dims ();
1258  else
1259  {
1260  // Use dummy array. FIXME: Need(?) a better solution.
1261  Array<char> dummy (dimensions);
1262  dummy.delete_elements (dim, i);
1263  dimensions = dummy.dims ();
1264  }
1265 
1267 }
1268 
1269 void
1271 {
1272  octave_idx_type nf = nfields ();
1273  for (octave_idx_type k = 0; k < nf; k++)
1274  xvals[k].delete_elements (ia);
1275 
1276  if (nf > 0)
1277  dimensions = xvals[0].dims ();
1278  else
1279  {
1280  // Use dummy array. FIXME: Need(?) a better solution.
1281  Array<char> dummy (dimensions);
1282  dummy.delete_elements (ia);
1283  dimensions = dummy.dims ();
1284  }
1285 
1287 }
1288 
1289 void
1291 {
1292  octave_idx_type n_idx = idx.length ();
1293 
1294  Array<idx_vector> ia (dim_vector (n_idx, 1));
1295 
1296  for (octave_idx_type i = 0; i < n_idx; i++)
1297  {
1298  try
1299  {
1300  ia(i) = idx(i).index_vector ();
1301  }
1302  catch (octave::index_exception& e)
1303  {
1304  // Rethrow to allow more info to be reported later.
1305  e.set_pos_if_unset (n_idx, i+1);
1306  throw;
1307  }
1308  }
1309 
1310  delete_elements (ia);
1311 }
1312 
1313 /*
1314 ## test preservation of key order by indexing
1315 %!test
1316 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
1317 %! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
1318 */
1319 
1320 octave_map
1322 {
1323  if (nfields () == rb.nfields ())
1324  {
1325  for (const_iterator pa = begin (); pa != end (); pa++)
1326  {
1327  const_iterator pb = rb.seek (key (pa));
1328 
1329  if (pb == rb.end ())
1330  error ("field name mismatch in structure concatenation");
1331 
1332  contents(pa).insert (rb.contents (pb), ra_idx);
1333  }
1334  }
1335  else
1336  {
1337  dim_vector dv = dims ();
1338 
1339  if (dv.all_zero ())
1340  *this = rb;
1341  else if (! rb.dims ().all_zero ())
1342  error ("invalid structure concatenation");
1343  }
1344 
1345  return *this;
1346 }
1347 
1348 void
1350 {
1351  octave_idx_type nf = nfields ();
1352 
1353  for (octave_idx_type i = 0; i < nf; i++)
1354  {
1356  error ("internal error: dimension mismatch across fields in struct");
1357  }
1358 
1359 }
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:175
octave_map squeeze(void) const
Definition: oct-map.cc:443
dim_vector dimensions
Definition: oct-map.h:477
scalar structure containing the fields
Definition: ov-struct.cc:1736
Definition: Cell.h:37
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:691
void delete_elements(const idx_vector &i)
Definition: oct-map.cc:1230
const_iterator begin(void) const
Definition: oct-map.h:103
const octave_base_value const Array< octave_idx_type > & ra_idx
string_vector keys(void) const
Definition: oct-map.h:342
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:351
static const idx_vector colon
Definition: idx-vector.h:498
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
int ndims(void) const
Definition: oct-map.h:418
void delete_elements(const idx_vector &i)
Deleting elements.
Definition: Array.cc:1389
const_iterator iterator
Definition: oct-map.h:305
bool isfield(const std::string &name) const
Definition: oct-map.cc:60
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:665
for large enough k
Definition: lu.cc:617
Array< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Definition: Array.cc:430
void resize(int n, int fill_value=0)
Definition: dim-vector.h:310
const T * fortran_vec(void) const
Definition: Array.h:584
void assign(const octave_value_list &idx, const Cell &rhs, const octave_value &fill_val=Matrix())
Definition: Cell.cc:220
void error(const char *fmt,...)
Definition: error.cc:578
octave_idx_type nfields(void) const
Definition: oct-map.h:115
std::string key(const_iterator p) const
Definition: oct-map.h:312
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:442
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:191
octave_fields(void)
Definition: oct-map.h:62
const_iterator end(void) const
Definition: oct-map.h:308
std::vector< Cell > xvals
Definition: oct-map.h:476
octave_idx_type rmfield(const std::string &name)
Definition: oct-map.cc:87
i e
Definition: data.cc:2591
octave_fields xkeys
Definition: oct-map.h:254
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:645
void orderfields(Array< octave_idx_type > &perm)
Definition: oct-map.cc:108
Array< T > reshape(octave_idx_type nr, octave_idx_type nc) const
Definition: Array.h:549
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:145
octave_scalar_map orderfields(void) const
Definition: oct-map.cc:209
octave_map permute(const Array< int > &vec, bool inv=false) const
Definition: oct-map.cc:466
octave_idx_type index(const_iterator p) const
Definition: oct-map.h:314
Cell getfield(const std::string &key) const
Definition: oct-map.cc:276
std::vector< octave_value > xvals
Definition: oct-map.h:255
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:697
octave_fields xkeys
Definition: oct-map.h:475
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:412
string_vector fieldnames(void) const
Definition: oct-map.cc:159
octave_map reshape(const dim_vector &dv) const
Definition: oct-map.cc:527
dim_vector dims(void) const
Definition: ov.h:469
void rmfield(const std::string &key)
Definition: oct-map.cc:201
octave_scalar_map fast_elem_extract(octave_idx_type n) const
Definition: oct-map.cc:404
bool fast_elem_insert(octave_idx_type n, const octave_scalar_map &rhs)
Definition: oct-map.cc:414
void resize(const dim_vector &dv, const T &rfv)
Resizing (with fill).
Definition: Array.cc:1010
octave_scalar_map elem(octave_idx_type n) const
Definition: oct-map.cc:371
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
void rmfield(const std::string &key)
Definition: oct-map.cc:299
bool equal_up_to_order(const octave_fields &other, octave_idx_type *perm) const
Definition: oct-map.cc:124
const Cell & contents(const_iterator p) const
Definition: oct-map.h:317
fields_rep * rep
Definition: oct-map.h:56
Cell & insert(const Cell &a, octave_idx_type r, octave_idx_type c)
Definition: Cell.cc:308
Definition: dMatrix.h:36
sz
Definition: data.cc:5264
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:184
bool all_zero(void) const
Definition: dim-vector.h:327
octave_map(void)
Definition: oct-map.h:277
void make_unique(void)
Definition: oct-map.h:72
void setfield(const std::string &key, const Cell &val)
Definition: oct-map.cc:283
T & xelem(octave_idx_type n)
Definition: Array.h:458
void extract_scalar(octave_scalar_map &dest, octave_idx_type index) const
Definition: oct-map.cc:362
octave_idx_type nfields(void) const
Definition: oct-map.h:330
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
void clear(void)
Definition: Array.cc:86
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:194
bool is_same(const octave_fields &other) const
Definition: oct-map.h:140
octave_map transpose(void) const
Definition: oct-map.cc:500
const_iterator iterator
Definition: oct-map.h:101
p
Definition: lu.cc:138
octave_map map(dims)
octave_idx_type length(void) const
Definition: ovl.h:96
bool isempty(void) const
Definition: oct-map.h:377
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
octave_idx_type getfield(const std::string &name) const
Definition: oct-map.cc:66
dim_vector squeeze(void) const
Definition: dim-vector.cc:122
octave_idx_type nfields(void) const
Definition: ov.h:500
octave_map column(octave_idx_type k) const
Definition: oct-map.cc:980
for i
Definition: data.cc:5264
void resize(const dim_vector &dv, bool fill=false)
Definition: oct-map.cc:577
void optimize_dimensions(void)
Definition: oct-map.cc:1349
octave_map concat(const octave_map &rb, const Array< octave_idx_type > &ra_idx)
Definition: oct-map.cc:1321
dim_vector dims(void) const
Definition: oct-map.h:416
octave_fields::const_iterator const_iterator
Definition: oct-map.h:304
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
octave_map page(octave_idx_type k) const
Definition: oct-map.cc:986
octave_idx_type nfields(void) const
Definition: oct-map.h:207
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
const_iterator begin(void) const
Definition: oct-map.h:307
const_iterator seek(const std::string &k) const
Definition: oct-map.h:310
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
dim_vector dv
Definition: sub2ind.cc:263
octave_scalar_map(void)
Definition: oct-map.h:160
octave_map orderfields(void) const
Definition: oct-map.cc:307
static void do_cat(int dim, octave_idx_type n, const octave_scalar_map *map_list, octave_map &retval)
Definition: oct-map.cc:603
const_iterator end(void) const
Definition: oct-map.h:104
static fields_rep * nil_rep(void)
Definition: oct-map.cc:37