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