GNU Octave  9.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-2024 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 
38 octave_fields::fields_rep *
39 octave_fields::nil_rep ()
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
361 octave_map::extract_scalar (octave_scalar_map& dest,
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.
375  extract_scalar (retval, compute_index (n, m_dimensions));
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.
397  extract_scalar (retval, compute_index (ra_idx, m_dimensions));
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.
531  retval.m_dimensions.chop_trailing_singletons ();
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;
596  optimize_dimensions ();
597 }
598 
599 void
600 octave_map::do_cat (int dim, octave_idx_type n,
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.
642 void
644  const octave_scalar_map& src,
645  octave_scalar_map& dest,
647 {
648  dest = src.orderfields (ref, perm);
649 }
650 
651 // In non-scalar case, we also promote empty structs without fields.
652 void
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
664 permute_to_correct_order (octave_idx_type n, octave_idx_type nf,
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& ee)
684  {
685  error (ee, "cat: field names mismatch in concatenating structs");
686  }
687 }
688 
691 {
692  octave_map retval;
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.m_keys = map_list[idx].m_keys;
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].m_keys.is_same (map_list[i].m_keys);
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  {
741  dim_vector& rd = retval.m_dimensions;
742  rd.resize (dim+1, 1);
743  rd(0) = rd(1) = 1;
744  rd(dim) = n;
745  }
746 
747  retval.optimize_dimensions ();
748  }
749 
750  return retval;
751 }
752 
754 octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list)
755 {
756  octave_map retval;
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.m_keys = map_list[idx].m_keys;
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].m_keys.is_same (map_list[i].m_keys);
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].m_dimensions;
810 
811  for (octave_idx_type i = 1; i < n; i++)
812  {
813  if (! dv.concat (map_list[i].m_dimensions, dim))
814  error ("dimension mismatch in struct concatenation");
815  }
816 
817  retval.m_dimensions = dv;
818  }
819  }
820 
821  retval.optimize_dimensions ();
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 octave::idx_vector& i, bool resize_ok) const
849 {
850  octave_map retval (m_keys);
851  octave_idx_type nf = nfields ();
852 
853  for (octave_idx_type k = 0; k < nf; k++)
854  retval.m_vals[k] = m_vals[k].index (i, resize_ok);
855 
856  if (nf > 0)
857  retval.m_dimensions = retval.m_vals[0].dims ();
858  else
859  {
860  // Use dummy array. FIXME: Need(?) a better solution.
861  Array<char> dummy (m_dimensions);
862  dummy = dummy.index (i, resize_ok);
863  retval.m_dimensions = dummy.dims ();
864  }
865 
866  retval.optimize_dimensions ();
867 
868  return retval;
869 }
870 
873  bool resize_ok) const
874 {
875  octave_map retval (m_keys);
876  octave_idx_type nf = nfields ();
877 
878  for (octave_idx_type k = 0; k < nf; k++)
879  retval.m_vals[k] = m_vals[k].index (i, j, resize_ok);
880 
881  if (nf > 0)
882  retval.m_dimensions = retval.m_vals[0].dims ();
883  else
884  {
885  // Use dummy array. FIXME: Need(?) a better solution.
886  Array<char> dummy (m_dimensions);
887  dummy = dummy.index (i, j, resize_ok);
888  retval.m_dimensions = dummy.dims ();
889  }
890 
891  retval.optimize_dimensions ();
892 
893  return retval;
894 }
895 
897 octave_map::index (const Array<octave::idx_vector>& ia, bool resize_ok) const
898 {
899  octave_map retval (m_keys);
900  octave_idx_type nf = nfields ();
901 
902  for (octave_idx_type k = 0; k < nf; k++)
903  retval.m_vals[k] = m_vals[k].index (ia, resize_ok);
904 
905  if (nf > 0)
906  retval.m_dimensions = retval.m_vals[0].dims ();
907  else
908  {
909  // Use dummy array. FIXME: Need(?) a better solution.
910  Array<char> dummy (m_dimensions);
911  dummy = dummy.index (ia, resize_ok);
912  retval.m_dimensions = dummy.dims ();
913  }
914 
915  retval.optimize_dimensions ();
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 ();
924  octave_map retval;
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  octave::idx_vector i = idx(0).index_vector ();
939 
940  retval = index (i, resize_ok);
941  }
942  break;
943 
944  case 2:
945  {
946  octave::idx_vector i = idx(0).index_vector ();
947 
948  k = 1;
949  octave::idx_vector j = idx(1).index_vector ();
950 
951  retval = index (i, j, resize_ok);
952  }
953  break;
954 
955  default:
956  {
957  Array<octave::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& ie)
968  {
969  // Rethrow to allow more info to be reported later.
970  ie.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 (octave::idx_vector::colon, k);
982 }
983 
986 {
987  static Array<octave::idx_vector> ia (dim_vector (3, 1),
988  octave::idx_vector::colon);
989 
990  ia(2) = k;
991  return index (ia);
992 }
993 
994 void
996 {
997  if (rhs.m_keys.is_same (m_keys))
998  {
999  octave_idx_type nf = nfields ();
1000 
1001  for (octave_idx_type k = 0; k < nf; k++)
1002  m_vals[k].assign (i, rhs.m_vals[k], Matrix ());
1003 
1004  if (nf > 0)
1005  m_dimensions = m_vals[0].dims ();
1006  else
1007  {
1008  // Use dummy array. FIXME: Need(?) a better solution.
1009  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1010  dummy.assign (i, rhs_dummy);
1011  m_dimensions = dummy.dims ();
1012  }
1013 
1014  optimize_dimensions ();
1015  }
1016  else if (nfields () == 0)
1017  {
1018  octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1032  {
1033  error (ee, "incompatible fields in struct assignment");
1034  }
1035 
1036  error_unless (rhs1.m_keys.is_same (m_keys));
1037  assign (i, rhs1);
1038  }
1039 }
1040 
1041 void
1043  const octave_map& rhs)
1044 {
1045  if (rhs.m_keys.is_same (m_keys))
1046  {
1047  octave_idx_type nf = nfields ();
1048 
1049  for (octave_idx_type k = 0; k < nf; k++)
1050  m_vals[k].assign (i, j, rhs.m_vals[k], Matrix ());
1051 
1052  if (nf > 0)
1053  m_dimensions = m_vals[0].dims ();
1054  else
1055  {
1056  // Use dummy array. FIXME: Need(?) a better solution.
1057  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1058  dummy.assign (i, j, rhs_dummy);
1059  m_dimensions = dummy.dims ();
1060  }
1061 
1062  optimize_dimensions ();
1063  }
1064  else if (nfields () == 0)
1065  {
1066  octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1080  {
1081  error (ee, "incompatible fields in struct assignment");
1082  }
1083 
1084  error_unless (rhs1.m_keys.is_same (m_keys));
1085  assign (i, j, rhs1);
1086  }
1087 }
1088 
1089 void
1091  const octave_map& rhs)
1092 {
1093  if (rhs.m_keys.is_same (m_keys))
1094  {
1095  octave_idx_type nf = nfields ();
1096 
1097  for (octave_idx_type k = 0; k < nf; k++)
1098  m_vals[k].assign (ia, rhs.m_vals[k], Matrix ());
1099 
1100  if (nf > 0)
1101  m_dimensions = m_vals[0].dims ();
1102  else
1103  {
1104  // Use dummy array. FIXME: Need(?) a better solution.
1105  Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1106  dummy.assign (ia, rhs_dummy);
1107  m_dimensions = dummy.dims ();
1108  }
1109 
1110  optimize_dimensions ();
1111  }
1112  else if (nfields () == 0)
1113  {
1114  octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1128  {
1129  error (ee, "incompatible fields in struct assignment");
1130  }
1131 
1132  error_unless (rhs1.m_keys.is_same (m_keys));
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 before 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  octave::idx_vector i = idx(0).index_vector ();
1155 
1156  assign (i, rhs);
1157  }
1158  break;
1159 
1160  case 2:
1161  {
1162  octave::idx_vector i = idx(0).index_vector ();
1163 
1164  k = 1;
1165  octave::idx_vector j = idx(1).index_vector ();
1166 
1167  assign (i, j, rhs);
1168  }
1169  break;
1170 
1171  default:
1172  {
1173  Array<octave::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& ie)
1184  {
1185  // Rethrow to allow more info to be reported later.
1186  ie.set_pos_if_unset (n_idx, k+1);
1187  throw;
1188  }
1189 }
1190 
1191 void
1192 octave_map::assign (const octave_value_list& idx, const std::string& k,
1193  const Cell& rhs)
1194 {
1195  Cell tmp;
1196  auto p = seek (k);
1197  Cell& ref = (p != end () ? contents (p) : tmp);
1198 
1199  if (&ref == &tmp)
1200  ref = Cell (m_dimensions);
1201 
1202  ref.assign (idx, rhs);
1203 
1204  if (ref.dims () != m_dimensions)
1205  {
1206  m_dimensions = ref.dims ();
1207 
1208  octave_idx_type nf = nfields ();
1209  for (octave_idx_type i = 0; i < nf; i++)
1210  {
1211  if (&m_vals[i] != &ref)
1212  m_vals[i].resize (m_dimensions, Matrix ());
1213  }
1214 
1215  optimize_dimensions ();
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  m_vals[k].delete_elements (i);
1235 
1236  if (nf > 0)
1237  m_dimensions = m_vals[0].dims ();
1238  else
1239  {
1240  // Use dummy array. FIXME: Need(?) a better solution.
1241  Array<char> dummy (m_dimensions);
1242  dummy.delete_elements (i);
1243  m_dimensions = dummy.dims ();
1244  }
1245 
1246  optimize_dimensions ();
1247 }
1248 
1249 void
1251 {
1252  octave_idx_type nf = nfields ();
1253  for (octave_idx_type k = 0; k < nf; k++)
1254  m_vals[k].delete_elements (dim, i);
1255 
1256  if (nf > 0)
1257  m_dimensions = m_vals[0].dims ();
1258  else
1259  {
1260  // Use dummy array. FIXME: Need(?) a better solution.
1261  Array<char> dummy (m_dimensions);
1262  dummy.delete_elements (dim, i);
1263  m_dimensions = dummy.dims ();
1264  }
1265 
1266  optimize_dimensions ();
1267 }
1268 
1269 void
1271 {
1272  octave_idx_type nf = nfields ();
1273  for (octave_idx_type k = 0; k < nf; k++)
1274  m_vals[k].delete_elements (ia);
1275 
1276  if (nf > 0)
1277  m_dimensions = m_vals[0].dims ();
1278  else
1279  {
1280  // Use dummy array. FIXME: Need(?) a better solution.
1281  Array<char> dummy (m_dimensions);
1282  dummy.delete_elements (ia);
1283  m_dimensions = dummy.dims ();
1284  }
1285 
1286  optimize_dimensions ();
1287 }
1288 
1289 void
1291 {
1292  octave_idx_type n_idx = idx.length ();
1293 
1294  Array<octave::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& ie)
1303  {
1304  // Rethrow to allow more info to be reported later.
1305  ie.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 (auto pa = cbegin (); pa != cend (); pa++)
1326  {
1327  auto pb = rb.seek (key (pa));
1328 
1329  if (pb == rb.cend ())
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
1349 octave_map::optimize_dimensions ()
1350 {
1351  octave_idx_type nf = nfields ();
1352 
1353  for (octave_idx_type i = 0; i < nf; i++)
1354  {
1355  if (! m_vals[i].optimize_dimensions (m_dimensions))
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:177
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
Array< T, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
Definition: Array-base.cc:710
void clear()
Definition: Array-base.cc:109
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
void delete_elements(const octave::idx_vector &i)
Deleting elements.
Definition: Array-base.cc:1407
Array< T, Alloc > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
Definition: Array-base.cc:450
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:635
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
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
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:140
void chop_trailing_singletons()
Definition: dim-vector.h:164
dim_vector squeeze() const
Definition: dim-vector.cc:117
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
bool all_zero() const
Definition: dim-vector.h:300
void orderfields(Array< octave_idx_type > &perm)
Definition: oct-map.cc:110
octave_idx_type rmfield(const std::string &name)
Definition: oct-map.cc:89
const_iterator end() const
Definition: oct-map.h:112
void make_unique()
Definition: oct-map.h:77
const_iterator begin() const
Definition: oct-map.h:111
octave_idx_type nfields() const
Definition: oct-map.h:126
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:151
bool isfield(const std::string &name) const
Definition: oct-map.cc:62
string_vector fieldnames() const
Definition: oct-map.cc:158
octave_fields()
Definition: oct-map.h:67
octave_idx_type getfield(const std::string &name) const
Definition: oct-map.cc:68
const_iterator cbegin() const
Definition: oct-map.h:300
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
void rmfield(const std::string &key)
Definition: oct-map.cc:298
octave_idx_type nfields() const
Definition: oct-map.h:323
octave_map squeeze() const
Definition: oct-map.cc:442
octave_scalar_map fast_elem_extract(octave_idx_type n) const
Definition: oct-map.cc:403
const_iterator end() const
Definition: oct-map.h:298
string_vector keys() const
Definition: oct-map.h:335
octave_map reshape(const dim_vector &dv) const
Definition: oct-map.cc:524
dim_vector dims() const
Definition: oct-map.h:409
octave_map permute(const Array< int > &vec, bool inv=false) const
Definition: oct-map.cc:465
octave_map orderfields() const
Definition: oct-map.cc:306
void delete_elements(const octave::idx_vector &i)
Definition: oct-map.cc:1230
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:303
octave_map concat(const octave_map &rb, const Array< octave_idx_type > &ra_idx)
Definition: oct-map.cc:1321
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:344
std::string key(const_iterator p) const
Definition: oct-map.h:305
octave_map transpose() const
Definition: oct-map.cc:499
const Cell & contents(const_iterator p) const
Definition: oct-map.h:310
bool fast_elem_insert(octave_idx_type n, const octave_scalar_map &rhs)
Definition: oct-map.cc:413
const_iterator cend() const
Definition: oct-map.h:301
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:690
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:307
octave_map(const octave_fields &k)
Definition: oct-map.h:271
octave_map column(octave_idx_type k) const
Definition: oct-map.cc:979
bool isempty() const
Definition: oct-map.h:370
octave_scalar_map(const octave_fields &k)
Definition: oct-map.h:168
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:197
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_idx_type nfields() const
Definition: oct-map.h:210
octave_scalar_map orderfields() const
Definition: oct-map.cc:208
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
octave_idx_type length() const
Definition: ovl.h:113
std::string & xelem(octave_idx_type i)
Definition: str-vec.h:108
octave_idx_type numel() const
Definition: str-vec.h:100
void() error(const char *fmt,...)
Definition: error.cc:988
#define error_unless(cond)
Definition: error.h:530
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
#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:643
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()) ? '\'' :'"'))