GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-map.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1995-2025 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
38octave_fields::fields_rep *
39octave_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
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.rwdata ());
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{
185 octave_idx_type idx = m_keys.getfield (k);
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{
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
199void
200octave_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
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{
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
274Cell
275octave_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
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
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
297void
298octave_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
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{
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
360void
361octave_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
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
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
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 {
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
569libinterp/corefcn/oct-map.cc
570
571*/
572
573void
574octave_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
599void
600octave_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 panic_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
621void
622octave_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.
642void
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.
652void
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
664permute_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
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.
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
872octave_map::index (const octave::idx_vector& i, const octave::idx_vector& j,
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
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.
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
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{
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
994void
995octave_map::assign (const octave::idx_vector& i, const octave_map& rhs)
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 panic_unless (rhs1.m_keys.is_same (m_keys));
1037 assign (i, rhs1);
1038 }
1039}
1040
1041void
1042octave_map::assign (const octave::idx_vector& i, const octave::idx_vector& j,
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 panic_unless (rhs1.m_keys.is_same (m_keys));
1085 assign (i, j, rhs1);
1086 }
1087}
1088
1089void
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 panic_unless (rhs1.m_keys.is_same (m_keys));
1133 assign (ia, rhs1);
1134 }
1135}
1136
1137void
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
1191void
1192octave_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
1229void
1230octave_map::delete_elements (const octave::idx_vector& i)
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
1249void
1250octave_map::delete_elements (int dim, const octave::idx_vector& i)
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
1269void
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
1289void
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
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 const 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
1348void
1349octave_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)
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array.h:525
Array< T, Alloc > index(const octave::idx_vector &i) const
Indexing without resizing.
void clear()
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
void delete_elements(const octave::idx_vector &i)
Deleting elements.
Array< T, Alloc > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition Array.h:636
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
Definition Cell.h:41
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
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
void chop_trailing_singletons()
Definition dim-vector.h:160
dim_vector squeeze() const
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
bool all_zero() const
Definition dim-vector.h:296
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_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
const Cell & contents(const_iterator p) const
Definition oct-map.h:310
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
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
const octave_value & contents(const_iterator p) const
Definition oct-map.h:197
octave_scalar_map(const octave_fields &k)
Definition oct-map.h:168
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:111
std::string & xelem(octave_idx_type i)
Definition str-vec.h:106
octave_idx_type numel() const
Definition str-vec.h:98
void error(const char *fmt,...)
Definition error.cc:1003
#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
#define panic_unless(cond)
Definition panic.h:59