GNU Octave 7.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-2022 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
53octave_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
61bool
62octave_fields::isfield (const std::string& field) const
63{
64 return m_rep->find (field) != m_rep->end ();
65}
66
68octave_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
75octave_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
89octave_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
109void
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
125bool
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
146bool
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
183octave_scalar_map::getfield (const std::string& k) const
184{
186 return (idx >= 0) ? m_vals[idx] : octave_value ();
187}
188
189void
190octave_scalar_map::setfield (const std::string& k, const octave_value& val)
191{
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
199void
200octave_scalar_map::rmfield (const std::string& k)
201{
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
248octave_scalar_map::contents (const std::string& k) const
249{
250 return getfield (k);
251}
252
254octave_scalar_map::contents (const std::string& k)
255{
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
274Cell
275octave_map::getfield (const std::string& k) const
276{
278 return (idx >= 0) ? m_vals[idx] : Cell ();
279}
280
281void
282octave_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
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
297void
298octave_map::rmfield (const std::string& k)
299{
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
345Cell
346octave_map::contents (const std::string& k) const
347{
348 return getfield (k);
349}
350
351Cell&
352octave_map::contents (const std::string& k)
353{
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
360void
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
412bool
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
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
465octave_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 {
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 assert (ndims () == 2);
502
503 octave_map retval (m_keys);
504
506
507 octave_idx_type nf = nfields ();
508 for (octave_idx_type i = 0; i < nf; i++)
509 retval.m_vals[i] = m_vals[i].transpose ();
510
511 retval.optimize_dimensions ();
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{
528 octave_map retval (m_keys);
529 retval.m_dimensions = dv;
530
531 // When reshaping m_vals 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.m_vals.reserve (nf);
539 for (octave_idx_type i = 0; i < nf; i++)
540 retval.m_vals[i] = m_vals[i].reshape (dv);
541 }
542 else
543 {
544 // FIXME: Do it with a dummy array, to reuse error message.
545 // Need (?) a better solution.
547 dummy.reshape (dv);
548 }
549
550 retval.optimize_dimensions ();
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
571libinterp/corefcn/oct-map.cc
572
573*/
574
575void
576octave_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 m_vals[i].resize (dv, Matrix ());
585 else
586 m_vals[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.
594 dummy.resize (dv);
595 }
596
597 m_dimensions = dv;
599}
600
601void
603 const octave_scalar_map *map_list,
604 octave_map& retval)
605{
606 octave_idx_type nf = retval.nfields ();
607 retval.m_vals.reserve (nf);
608
609 dim_vector& rd = retval.m_dimensions;
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.m_vals.push_back (Cell (rd));
617 assert (retval.m_vals[j].numel () == n);
618 for (octave_idx_type i = 0; i < n; i++)
619 retval.m_vals[j].xelem (i) = map_list[i].m_vals[j];
620 }
621}
622
623void
624octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list,
625 octave_map& retval)
626{
627 octave_idx_type nf = retval.nfields ();
628 retval.m_vals.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].m_vals[j];
636
637 retval.m_vals.push_back (Array<octave_value>::cat (dim, n, field_list));
638 if (j == 0)
639 retval.m_dimensions = retval.m_vals[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.
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
662template <typename map>
663static 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& 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
754octave_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
848octave_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.
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.
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
897octave_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.
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
921octave_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 {
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{
982}
983
986{
988
989 ia(2) = k;
990 return index (ia);
991}
992
993void
995{
996 if (rhs.m_keys.is_same (m_keys))
997 {
998 octave_idx_type nf = nfields ();
999
1000 for (octave_idx_type k = 0; k < nf; k++)
1001 m_vals[k].assign (i, rhs.m_vals[k], Matrix ());
1002
1003 if (nf > 0)
1004 m_dimensions = m_vals[0].dims ();
1005 else
1006 {
1007 // Use dummy array. FIXME: Need(?) a better solution.
1008 Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1009 dummy.assign (i, rhs_dummy);;
1010 m_dimensions = dummy.dims ();
1011 }
1012
1014 }
1015 else if (nfields () == 0)
1016 {
1017 octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1031 {
1032 error (ee, "incompatible fields in struct assignment");
1033 }
1034
1035 assert (rhs1.m_keys.is_same (m_keys));
1036 assign (i, rhs1);
1037 }
1038}
1039
1040void
1042 const octave_map& rhs)
1043{
1044 if (rhs.m_keys.is_same (m_keys))
1045 {
1046 octave_idx_type nf = nfields ();
1047
1048 for (octave_idx_type k = 0; k < nf; k++)
1049 m_vals[k].assign (i, j, rhs.m_vals[k], Matrix ());
1050
1051 if (nf > 0)
1052 m_dimensions = m_vals[0].dims ();
1053 else
1054 {
1055 // Use dummy array. FIXME: Need(?) a better solution.
1056 Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1057 dummy.assign (i, j, rhs_dummy);;
1058 m_dimensions = dummy.dims ();
1059 }
1060
1062 }
1063 else if (nfields () == 0)
1064 {
1065 octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1079 {
1080 error (ee, "incompatible fields in struct assignment");
1081 }
1082
1083 assert (rhs1.m_keys.is_same (m_keys));
1084 assign (i, j, rhs1);
1085 }
1086}
1087
1088void
1090 const octave_map& rhs)
1091{
1092 if (rhs.m_keys.is_same (m_keys))
1093 {
1094 octave_idx_type nf = nfields ();
1095
1096 for (octave_idx_type k = 0; k < nf; k++)
1097 m_vals[k].assign (ia, rhs.m_vals[k], Matrix ());
1098
1099 if (nf > 0)
1100 m_dimensions = m_vals[0].dims ();
1101 else
1102 {
1103 // Use dummy array. FIXME: Need(?) a better solution.
1104 Array<char> dummy (m_dimensions), rhs_dummy (rhs.m_dimensions);
1105 dummy.assign (ia, rhs_dummy);;
1106 m_dimensions = dummy.dims ();
1107 }
1108
1110 }
1111 else if (nfields () == 0)
1112 {
1113 octave_map tmp (m_dimensions, rhs.m_keys);
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& ee)
1127 {
1128 error (ee, "incompatible fields in struct assignment");
1129 }
1130
1131 assert (rhs1.m_keys.is_same (m_keys));
1132 assign (ia, rhs1);
1133 }
1134}
1135
1136void
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 octave::idx_vector i = idx(0).index_vector ();
1154
1155 assign (i, rhs);
1156 }
1157 break;
1158
1159 case 2:
1160 {
1161 octave::idx_vector i = idx(0).index_vector ();
1162
1163 k = 1;
1164 octave::idx_vector j = idx(1).index_vector ();
1165
1166 assign (i, j, rhs);
1167 }
1168 break;
1169
1170 default:
1171 {
1172 Array<octave::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& ie)
1183 {
1184 // Rethrow to allow more info to be reported later.
1185 ie.set_pos_if_unset (n_idx, k+1);
1186 throw;
1187 }
1188}
1189
1190void
1191octave_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 (m_dimensions);
1200
1201 ref.assign (idx, rhs);
1202
1203 if (ref.dims () != m_dimensions)
1204 {
1205 m_dimensions = ref.dims ();
1206
1207 octave_idx_type nf = nfields ();
1208 for (octave_idx_type i = 0; i < nf; i++)
1209 {
1210 if (&m_vals[i] != &ref)
1211 m_vals[i].resize (m_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
1228void
1230{
1231 octave_idx_type nf = nfields ();
1232 for (octave_idx_type k = 0; k < nf; k++)
1233 m_vals[k].delete_elements (i);
1234
1235 if (nf > 0)
1236 m_dimensions = m_vals[0].dims ();
1237 else
1238 {
1239 // Use dummy array. FIXME: Need(?) a better solution.
1240 Array<char> dummy (m_dimensions);
1241 dummy.delete_elements (i);
1242 m_dimensions = dummy.dims ();
1243 }
1244
1246}
1247
1248void
1250{
1251 octave_idx_type nf = nfields ();
1252 for (octave_idx_type k = 0; k < nf; k++)
1253 m_vals[k].delete_elements (dim, i);
1254
1255 if (nf > 0)
1256 m_dimensions = m_vals[0].dims ();
1257 else
1258 {
1259 // Use dummy array. FIXME: Need(?) a better solution.
1260 Array<char> dummy (m_dimensions);
1261 dummy.delete_elements (dim, i);
1262 m_dimensions = dummy.dims ();
1263 }
1264
1266}
1267
1268void
1270{
1271 octave_idx_type nf = nfields ();
1272 for (octave_idx_type k = 0; k < nf; k++)
1273 m_vals[k].delete_elements (ia);
1274
1275 if (nf > 0)
1276 m_dimensions = m_vals[0].dims ();
1277 else
1278 {
1279 // Use dummy array. FIXME: Need(?) a better solution.
1280 Array<char> dummy (m_dimensions);
1281 dummy.delete_elements (ia);
1282 m_dimensions = dummy.dims ();
1283 }
1284
1286}
1287
1288void
1290{
1291 octave_idx_type n_idx = idx.length ();
1292
1293 Array<octave::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& ie)
1302 {
1303 // Rethrow to allow more info to be reported later.
1304 ie.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
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
1347void
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
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:504
OCTARRAY_API void clear(void)
Definition: Array.cc:87
OCTARRAY_API Array< T, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:697
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:487
OCTARRAY_API void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1010
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
OCTARRAY_API void delete_elements(const octave::idx_vector &i)
Deleting elements.
Definition: Array.cc:1394
OCTARRAY_API Array< T, Alloc > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
Definition: Array.cc:431
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:595
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
static const idx_vector colon
Definition: idx-vector.h:483
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
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: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
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: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
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
octave_map transpose(void) const
Definition: oct-map.cc:499
void delete_elements(const octave::idx_vector &i)
Definition: oct-map.cc:1229
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
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
int ndims(void) const
Definition: oct-map.h:432
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:690
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:979
octave_map squeeze(void) const
Definition: oct-map.cc:442
octave_fields m_keys
Definition: oct-map.h:265
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:205
octave_scalar_map orderfields(void) const
Definition: oct-map.cc:208
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:980
#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()) ? '\'' :'"'))