GNU Octave  8.1.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-2023 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  : m_rep (new fields_rep)
47 {
48  octave_idx_type n = fields.numel ();
49  for (octave_idx_type i = 0; i < n; i++)
50  (*m_rep)[fields(i)] = i;
51 }
52 
53 octave_fields::octave_fields (const char *const *fields)
54  : m_rep (new fields_rep)
55 {
56  octave_idx_type n = 0;
57  while (*fields)
58  (*m_rep)[std::string (*fields++)] = n++;
59 }
60 
61 bool
62 octave_fields::isfield (const std::string& field) const
63 {
64  return m_rep->find (field) != m_rep->end ();
65 }
66 
68 octave_fields::getfield (const std::string& field) const
69 {
70  auto p = m_rep->find (field);
71  return (p != m_rep->end ()) ? p->second : -1;
72 }
73 
75 octave_fields::getfield (const std::string& field)
76 {
77  auto p = m_rep->find (field);
78  if (p != m_rep->end ())
79  return p->second;
80  else
81  {
82  make_unique ();
83  octave_idx_type n = m_rep->size ();
84  return (*m_rep)[field] = n;
85  }
86 }
87 
89 octave_fields::rmfield (const std::string& field)
90 {
91  auto p = m_rep->find (field);
92  if (p == m_rep->end ())
93  return -1;
94  else
95  {
96  octave_idx_type n = p->second;
97  make_unique ();
98  m_rep->erase (field);
99  for (auto& fld_idx : *m_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 = m_rep->size ();
113  perm.clear (n, 1);
114 
115  make_unique ();
116  octave_idx_type i = 0;
117  for (auto& fld_idx : *m_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 {
161  string_vector retval(n);
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  std::size_t sz = m.size ();
173  m_vals.resize (sz);
174  std::size_t i = 0;
175  for (const auto& k_v : m)
176  {
177  m_keys.getfield (k_v.first);
178  m_vals[i++] = k_v.second;
179  }
180 }
181 
183 octave_scalar_map::getfield (const std::string& k) const
184 {
185  octave_idx_type idx = m_keys.getfield (k);
186  return (idx >= 0) ? m_vals[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 = m_keys.getfield (k);
193  if (idx < static_cast<octave_idx_type> (m_vals.size ()))
194  m_vals[idx] = val;
195  else
196  m_vals.push_back (val);
197 }
198 
199 void
200 octave_scalar_map::rmfield (const std::string& k)
201 {
202  octave_idx_type idx = m_keys.rmfield (k);
203  if (idx >= 0)
204  m_vals.erase (m_vals.begin () + idx);
205 }
206 
209 {
211  return orderfields (perm);
212 }
213 
216 {
217  octave_scalar_map retval (m_keys);
218  retval.m_keys.orderfields (perm);
219 
220  octave_idx_type nf = nfields ();
221  for (octave_idx_type i = 0; i < nf; i++)
222  retval.m_vals[i] = m_vals[perm.xelem (i)];
223 
224  return retval;
225 }
226 
229  Array<octave_idx_type>& perm) const
230 {
231  if (m_keys.is_same (other.m_keys))
232  return *this;
233  else
234  {
235  octave_scalar_map retval (other.m_keys);
236  if (! other.m_keys.equal_up_to_order (m_keys, 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.m_vals[i] = m_vals[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 = m_keys.getfield (k);
257  if (idx >= static_cast<octave_idx_type> (m_vals.size ()))
258  m_vals.resize (idx+1);
259  return m_vals[idx];
260 }
261 
263  : m_keys (m.m_keys), m_vals (), m_dimensions (1, 1)
264 {
265  octave_idx_type nf = m.nfields ();
266  m_vals.reserve (nf);
267  for (octave_idx_type i = 0; i < nf; i++)
268  {
269  m_vals.push_back (Cell (m_dimensions));
270  m_vals[i].xelem (0) = m.m_vals[i];
271  }
272 }
273 
274 Cell
275 octave_map::getfield (const std::string& k) const
276 {
277  octave_idx_type idx = m_keys.getfield (k);
278  return (idx >= 0) ? m_vals[idx] : Cell ();
279 }
280 
281 void
282 octave_map::setfield (const std::string& k, const Cell& val)
283 {
284  if (nfields () == 0)
285  m_dimensions = val.dims ();
286 
287  if (val.dims () != m_dimensions)
288  error ("octave_map::setfield: internal error");
289 
290  octave_idx_type idx = m_keys.getfield (k);
291  if (idx < static_cast<octave_idx_type> (m_vals.size ()))
292  m_vals[idx] = val;
293  else
294  m_vals.push_back (val);
295 }
296 
297 void
298 octave_map::rmfield (const std::string& k)
299 {
300  octave_idx_type idx = m_keys.rmfield (k);
301  if (idx >= 0)
302  m_vals.erase (m_vals.begin () + idx);
303 }
304 
307 {
309  return orderfields (perm);
310 }
311 
314 {
315  octave_map retval (m_keys);
316  retval.m_keys.orderfields (perm);
317 
318  octave_idx_type nf = nfields ();
319  for (octave_idx_type i = 0; i < nf; i++)
320  retval.m_vals[i] = m_vals[perm.xelem (i)];
321 
322  return retval;
323 }
324 
327  Array<octave_idx_type>& perm) const
328 {
329  if (m_keys.is_same (other.m_keys))
330  return *this;
331  else
332  {
333  octave_map retval (other.m_keys);
334  if (! other.m_keys.equal_up_to_order (m_keys, 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.m_vals[i] = m_vals[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 = m_keys.getfield (k);
355  if (idx >= static_cast<octave_idx_type> (m_vals.size ()))
356  m_vals.push_back (Cell (m_dimensions)); // auto-set correct dims.
357  return m_vals[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.m_vals[i] = m_vals[i](idx);
367 }
368 
371 {
372  octave_scalar_map retval (m_keys);
373 
374  // Optimize this so that there is just one check.
376 
377  return retval;
378 }
379 
382 {
383  octave_scalar_map retval (m_keys);
384 
385  // Optimize this so that there is just one check.
386  extract_scalar (retval, compute_index (i, j, m_dimensions));
387 
388  return retval;
389 }
390 
393 {
394  octave_scalar_map retval (m_keys);
395 
396  // Optimize this so that there is just one check.
398 
399  return retval;
400 }
401 
404 {
405  octave_scalar_map retval (m_keys);
406 
407  extract_scalar (retval, n);
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.m_keys.is_same (m_keys))
420  {
421  for (octave_idx_type i = 0; i < nf; i++)
422  m_vals[i](n) = rhs.m_vals[i];
423 
424  retval = true;
425  }
426  else
427  {
429  if (m_keys.equal_up_to_order (rhs.m_keys, perm))
430  {
431  for (octave_idx_type i = 0; i < nf; i++)
432  m_vals[i](n) = rhs.m_vals[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 
447  retval.m_dimensions = m_dimensions.squeeze ();
448 
449  for (octave_idx_type i = 0; i < nf; i++)
450  retval.m_vals[i] = m_vals[i].squeeze ();
451 
452  retval.optimize_dimensions ();
453 
454  return retval;
455 }
456 
457 /*
458 ## test preservation of m_keys 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 {
467  octave_map retval (m_keys);
468  octave_idx_type nf = nfields ();
469 
470  for (octave_idx_type i = 0; i < nf; i++)
471  retval.m_vals[i] = m_vals[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.m_dimensions = retval.m_vals[0].dims ();
479  else
480  {
481  Array<char> dummy (m_dimensions);
482  dummy = dummy.permute (vec, inv);
483  retval.m_dimensions = dummy.dims ();
484  }
485 
486  retval.optimize_dimensions ();
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  octave_map retval (m_keys);
502 
503  retval.m_dimensions = dim_vector (m_dimensions (1), m_dimensions (0));
504 
505  octave_idx_type nf = nfields ();
506  for (octave_idx_type i = 0; i < nf; i++)
507  retval.m_vals[i] = m_vals[i].transpose ();
508 
509  retval.optimize_dimensions ();
510 
511  return retval;
512 }
513 
514 /*
515 ## test preservation of key order by transpose
516 %!test
517 %! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27;
518 %! assert (fieldnames (transpose (x)), {"d"; "a"; "f"});
519 %! assert (fieldnames (x'), {"d"; "a"; "f"});
520 %! assert (fieldnames (x.'), {"d"; "a"; "f"});
521 */
522 
525 {
526  octave_map retval (m_keys);
527  retval.m_dimensions = dv;
528 
529  // When reshaping m_vals the Array constructor chops trailing singletons,
530  // hence we need to do the same for the whole map.
532 
533  octave_idx_type nf = nfields ();
534  if (nf > 0)
535  {
536  retval.m_vals.reserve (nf);
537  for (octave_idx_type i = 0; i < nf; i++)
538  retval.m_vals[i] = m_vals[i].reshape (dv);
539  }
540  else
541  {
542  // FIXME: Do it with a dummy array, to reuse error message.
543  // Need (?) a better solution.
544  Array<char> dummy (m_dimensions);
545  dummy.reshape (dv);
546  }
547 
548  retval.optimize_dimensions ();
549 
550  return retval;
551 }
552 
553 /*
554 ## test preservation of key order by reshape
555 %!test
556 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
557 %! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"});
558 
559 ## test chopping of trailing singletons
560 %!test <*51634>
561 %! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27;
562 %! reshape (x, 3, 8, 1, 1);
563 
564 %!test <*46385>
565 %! M = repmat (struct ('a', ones (100), 'b', true), 1, 2);
566 %! M = repmat (M, 1, 2);
567 %! assert (size (M), [1, 4]);
568 
569 libinterp/corefcn/oct-map.cc
570 
571 */
572 
573 void
574 octave_map::resize (const dim_vector& dv, bool fill)
575 {
576  octave_idx_type nf = nfields ();
577  if (nf > 0)
578  {
579  for (octave_idx_type i = 0; i < nf; i++)
580  {
581  if (fill)
582  m_vals[i].resize (dv, Matrix ());
583  else
584  m_vals[i].resize (dv);
585  }
586  }
587  else
588  {
589  // FIXME: Do it with a dummy array, to reuse error message.
590  // Need (?) a better solution.
591  Array<char> dummy (m_dimensions);
592  dummy.resize (dv);
593  }
594 
595  m_dimensions = dv;
597 }
598 
599 void
601  const octave_scalar_map *map_list,
602  octave_map& retval)
603 {
604  octave_idx_type nf = retval.nfields ();
605  retval.m_vals.reserve (nf);
606 
607  dim_vector& rd = retval.m_dimensions;
608  rd.resize (dim+1, 1);
609  rd(0) = rd(1) = 1;
610  rd(dim) = n;
611 
612  for (octave_idx_type j = 0; j < nf; j++)
613  {
614  retval.m_vals.push_back (Cell (rd));
615  error_unless (retval.m_vals[j].numel () == n);
616  for (octave_idx_type i = 0; i < n; i++)
617  retval.m_vals[j].xelem (i) = map_list[i].m_vals[j];
618  }
619 }
620 
621 void
622 octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
623  octave_map& retval)
624 {
625  octave_idx_type nf = retval.nfields ();
626  retval.m_vals.reserve (nf);
627 
629 
630  for (octave_idx_type j = 0; j < nf; j++)
631  {
632  for (octave_idx_type i = 0; i < n; i++)
633  field_list[i] = map_list[i].m_vals[j];
634 
635  retval.m_vals.push_back (Array<octave_value>::cat (dim, n, field_list));
636  if (j == 0)
637  retval.m_dimensions = retval.m_vals[j].dims ();
638  }
639 }
640 
641 // This is just a wrapper.
643  const octave_scalar_map& src,
644  octave_scalar_map& dest,
646 {
647  dest = src.orderfields (ref, perm);
648 }
649 
650 // In non-scalar case, we also promote empty structs without fields.
651 void permute_to_correct_order1 (const octave_map& ref, const octave_map& src,
652  octave_map& dest, Array<octave_idx_type>& perm)
653 {
654  if (src.nfields () == 0 && src.isempty ())
655  dest = octave_map (src.dims (), ref.keys ());
656  else
657  dest = src.orderfields (ref, perm);
658 }
659 
660 template <typename map>
661 static void
663  octave_idx_type idx, const map *map_list,
664  map *new_map_list)
665 {
666  new_map_list[idx] = map_list[idx];
667 
668  Array<octave_idx_type> perm (dim_vector (1, nf));
669 
670  try
671  {
672  for (octave_idx_type i = 0; i < n; i++)
673  {
674  if (i == idx)
675  continue;
676 
677  permute_to_correct_order1 (map_list[idx], map_list[i],
678  new_map_list[i], perm);
679  }
680  }
681  catch (octave::execution_exception& ee)
682  {
683  error (ee, "cat: field names mismatch in concatenating structs");
684  }
685 }
686 
689 {
690  octave_map retval;
691 
692  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
693  if (dim == -1 || dim == -2)
694  dim = -dim - 1;
695  else if (dim < 0)
696  error ("cat: invalid dimension");
697 
698  if (n == 1)
699  retval = map_list[0];
700  else if (n > 1)
701  {
702  octave_idx_type idx, nf = 0;
703  for (idx = 0; idx < n; idx++)
704  {
705  nf = map_list[idx].nfields ();
706  if (nf > 0)
707  {
708  retval.m_keys = map_list[idx].m_keys;
709  break;
710  }
711  }
712 
713  if (nf > 0)
714  {
715  // Try the fast case.
716  bool all_same = true;
717  for (octave_idx_type i = 0; i < n; i++)
718  {
719  all_same = map_list[idx].m_keys.is_same (map_list[i].m_keys);
720  if (! all_same)
721  break;
722  }
723 
724  if (all_same)
725  do_cat (dim, n, map_list, retval);
726  else
727  {
728  // permute all structures to common order.
729  OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n);
730 
731  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
732 
733  do_cat (dim, n, new_map_list, retval);
734  }
735 
736  }
737  else
738  {
739  dim_vector& rd = retval.m_dimensions;
740  rd.resize (dim+1, 1);
741  rd(0) = rd(1) = 1;
742  rd(dim) = n;
743  }
744 
745  retval.optimize_dimensions ();
746  }
747 
748  return retval;
749 }
750 
752 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
753 {
754  octave_map retval;
755 
756  // Allow dim = -1, -2 for compatibility, though it makes no difference here.
757  if (dim == -1 || dim == -2)
758  dim = -dim - 1;
759  else if (dim < 0)
760  error ("cat: invalid dimension");
761 
762  if (n == 1)
763  retval = map_list[0];
764  else if (n > 1)
765  {
766  octave_idx_type idx, nf = 0;
767 
768  for (idx = 0; idx < n; idx++)
769  {
770  nf = map_list[idx].nfields ();
771  if (nf > 0)
772  {
773  retval.m_keys = map_list[idx].m_keys;
774  break;
775  }
776  }
777 
778  // Try the fast case.
779  bool all_same = true;
780 
781  if (nf > 0)
782  {
783  for (octave_idx_type i = 0; i < n; i++)
784  {
785  all_same = map_list[idx].m_keys.is_same (map_list[i].m_keys);
786 
787  if (! all_same)
788  break;
789  }
790  }
791 
792  if (all_same && nf > 0)
793  do_cat (dim, n, map_list, retval);
794  else
795  {
796  if (nf > 0)
797  {
798  // permute all structures to correct order.
799  OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n);
800 
801  permute_to_correct_order (n, nf, idx, map_list, new_map_list);
802 
803  do_cat (dim, n, new_map_list, retval);
804  }
805  else
806  {
807  dim_vector dv = map_list[0].m_dimensions;
808 
809  for (octave_idx_type i = 1; i < n; i++)
810  {
811  if (! dv.concat (map_list[i].m_dimensions, dim))
812  error ("dimension mismatch in struct concatenation");
813  }
814 
815  retval.m_dimensions = dv;
816  }
817  }
818 
819  retval.optimize_dimensions ();
820  }
821 
822  return retval;
823 }
824 
825 /*
826 ## test preservation of key order by concatenation
827 %!test
828 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
829 %! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33;
830 %! assert (fieldnames ([x; y]), {"d"; "a"; "f"});
831 
832 %!test
833 %! s = struct ();
834 %! sr = [s,s];
835 %! sc = [s;s];
836 %! sm = [s,s;s,s];
837 %! assert (numfields (sr), 0);
838 %! assert (numfields (sc), 0);
839 %! assert (numfields (sm), 0);
840 %! assert (size (sr), [1, 2]);
841 %! assert (size (sc), [2, 1]);
842 %! assert (size (sm), [2, 2]);
843 */
844 
846 octave_map::index (const octave::idx_vector& i, bool resize_ok) const
847 {
848  octave_map retval (m_keys);
849  octave_idx_type nf = nfields ();
850 
851  for (octave_idx_type k = 0; k < nf; k++)
852  retval.m_vals[k] = m_vals[k].index (i, resize_ok);
853 
854  if (nf > 0)
855  retval.m_dimensions = retval.m_vals[0].dims ();
856  else
857  {
858  // Use dummy array. FIXME: Need(?) a better solution.
859  Array<char> dummy (m_dimensions);
860  dummy = dummy.index (i, resize_ok);
861  retval.m_dimensions = dummy.dims ();
862  }
863 
864  retval.optimize_dimensions ();
865 
866  return retval;
867 }
868 
871  bool resize_ok) const
872 {
873  octave_map retval (m_keys);
874  octave_idx_type nf = nfields ();
875 
876  for (octave_idx_type k = 0; k < nf; k++)
877  retval.m_vals[k] = m_vals[k].index (i, j, resize_ok);
878 
879  if (nf > 0)
880  retval.m_dimensions = retval.m_vals[0].dims ();
881  else
882  {
883  // Use dummy array. FIXME: Need(?) a better solution.
884  Array<char> dummy (m_dimensions);
885  dummy = dummy.index (i, j, resize_ok);
886  retval.m_dimensions = dummy.dims ();
887  }
888 
889  retval.optimize_dimensions ();
890 
891  return retval;
892 }
893 
895 octave_map::index (const Array<octave::idx_vector>& ia, bool resize_ok) const
896 {
897  octave_map retval (m_keys);
898  octave_idx_type nf = nfields ();
899 
900  for (octave_idx_type k = 0; k < nf; k++)
901  retval.m_vals[k] = m_vals[k].index (ia, resize_ok);
902 
903  if (nf > 0)
904  retval.m_dimensions = retval.m_vals[0].dims ();
905  else
906  {
907  // Use dummy array. FIXME: Need(?) a better solution.
908  Array<char> dummy (m_dimensions);
909  dummy = dummy.index (ia, resize_ok);
910  retval.m_dimensions = dummy.dims ();
911  }
912 
913  retval.optimize_dimensions ();
914 
915  return retval;
916 }
917 
919 octave_map::index (const octave_value_list& idx, bool resize_ok) const
920 {
921  octave_idx_type n_idx = idx.length ();
922  octave_map retval;
923 
924  // If we catch an indexing error in index_vector, we flag an error in
925  // index k. Ensure it is the right value before each idx_vector call.
926  // Same variable as used in the for loop in the default case.
927 
928  octave_idx_type k = 0;
929 
930  try
931  {
932  switch (n_idx)
933  {
934  case 1:
935  {
936  octave::idx_vector i = idx(0).index_vector ();
937 
938  retval = index (i, resize_ok);
939  }
940  break;
941 
942  case 2:
943  {
944  octave::idx_vector i = idx(0).index_vector ();
945 
946  k = 1;
947  octave::idx_vector j = idx(1).index_vector ();
948 
949  retval = index (i, j, resize_ok);
950  }
951  break;
952 
953  default:
954  {
955  Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
956 
957  for (k = 0; k < n_idx; k++)
958  ia(k) = idx(k).index_vector ();
959 
960  retval = index (ia, resize_ok);
961  }
962  break;
963  }
964  }
965  catch (octave::index_exception& ie)
966  {
967  // Rethrow to allow more info to be reported later.
968  ie.set_pos_if_unset (n_idx, k+1);
969  throw;
970  }
971 
972  return retval;
973 }
974 
975 // Perhaps one day these will be optimized. Right now, they just call index.
978 {
979  return index (octave::idx_vector::colon, k);
980 }
981 
984 {
985  static Array<octave::idx_vector> ia (dim_vector (3, 1),
986  octave::idx_vector::colon);
987 
988  ia(2) = k;
989  return index (ia);
990 }
991 
992 void
994 {
995  if (rhs.m_keys.is_same (m_keys))
996  {
997  octave_idx_type nf = nfields ();
998 
999  for (octave_idx_type k = 0; k < nf; k++)
1000  m_vals[k].assign (i, rhs.m_vals[k], Matrix ());
1001 
1002  if (nf > 0)
1003  m_dimensions = m_vals[0].dims ();
1004  else
1005  {
1006  // Use dummy array. FIXME: Need(?) a better solution.
1007  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1008  dummy.assign (i, rhs_dummy);;
1009  m_dimensions = dummy.dims ();
1010  }
1011 
1013  }
1014  else if (nfields () == 0)
1015  {
1016  octave_map tmp (m_dimensions, rhs.m_keys);
1017  tmp.assign (i, rhs);
1018  *this = tmp;
1019  }
1020  else
1021  {
1023  octave_map rhs1;
1024 
1025  try
1026  {
1027  rhs1 = rhs.orderfields (*this, perm);
1028  }
1029  catch (octave::execution_exception& ee)
1030  {
1031  error (ee, "incompatible fields in struct assignment");
1032  }
1033 
1034  error_unless (rhs1.m_keys.is_same (m_keys));
1035  assign (i, rhs1);
1036  }
1037 }
1038 
1039 void
1041  const octave_map& rhs)
1042 {
1043  if (rhs.m_keys.is_same (m_keys))
1044  {
1045  octave_idx_type nf = nfields ();
1046 
1047  for (octave_idx_type k = 0; k < nf; k++)
1048  m_vals[k].assign (i, j, rhs.m_vals[k], Matrix ());
1049 
1050  if (nf > 0)
1051  m_dimensions = m_vals[0].dims ();
1052  else
1053  {
1054  // Use dummy array. FIXME: Need(?) a better solution.
1055  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1056  dummy.assign (i, j, rhs_dummy);;
1057  m_dimensions = dummy.dims ();
1058  }
1059 
1061  }
1062  else if (nfields () == 0)
1063  {
1064  octave_map tmp (m_dimensions, rhs.m_keys);
1065  tmp.assign (i, j, rhs);
1066  *this = tmp;
1067  }
1068  else
1069  {
1071  octave_map rhs1;
1072 
1073  try
1074  {
1075  rhs1 = rhs.orderfields (*this, perm);
1076  }
1077  catch (octave::execution_exception& ee)
1078  {
1079  error (ee, "incompatible fields in struct assignment");
1080  }
1081 
1082  error_unless (rhs1.m_keys.is_same (m_keys));
1083  assign (i, j, rhs1);
1084  }
1085 }
1086 
1087 void
1089  const octave_map& rhs)
1090 {
1091  if (rhs.m_keys.is_same (m_keys))
1092  {
1093  octave_idx_type nf = nfields ();
1094 
1095  for (octave_idx_type k = 0; k < nf; k++)
1096  m_vals[k].assign (ia, rhs.m_vals[k], Matrix ());
1097 
1098  if (nf > 0)
1099  m_dimensions = m_vals[0].dims ();
1100  else
1101  {
1102  // Use dummy array. FIXME: Need(?) a better solution.
1103  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1104  dummy.assign (ia, rhs_dummy);;
1105  m_dimensions = dummy.dims ();
1106  }
1107 
1109  }
1110  else if (nfields () == 0)
1111  {
1112  octave_map tmp (m_dimensions, rhs.m_keys);
1113  tmp.assign (ia, rhs);
1114  *this = tmp;
1115  }
1116  else
1117  {
1119  octave_map rhs1;
1120 
1121  try
1122  {
1123  rhs1 = rhs.orderfields (*this, perm);
1124  }
1125  catch (octave::execution_exception& ee)
1126  {
1127  error (ee, "incompatible fields in struct assignment");
1128  }
1129 
1130  error_unless (rhs1.m_keys.is_same (m_keys));
1131  assign (ia, rhs1);
1132  }
1133 }
1134 
1135 void
1137 {
1138  octave_idx_type n_idx = idx.length ();
1139 
1140  // If we catch an indexing error in index_vector, we flag an error in
1141  // index k. Ensure it is the right value before each idx_vector call.
1142  // Same variable as used in the for loop in the default case.
1143 
1144  octave_idx_type k = 0;
1145 
1146  try
1147  {
1148  switch (n_idx)
1149  {
1150  case 1:
1151  {
1152  octave::idx_vector i = idx(0).index_vector ();
1153 
1154  assign (i, rhs);
1155  }
1156  break;
1157 
1158  case 2:
1159  {
1160  octave::idx_vector i = idx(0).index_vector ();
1161 
1162  k = 1;
1163  octave::idx_vector j = idx(1).index_vector ();
1164 
1165  assign (i, j, rhs);
1166  }
1167  break;
1168 
1169  default:
1170  {
1171  Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
1172 
1173  for (k = 0; k < n_idx; k++)
1174  ia(k) = idx(k).index_vector ();
1175 
1176  assign (ia, rhs);
1177  }
1178  break;
1179  }
1180  }
1181  catch (octave::index_exception& ie)
1182  {
1183  // Rethrow to allow more info to be reported later.
1184  ie.set_pos_if_unset (n_idx, k+1);
1185  throw;
1186  }
1187 }
1188 
1189 void
1190 octave_map::assign (const octave_value_list& idx, const std::string& k,
1191  const Cell& rhs)
1192 {
1193  Cell tmp;
1194  auto p = seek (k);
1195  Cell& ref = (p != end () ? contents (p) : tmp);
1196 
1197  if (&ref == &tmp)
1198  ref = Cell (m_dimensions);
1199 
1200  ref.assign (idx, rhs);
1201 
1202  if (ref.dims () != m_dimensions)
1203  {
1204  m_dimensions = ref.dims ();
1205 
1206  octave_idx_type nf = nfields ();
1207  for (octave_idx_type i = 0; i < nf; i++)
1208  {
1209  if (&m_vals[i] != &ref)
1210  m_vals[i].resize (m_dimensions, Matrix ());
1211  }
1212 
1214  }
1215 
1216  if (&ref == &tmp)
1217  setfield (k, tmp);
1218 }
1219 
1220 /*
1221 %!test
1222 %! rhs.b = 1;
1223 %! a(3) = rhs;
1224 %! assert ({a.b}, {[], [], 1});
1225 */
1226 
1227 void
1229 {
1230  octave_idx_type nf = nfields ();
1231  for (octave_idx_type k = 0; k < nf; k++)
1232  m_vals[k].delete_elements (i);
1233 
1234  if (nf > 0)
1235  m_dimensions = m_vals[0].dims ();
1236  else
1237  {
1238  // Use dummy array. FIXME: Need(?) a better solution.
1239  Array<char> dummy (m_dimensions);
1240  dummy.delete_elements (i);
1241  m_dimensions = dummy.dims ();
1242  }
1243 
1245 }
1246 
1247 void
1249 {
1250  octave_idx_type nf = nfields ();
1251  for (octave_idx_type k = 0; k < nf; k++)
1252  m_vals[k].delete_elements (dim, i);
1253 
1254  if (nf > 0)
1255  m_dimensions = m_vals[0].dims ();
1256  else
1257  {
1258  // Use dummy array. FIXME: Need(?) a better solution.
1259  Array<char> dummy (m_dimensions);
1260  dummy.delete_elements (dim, i);
1261  m_dimensions = dummy.dims ();
1262  }
1263 
1265 }
1266 
1267 void
1269 {
1270  octave_idx_type nf = nfields ();
1271  for (octave_idx_type k = 0; k < nf; k++)
1272  m_vals[k].delete_elements (ia);
1273 
1274  if (nf > 0)
1275  m_dimensions = m_vals[0].dims ();
1276  else
1277  {
1278  // Use dummy array. FIXME: Need(?) a better solution.
1279  Array<char> dummy (m_dimensions);
1280  dummy.delete_elements (ia);
1281  m_dimensions = dummy.dims ();
1282  }
1283 
1285 }
1286 
1287 void
1289 {
1290  octave_idx_type n_idx = idx.length ();
1291 
1292  Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
1293 
1294  for (octave_idx_type i = 0; i < n_idx; i++)
1295  {
1296  try
1297  {
1298  ia(i) = idx(i).index_vector ();
1299  }
1300  catch (octave::index_exception& ie)
1301  {
1302  // Rethrow to allow more info to be reported later.
1303  ie.set_pos_if_unset (n_idx, i+1);
1304  throw;
1305  }
1306  }
1307 
1308  delete_elements (ia);
1309 }
1310 
1311 /*
1312 ## test preservation of key order by indexing
1313 %!test
1314 %! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27;
1315 %! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"});
1316 */
1317 
1318 octave_map
1320 {
1321  if (nfields () == rb.nfields ())
1322  {
1323  for (auto pa = cbegin (); pa != cend (); pa++)
1324  {
1325  auto pb = rb.seek (key (pa));
1326 
1327  if (pb == rb.cend ())
1328  error ("field name mismatch in structure concatenation");
1329 
1330  contents(pa).insert (rb.contents (pb), ra_idx);
1331  }
1332  }
1333  else
1334  {
1335  dim_vector dv = dims ();
1336 
1337  if (dv.all_zero ())
1338  *this = rb;
1339  else if (! rb.dims ().all_zero ())
1340  error ("invalid structure concatenation");
1341  }
1342 
1343  return *this;
1344 }
1345 
1346 void
1348 {
1349  octave_idx_type nf = nfields ();
1350 
1351  for (octave_idx_type i = 0; i < nf; i++)
1352  {
1354  error ("internal error: dimension mismatch across fields in struct");
1355  }
1356 
1357 }
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:177
OCTARRAY_API void clear(void)
Definition: Array-base.cc:109
OCTARRAY_API Array< T, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
Definition: Array-base.cc:719
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_OVERRIDABLE_FUNC_API const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
OCTARRAY_API void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1032
OCTARRAY_OVERRIDABLE_FUNC_API Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:635
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array-base.cc:1766
OCTARRAY_API void delete_elements(const octave::idx_vector &i)
Deleting elements.
Definition: Array-base.cc:1416
OCTARRAY_API Array< T, Alloc > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
Definition: Array-base.cc:453
OCTARRAY_OVERRIDABLE_FUNC_API T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
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:94
OCTAVE_API bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:140
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
bool all_zero(void) const
Definition: dim-vector.h:300
void chop_trailing_singletons(void)
Definition: dim-vector.h:164
OCTAVE_API dim_vector squeeze(void) const
Definition: dim-vector.cc:117
void orderfields(Array< octave_idx_type > &perm)
Definition: oct-map.cc:110
const_iterator begin(void) const
Definition: oct-map.h:108
fields_rep * m_rep
Definition: oct-map.h:58
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
void make_unique(void)
Definition: oct-map.h:74
void resize(const dim_vector &dv, bool fill=false)
Definition: oct-map.cc:574
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:600
void rmfield(const std::string &key)
Definition: oct-map.cc:298
octave_fields m_keys
Definition: oct-map.h:490
octave_scalar_map fast_elem_extract(octave_idx_type n) const
Definition: oct-map.cc:403
octave_map reshape(const dim_vector &dv) const
Definition: oct-map.cc:524
octave_idx_type nfields(void) const
Definition: oct-map.h:344
void optimize_dimensions(void)
Definition: oct-map.cc:1347
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 delete_elements(const octave::idx_vector &i)
Definition: oct-map.cc:1228
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:983
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:1319
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
dim_vector m_dimensions
Definition: oct-map.h:492
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
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
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:688
octave_map(void)
Definition: oct-map.h:288
octave_scalar_map elem(octave_idx_type n) const
Definition: oct-map.cc:370
std::vector< Cell > m_vals
Definition: oct-map.h:491
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:977
octave_map squeeze(void) const
Definition: oct-map.cc:442
octave_fields m_keys
Definition: oct-map.h:265
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
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
std::vector< octave_value > m_vals
Definition: oct-map.h:266
octave_scalar_map(void)
Definition: oct-map.h:168
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
octave_idx_type length(void) const
Definition: ovl.h:113
std::string & xelem(octave_idx_type i)
Definition: str-vec.h:108
octave_idx_type numel(void) const
Definition: str-vec.h:100
void error(const char *fmt,...)
Definition: error.cc:979
void error_unless(bool cond)
Definition: error.h:549
octave::idx_vector idx_vector
Definition: idx-vector.h:1039
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:642
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:662
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()) ? '\'' :'"'))