comparison liboctave/Array.cc @ 8290:7cbe01c21986

improve dense array indexing
author Jaroslav Hajek <highegg@gmail.com>
date Mon, 20 Oct 2008 16:54:28 +0200
parents 6c08e3921d3e
children f2e050b62199
comparison
equal deleted inserted replaced
8289:ac7f334d9652 8290:7cbe01c21986
1 // Template array classes 1 // Template array classes
2 /* 2 /*
3 3
4 Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004, 4 Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004,
5 2005, 2006, 2007 John W. Eaton 5 2005, 2006, 2007 John W. Eaton
6 Copyright (C) 2008 Jaroslav Hajek <highegg@gmail.com>
6 7
7 This file is part of Octave. 8 This file is part of Octave.
8 9
9 Octave is free software; you can redistribute it and/or modify it 10 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the 11 under the terms of the GNU General Public License as published by the
30 #include <climits> 31 #include <climits>
31 32
32 #include <iostream> 33 #include <iostream>
33 #include <sstream> 34 #include <sstream>
34 #include <vector> 35 #include <vector>
36 #include <algorithm>
35 #include <new> 37 #include <new>
36 38
37 #include "Array.h" 39 #include "Array.h"
38 #include "Array-util.h" 40 #include "Array-util.h"
39 #include "idx-vector.h" 41 #include "idx-vector.h"
42 // One dimensional array class. Handles the reference counting for 44 // One dimensional array class. Handles the reference counting for
43 // all the derived classes. 45 // all the derived classes.
44 46
45 template <class T> 47 template <class T>
46 Array<T>::Array (const Array<T>& a, const dim_vector& dv) 48 Array<T>::Array (const Array<T>& a, const dim_vector& dv)
47 : rep (a.rep), dimensions (dv), idx (0), idx_count (0) 49 : rep (a.rep), dimensions (dv)
48 { 50 {
49 rep->count++; 51 rep->count++;
50 52
51 if (a.numel () < dv.numel ()) 53 if (a.numel () < dv.numel ())
52 (*current_liboctave_error_handler) 54 (*current_liboctave_error_handler)
56 template <class T> 58 template <class T>
57 Array<T>::~Array (void) 59 Array<T>::~Array (void)
58 { 60 {
59 if (--rep->count <= 0) 61 if (--rep->count <= 0)
60 delete rep; 62 delete rep;
61
62 delete [] idx;
63 } 63 }
64 64
65 template <class T> 65 template <class T>
66 Array<T>& 66 Array<T>&
67 Array<T>::operator = (const Array<T>& a) 67 Array<T>::operator = (const Array<T>& a)
73 73
74 rep = a.rep; 74 rep = a.rep;
75 rep->count++; 75 rep->count++;
76 76
77 dimensions = a.dimensions; 77 dimensions = a.dimensions;
78
79 delete [] idx;
80 idx_count = 0;
81 idx = 0;
82 } 78 }
83 79
84 return *this; 80 return *this;
85 } 81 }
86 82
557 retval.chop_trailing_singletons (); 553 retval.chop_trailing_singletons ();
558 554
559 return retval; 555 return retval;
560 } 556 }
561 557
558 // Helper class for multi-d index reduction and recursive indexing/indexed assignment.
559 // Rationale: we could avoid recursion using a state machine instead. However, using
560 // recursion is much more amenable to possible parallelization in the future.
561 // Also, the recursion solution is cleaner and more understandable.
562 class rec_index_helper
563 {
564 octave_idx_type *dim, *cdim;
565 idx_vector *idx;
566 int top;
567
568 public:
569 rec_index_helper (const dim_vector& dv, const Array<idx_vector>& ia)
570 {
571 int n = ia.length ();
572 assert (n > 0 && (dv.length () == std::max (n, 2)));
573
574 dim = new octave_idx_type [2*n];
575 // A hack to avoid double allocation
576 cdim = dim + n;
577 idx = new idx_vector [n];
578 top = 0;
579
580 dim[0] = dv(0);
581 cdim[0] = 1;
582 idx[0] = ia(0);
583
584 for (int i = 1; i < n; i++)
585 {
586 // Try reduction...
587 if (idx[top].maybe_reduce (dim[top], ia(i), dv(i)))
588 {
589 // Reduction successful, fold dimensions.
590 dim[top] *= dv(i);
591 }
592 else
593 {
594 // Unsuccessful, store index & cumulative dim.
595 top++;
596 idx[top] = ia(i);
597 dim[top] = dv(i);
598 cdim[top] = cdim[top-1] * dim[top-1];
599 }
600 }
601 }
602
603 ~rec_index_helper (void) { delete [] idx; delete [] dim; }
604
605 private:
606
607 // Recursive N-d indexing
608 template <class T>
609 T *do_index (const T *src, T *dest, int lev) const
610 {
611 if (lev == 0)
612 dest += idx[0].index (src, dim[0], dest);
613 else
614 {
615 octave_idx_type n = idx[lev].length (dim[lev]), d = cdim[lev];
616 for (octave_idx_type i = 0; i < n; i++)
617 dest = do_index (src + d*idx[lev].xelem (i), dest, lev-1);
618 }
619
620 return dest;
621 }
622
623 // Recursive N-d indexed assignment
624 template <class T>
625 const T *do_assign (const T *src, T *dest, int lev) const
626 {
627 if (lev == 0)
628 src += idx[0].assign (src, dim[0], dest);
629 else
630 {
631 octave_idx_type n = idx[lev].length (dim[lev]), d = cdim[lev];
632 for (octave_idx_type i = 0; i < n; i++)
633 src = do_assign (src, dest + d*idx[lev].xelem (i), lev-1);
634 }
635
636 return src;
637 }
638
639 // Recursive N-d indexed assignment
640 template <class T>
641 void do_fill (const T& val, T *dest, int lev) const
642 {
643 if (lev == 0)
644 idx[0].fill (val, dim[0], dest);
645 else
646 {
647 octave_idx_type n = idx[lev].length (dim[lev]), d = cdim[lev];
648 for (octave_idx_type i = 0; i < n; i++)
649 do_fill (val, dest + d*idx[lev].xelem (i), lev-1);
650 }
651 }
652
653 public:
654
655 template <class T>
656 void index (const T *src, T *dest) const { do_index (src, dest, top); }
657
658 template <class T>
659 void assign (const T *src, T *dest) const { do_assign (src, dest, top); }
660
661 template <class T>
662 void fill (const T& val, T *dest) const { do_fill (val, dest, top); }
663
664 };
665
666 // Helper class for multi-d recursive resizing
667 // This handles resize () in an efficient manner, touching memory only
668 // once (apart from reinitialization)
669 class rec_resize_helper
670 {
671 octave_idx_type *cext, *sext, *dext;
672 int n;
673
674 public:
675 rec_resize_helper (const dim_vector& ndv, const dim_vector& odv)
676 {
677 int l = ndv.length ();
678 assert (odv.length () == l);
679 octave_idx_type ld = 1;
680 int i = 0;
681 for (; i < l-1 && ndv(i) == odv(i); i++) ld *= ndv(i);
682 n = l - i;
683 cext = new octave_idx_type[3*n];
684 // Trick to avoid three allocations
685 sext = cext + n;
686 dext = sext + n;
687
688 octave_idx_type sld = ld, dld = ld;
689 for (int j = 0; j < n; j++)
690 {
691 cext[j] = std::min (ndv(i+j), odv(i+j));
692 sext[j] = sld *= odv(i+j);
693 dext[j] = dld *= ndv(i+j);
694 }
695 cext[0] *= ld;
696 }
697
698 ~rec_resize_helper (void) { delete [] cext; }
699
700 private:
701 // recursive resizing
702 template <class T>
703 void do_resize_fill (const T* src, T *dest, const T& rfv, int lev) const
704 {
705 if (lev == 0)
706 {
707 T* destc = std::copy (src, src + cext[0], dest);
708 std::fill (destc, dest + dext[0], rfv);
709 }
710 else
711 {
712 octave_idx_type sd = sext[lev-1], dd = dext[lev-1], k;
713 for (k = 0; k < cext[lev]; k++)
714 do_resize_fill (src + k * sd, dest + k * dd, rfv, lev - 1);
715
716 std::fill (dest + k * dd, dest + dext[lev], rfv);
717 }
718 }
719 public:
720 template <class T>
721 void resize_fill (const T* src, T *dest, const T& rfv) const
722 { do_resize_fill (src, dest, rfv, n-1); }
723
724 };
725
726 static void gripe_index_out_of_range (void)
727 {
728 (*current_liboctave_error_handler)
729 ("A(I): Index exceeds matrix dimension.");
730 }
731
732 template <class T>
733 Array<T>
734 Array<T>::index (const idx_vector& i) const
735 {
736 octave_idx_type n = numel ();
737 Array<T> retval;
738
739 if (i.is_colon ())
740 {
741 // A(:) produces a shallow copy as a column vector.
742 retval.dimensions = dim_vector (n, 1);
743 rep->count++;
744 retval.rep = rep;
745 }
746 else if (i.extent (n) != n)
747 {
748 gripe_index_out_of_range ();
749 }
750 else
751 {
752 // FIXME: This is the only place where orig_dimensions are used.
753 dim_vector rd = i.orig_dimensions ();
754 octave_idx_type il = i.length (n);
755
756 // FIXME: This is for Matlab compatibility. Matlab 2007 given `b = ones(3,1)'
757 // yields the following:
758 // b(zeros(0,0)) gives []
759 // b(zeros(1,0)) gives zeros(0,1)
760 // b(zeros(0,1)) gives zeros(0,1)
761 // b(zeros(0,m)) gives zeros(0,m)
762 // b(zeros(m,0)) gives zeros(m,0)
763 // b(1:2) gives ones(2,1)
764 // b(ones(2)) gives ones(2) etc.
765 // As you can see, the behaviour is weird, but the tests end up pretty
766 // simple. Nah, I don't want to suggest that this is ad hoc :) Neither do
767 // I want to say that Matlab is a lousy piece of s...oftware.
768 if (ndims () == 2 && n != 1)
769 {
770 if (columns () == 1 && rd(0) == 1)
771 rd = dim_vector (il, 1);
772 else if (rows () == 1 && rd(1) == 1)
773 rd = dim_vector (1, il);
774 }
775
776 // Don't use resize here to avoid useless initialization for POD types.
777 retval = Array<T> (rd);
778
779 if (il != 0)
780 i.index (data (), n, retval.fortran_vec ());
781 }
782
783 return retval;
784 }
785
786 template <class T>
787 Array<T>
788 Array<T>::index (const idx_vector& i, const idx_vector& j) const
789 {
790 // Get dimensions, allowing Fortran indexing in the 2nd dim.
791 dim_vector dv = dimensions.redim (2);
792 octave_idx_type r = dv(0), c = dv(1);
793 Array<T> retval;
794
795 if (i.is_colon () && j.is_colon ())
796 {
797 // A(:,:) produces a shallow copy.
798 retval = Array<T> (*this, dv);
799 }
800 else if (i.extent (r) != r || j.extent (c) != c)
801 {
802 gripe_index_out_of_range ();
803 }
804 else
805 {
806 octave_idx_type n = numel (), il = i.length (r), jl = j.length (c);
807
808 // Don't use resize here to avoid useless initialization for POD types.
809 retval = Array<T> (dim_vector (il, jl));
810
811 idx_vector ii (i);
812
813 const T* src = data ();
814 T *dest = retval.fortran_vec ();
815
816 if (ii.maybe_reduce (r, j, c))
817 ii.index (src, n, dest);
818 else
819 {
820 for (octave_idx_type k = 0; k < jl; k++)
821 dest += i.index (src + r * j.xelem (k), r, dest);
822 }
823 }
824
825 return retval;
826 }
827
828 template <class T>
829 Array<T>
830 Array<T>::index (const Array<idx_vector>& ia) const
831 {
832 int ial = ia.length ();
833 Array<T> retval;
834
835 // FIXME: is this dispatching necessary?
836 if (ial == 1)
837 retval = index (ia(0));
838 else if (ial == 2)
839 retval = index (ia(0), ia(1));
840 else if (ial > 0)
841 {
842 // Get dimensions, allowing Fortran indexing in the last dim.
843 dim_vector dv = dimensions.redim (ial);
844
845 // Check for out of bounds conditions.
846 bool all_colons = true, mismatch = false;
847 for (int i = 0; i < ial; i++)
848 {
849 if (ia(i).extent (dv(i)) != dv(i))
850 {
851 mismatch = true;
852 break;
853 }
854 else
855 all_colons = all_colons && ia(i).is_colon ();
856 }
857
858
859 if (mismatch)
860 {
861 gripe_index_out_of_range ();
862 }
863 else if (all_colons)
864 {
865 // A(:,:,...,:) produces a shallow copy.
866 retval = Array<T> (*this, dv);
867 }
868 else
869 {
870 // Form result dimensions.
871 dim_vector rdv;
872 rdv.resize (ial);
873 for (int i = 0; i < ial; i++) rdv(i) = ia(i).length (dv(i));
874 rdv.chop_trailing_singletons ();
875
876 // Don't use resize here to avoid useless initialization for POD types.
877 retval = Array<T> (rdv);
878
879 // Prepare for recursive indexing
880 rec_index_helper rh (dv, ia);
881
882 // Do it.
883 rh.index (data (), retval.fortran_vec ());
884 }
885 }
886
887 return retval;
888 }
889
890 // FIXME: the following is a common error message to resize, regardless of whether it's
891 // called from assign or elsewhere. It seems OK to me, but eventually the gripe can be
892 // specialized. Anyway, propagating various error messages into procedure is, IMHO, a
893 // nonsense. If anything, we should change error handling here (and throughout liboctave)
894 // to allow custom handling of errors
895 static void gripe_invalid_resize (void)
896 {
897 (*current_liboctave_error_handler)
898 ("resize: Invalid resizing operation or ambiguous assignment to an out-of-bounds array element.");
899 }
900
901 // The default fill value. Override if you want a different one.
902
903 template <class T>
904 T Array<T>::resize_fill_value ()
905 {
906 return T ();
907 }
908
909 // Yes, we could do resize using index & assign. However, that would possibly
910 // involve a lot more memory traffic than we actually need.
911
562 template <class T> 912 template <class T>
563 void 913 void
564 Array<T>::resize_no_fill (octave_idx_type n) 914 Array<T>::resize_fill (octave_idx_type n, const T& rfv)
565 { 915 {
566 if (n < 0) 916 if (n >= 0 && ndims () == 2)
917 {
918 dim_vector dv;
919 // This is driven by Matlab's behaviour of giving a *row* vector on
920 // some out-of-bounds assignments. Specifically, matlab allows a(i) with
921 // out-of-bouds i when a is either of 0x0, 1x0, 1x1, 0xN, and gives
922 // a row vector in all cases (yes, even the last one, search me why).
923 // Giving a column vector would make much more sense (given the way
924 // trailing singleton dims are treated), but hey, Matlab is not here to
925 // make sense, it's here to make money ;)
926 bool invalid = false;
927 if (rows () == 0 || rows () == 1)
928 dv = dim_vector (1, n);
929 else if (columns () == 1)
930 dv = dim_vector (n, 1);
931 else
932 invalid = true;
933
934 if (invalid)
935 gripe_invalid_resize ();
936 else
937 {
938 octave_idx_type nx = numel ();
939 if (n != nx)
940 {
941 Array<T> tmp = Array<T> (dv);
942 T *dest = tmp.fortran_vec ();
943
944 octave_idx_type n0 = std::min (n, nx), n1 = n - n0;
945 dest = std::copy (data (), data () + n0, dest);
946 std::fill (dest, dest + n1, rfv);
947
948 *this = tmp;
949 }
950 }
951 }
952 else
953 gripe_invalid_resize ();
954 }
955
956 template <class T>
957 void
958 Array<T>::resize_fill (octave_idx_type r, octave_idx_type c, const T& rfv)
959 {
960 if (r >= 0 && c >= 0 && ndims () == 2)
961 {
962 octave_idx_type rx = rows (), cx = columns ();
963 if (r != rx || c != cx)
964 {
965 Array<T> tmp = Array<T> (dim_vector (r, c));
966 T *dest = tmp.fortran_vec ();
967
968 octave_idx_type r0 = std::min (r, rx), r1 = r - r0;
969 octave_idx_type c0 = std::min (c, cx), c1 = c - c0;
970 const T *src = data ();
971 if (r == rx)
972 dest = std::copy (src, src + r * c0, dest);
973 else
974 {
975 for (octave_idx_type k = 0; k < c0; k++)
976 {
977 dest = std::copy (src, src + r0, dest);
978 src += rx;
979 std::fill (dest, dest + r1, rfv);
980 dest += r1;
981 }
982 }
983
984 std::fill (dest, dest + r * c1, rfv);
985
986 *this = tmp;
987 }
988 }
989 else
990 gripe_invalid_resize ();
991
992 }
993
994 template<class T>
995 void
996 Array<T>::resize_fill (const dim_vector& dv, const T& rfv)
997 {
998 int dvl = dv.length ();
999 if (dvl == 1)
1000 resize (dv(0), rfv);
1001 else if (dvl == 2)
1002 resize (dv(0), dv(1), rfv);
1003 else if (dimensions != dv)
1004 {
1005 if (dimensions.length () <= dvl)
1006 {
1007 Array<T> tmp (dv);
1008 // Prepare for recursive resizing.
1009 rec_resize_helper rh (dv, dimensions.redim (dvl));
1010
1011 // Do it.
1012 rh.resize_fill (data (), tmp.fortran_vec (), rfv);
1013 *this = tmp;
1014 }
1015 else
1016 gripe_invalid_resize ();
1017 }
1018 }
1019
1020 template <class T>
1021 Array<T>
1022 Array<T>::index (const idx_vector& i, bool resize_ok, const T& rfv) const
1023 {
1024 Array<T> tmp = *this;
1025 if (resize_ok)
1026 {
1027 octave_idx_type n = numel (), nx = i.extent (n);
1028 if (n != nx)
1029 tmp.resize_fill (nx, rfv);
1030
1031 if (tmp.numel () != nx)
1032 return Array<T> ();
1033 }
1034
1035 return tmp.index (i);
1036 }
1037
1038 template <class T>
1039 Array<T>
1040 Array<T>::index (const idx_vector& i, const idx_vector& j,
1041 bool resize_ok, const T& rfv) const
1042 {
1043 Array<T> tmp = *this;
1044 if (resize_ok)
1045 {
1046 dim_vector dv = dimensions.redim (2);
1047 octave_idx_type r = dv(0), c = dv(1);
1048 octave_idx_type rx = i.extent (r), cx = j.extent (c);
1049 if (r != rx || c != cx)
1050 tmp.resize_fill (rx, cx, rfv);
1051
1052 if (tmp.rows () != rx || tmp.columns () != cx)
1053 return Array<T> ();
1054 }
1055
1056 return tmp.index (i, j);
1057 }
1058
1059 template <class T>
1060 Array<T>
1061 Array<T>::index (const Array<idx_vector>& ia,
1062 bool resize_ok, const T& rfv) const
1063 {
1064 Array<T> tmp = *this;
1065 if (resize_ok)
1066 {
1067 int ial = ia.length ();
1068 dim_vector dv = dimensions.redim (ial);
1069 dim_vector dvx; dvx.resize (ial);
1070 for (int i = 0; i < ial; i++) dvx(i) = ia(i).extent (dv (i));
1071 if (! (dvx == dv))
1072 tmp.resize_fill (dvx, rfv);
1073
1074 if (tmp.dimensions != dvx)
1075 return Array<T> ();
1076 }
1077
1078 return tmp.index (ia);
1079 }
1080
1081
1082 static void
1083 gripe_invalid_assignment_size (void)
1084 {
1085 (*current_liboctave_error_handler)
1086 ("A(I) = X: X must have the same size as I");
1087 }
1088
1089 static void
1090 gripe_assignment_dimension_mismatch (void)
1091 {
1092 (*current_liboctave_error_handler)
1093 ("A(I,J,...) = X: dimensions mismatch");
1094 }
1095
1096 template <class T>
1097 void
1098 Array<T>::assign (const idx_vector& i, const Array<T>& rhs, const T& rfv)
1099 {
1100 octave_idx_type n = numel (), rhl = rhs.numel ();
1101
1102 if (rhl == 1 || i.length (n) == rhl)
1103 {
1104 octave_idx_type nx = i.extent (n);
1105 // Try to resize first if necessary.
1106 if (nx != n)
1107 {
1108 resize_fill (nx, rfv);
1109 n = numel ();
1110 }
1111
1112 // If the resizing was ambiguous, resize has already griped.
1113 if (nx == n)
1114 {
1115 if (i.is_colon ())
1116 {
1117 // A(:) = X makes a full fill or a shallow copy.
1118 if (rhl == 1)
1119 fill (rhs(0));
1120 else
1121 *this = rhs.reshape (dimensions);
1122 }
1123 else
1124 {
1125 if (rhl == 1)
1126 i.fill (rhs(0), n, fortran_vec ());
1127 else
1128 i.assign (rhs.data (), n, fortran_vec ());
1129 }
1130 }
1131 }
1132 else
1133 gripe_invalid_assignment_size ();
1134 }
1135
1136 template <class T>
1137 void
1138 Array<T>::assign (const idx_vector& i, const idx_vector& j,
1139 const Array<T>& rhs, const T& rfv)
1140 {
1141 // Get RHS extents, discarding singletons.
1142 dim_vector rhdv = rhs.dims ();
1143 // Get LHS extents, allowing Fortran indexing in the second dim.
1144 dim_vector dv = dimensions.redim (2);
1145 // Check for out-of-bounds and form resizing dimensions.
1146 dim_vector rdv;
1147 // In the special when all dimensions are zero, colons are allowed to inquire
1148 // the shape of RHS. The rules are more obscure, so we solve that elsewhere.
1149 if (dv.all_zero ())
1150 rdv = zero_dims_inquire (i, j, rhdv);
1151 else
1152 {
1153 rdv(0) = i.extent (dv(0));
1154 rdv(1) = j.extent (dv(1));
1155 }
1156
1157 bool isfill = rhs.numel () == 1;
1158 octave_idx_type il = i.length (rdv(0)), jl = j.length (rdv(1));
1159 rhdv.chop_all_singletons ();
1160 bool match = isfill || (rhdv.length () == 2 && il == rhdv(0) && jl == rhdv(1));
1161 match = match || (il == 1 && jl == rhdv(0) && rhdv(1) == 1);
1162
1163 if (match)
1164 {
1165 // Resize if requested.
1166 if (rdv != dv)
1167 {
1168 resize (rdv, rfv);
1169 dv = dimensions;
1170 }
1171
1172 // If the resizing was invalid, resize has already griped.
1173 if (dv == rdv)
1174 {
1175 if (i.is_colon () && j.is_colon ())
1176 {
1177 // A(:,:) = X makes a full fill or a shallow copy
1178 if (isfill)
1179 fill (rhs(0));
1180 else
1181 *this = rhs.reshape (dimensions);
1182 }
1183 else
1184 {
1185 // The actual work.
1186 octave_idx_type n = numel (), r = rows (), c = columns ();
1187 idx_vector ii (i);
1188
1189 const T* src = rhs.data ();
1190 T *dest = fortran_vec ();
1191
1192 // Try reduction first.
1193 if (ii.maybe_reduce (r, j, c))
1194 {
1195 if (isfill)
1196 ii.fill (*src, n, dest);
1197 else
1198 ii.assign (src, n, dest);
1199 }
1200 else
1201 {
1202 if (isfill)
1203 {
1204 for (octave_idx_type k = 0; k < jl; k++)
1205 i.fill (*src, r, dest + r * j.xelem (k));
1206 }
1207 else
1208 {
1209 for (octave_idx_type k = 0; k < jl; k++)
1210 src += i.assign (src, r, dest + r * j.xelem (k));
1211 }
1212 }
1213 }
1214
1215 }
1216
1217 }
1218 else
1219 gripe_assignment_dimension_mismatch ();
1220 }
1221
1222 template <class T>
1223 void
1224 Array<T>::assign (const Array<idx_vector>& ia,
1225 const Array<T>& rhs, const T& rfv)
1226 {
1227 int ial = ia.length ();
1228
1229 // FIXME: is this dispatching necessary / desirable?
1230 if (ial == 1)
1231 assign (ia(0), rhs, rfv);
1232 else if (ial == 2)
1233 assign (ia(0), ia(1), rhs, rfv);
1234 else if (ial > 0)
1235 {
1236 // Get RHS extents, discarding singletons.
1237 dim_vector rhdv = rhs.dims ();
1238
1239 // Get LHS extents, allowing Fortran indexing in the second dim.
1240 dim_vector dv = dimensions.redim (ial);
1241
1242 // Get the extents forced by indexing.
1243 dim_vector rdv;
1244
1245 // In the special when all dimensions are zero, colons are allowed to
1246 // inquire the shape of RHS. The rules are more obscure, so we solve that
1247 // elsewhere.
1248 if (dv.all_zero ())
1249 rdv = zero_dims_inquire (ia, rhdv);
1250 else
1251 {
1252 rdv.resize (ial);
1253 for (int i = 0; i < ial; i++)
1254 rdv(i) = ia(i).extent (dv(i));
1255 }
1256
1257 // Check whether LHS and RHS match, up to singleton dims.
1258 bool match = true, all_colons = true, isfill = rhs.numel () == 1;
1259
1260 rhdv.chop_all_singletons ();
1261 int j = 0, rhdvl = rhdv.length ();
1262 for (int i = 0; i < ial; i++)
1263 {
1264 all_colons = all_colons && ia(i).is_colon ();
1265 octave_idx_type l = ia(i).length (rdv(i));
1266 if (l == 1) continue;
1267 match = match && j < rhdvl && l == rhdv(j++);
1268 }
1269
1270 match = match && (j == rhdvl || rhdv(j) == 1);
1271 match = match || isfill;
1272
1273 if (match)
1274 {
1275 // Resize first if necessary.
1276 if (rdv != dv)
1277 {
1278 resize_fill (rdv, rfv);
1279 dv = dimensions;
1280 chop_trailing_singletons ();
1281 }
1282
1283 // If the resizing was invalid, resize has already griped.
1284 if (dv == rdv)
1285 {
1286 if (all_colons)
1287 {
1288 // A(:,:,...,:) = X makes a full fill or a shallow copy.
1289 if (isfill)
1290 fill (rhs(0));
1291 else
1292 *this = rhs.reshape (dimensions);
1293 }
1294 else
1295 {
1296 // Do the actual work.
1297
1298 // Prepare for recursive indexing
1299 rec_index_helper rh (dv, ia);
1300
1301 // Do it.
1302 if (isfill)
1303 rh.fill (rhs(0), fortran_vec ());
1304 else
1305 rh.assign (rhs.data (), fortran_vec ());
1306 }
1307 }
1308 }
1309 else
1310 gripe_assignment_dimension_mismatch ();
1311 }
1312 }
1313
1314 template <class T>
1315 void
1316 Array<T>::delete_elements (const idx_vector& i)
1317 {
1318 octave_idx_type n = numel ();
1319 if (i.is_colon ())
1320 {
1321 *this = Array<T> ();
1322 }
1323 else if (i.extent (n) != n)
1324 {
1325 gripe_index_out_of_range ();
1326 }
1327 else if (i.length (n) != 0)
1328 {
1329 octave_idx_type l, u;
1330
1331 bool col_vec = ndims () == 2 && columns () == 1 && rows () != 1;
1332 if (i.is_cont_range (n, l, u))
1333 {
1334 // Special case deleting a contiguous range.
1335 octave_idx_type m = n + l - u;
1336 Array<T> tmp (dim_vector (col_vec ? m : 1, !col_vec ? m : 1));
1337 const T *src = data ();
1338 T *dest = tmp.fortran_vec ();
1339 dest = std::copy (src, src + l, dest);
1340 dest = std::copy (src + u, src + n, dest);
1341 *this = tmp;
1342 }
1343 else
1344 {
1345 // Use index.
1346 *this = index (i.complement (n));
1347 }
1348 }
1349 }
1350
1351 template <class T>
1352 void
1353 Array<T>::delete_elements (int dim, const idx_vector& i)
1354 {
1355 if (dim > ndims ())
567 { 1356 {
568 (*current_liboctave_error_handler) 1357 (*current_liboctave_error_handler)
569 ("can't resize to negative dimension"); 1358 ("invalid dimension in delete_elements");
570 return; 1359 return;
571 } 1360 }
572 1361
573 if (n == length ()) 1362 octave_idx_type n = dimensions (dim);
574 return; 1363 if (i.is_colon ())
575 1364 {
576 typename Array<T>::ArrayRep *old_rep = rep; 1365 *this = Array<T> ();
577 const T *old_data = data (); 1366 }
578 octave_idx_type old_len = length (); 1367 else if (i.extent (n) != n)
579 1368 {
580 rep = new typename Array<T>::ArrayRep (n); 1369 gripe_index_out_of_range ();
581 1370 }
582 dimensions = dim_vector (n); 1371 else if (i.length (n) != 0)
583 1372 {
584 if (n > 0 && old_data && old_len > 0) 1373 octave_idx_type l, u;
585 { 1374
586 octave_idx_type min_len = old_len < n ? old_len : n; 1375 if (i.is_cont_range (n, l, u))
587 1376 {
588 for (octave_idx_type i = 0; i < min_len; i++) 1377 // Special case deleting a contiguous range.
589 xelem (i) = old_data[i]; 1378 octave_idx_type nd = n + l - u, dl = 1, du = 1;
590 } 1379 dim_vector rdv = dimensions;
591 1380 rdv(dim) = nd;
592 if (--old_rep->count <= 0) 1381 for (int k = 0; k < dim; k++) dl *= dimensions(k);
593 delete old_rep; 1382 for (int k = dim + 1; k < ndims (); k++) du *= dimensions(k);
594 } 1383
595 1384 // Special case deleting a contiguous range.
596 template <class T> 1385 Array<T> tmp = Array<T> (rdv);
597 void 1386 const T *src = data ();
598 Array<T>::resize_no_fill (const dim_vector& dv) 1387 T *dest = tmp.fortran_vec ();
599 { 1388 l *= dl; u *= dl; n *= dl;
600 octave_idx_type n = dv.length (); 1389 for (octave_idx_type k = 0; k < du; k++)
601 1390 {
602 for (octave_idx_type i = 0; i < n; i++) 1391 dest = std::copy (src, src + l, dest);
603 { 1392 dest = std::copy (src + u, src + n, dest);
604 if (dv(i) < 0) 1393 src += n;
605 { 1394 }
606 (*current_liboctave_error_handler) 1395
607 ("can't resize to negative dimension"); 1396 *this = tmp;
608 return; 1397 }
609 } 1398 else
610 } 1399 {
611 1400 // Use index.
612 bool same_size = true; 1401 Array<idx_vector> ia (ndims (), idx_vector::colon);
613 1402 ia (dim) = i.complement (n);
614 if (dimensions.length () != n) 1403 *this = index (ia);
615 { 1404 }
616 same_size = false; 1405 }
617 } 1406 }
618 else 1407
619 { 1408 template <class T>
620 for (octave_idx_type i = 0; i < n; i++) 1409 void
621 { 1410 Array<T>::delete_elements (const Array<idx_vector>& ia)
622 if (dv(i) != dimensions(i)) 1411 {
623 { 1412 if (ia.length () == 1)
624 same_size = false; 1413 delete_elements (ia(0));
625 break; 1414 else
626 } 1415 {
627 } 1416 int len = ia.length (), k, dim = -1;
628 } 1417 for (k = 0; k < len; k++)
629 1418 {
630 if (same_size) 1419 if (! ia(k).is_colon ())
631 return; 1420 {
632 1421 if (dim < 0)
633 typename Array<T>::ArrayRep *old_rep = rep; 1422 dim = k;
634 const T *old_data = data (); 1423 else
635 1424 break;
636 octave_idx_type ts = get_size (dv); 1425 }
637 1426 }
638 rep = new typename Array<T>::ArrayRep (ts); 1427 if (dim < 0)
639 1428 {
640 dim_vector dv_old = dimensions; 1429 dim_vector dv = dimensions;
641 octave_idx_type dv_old_orig_len = dv_old.length (); 1430 dv(0) = 0;
642 dimensions = dv; 1431 *this = Array<T> (dv);
643 octave_idx_type ts_old = get_size (dv_old); 1432 }
644 1433 else if (k == len)
645 if (ts > 0 && ts_old > 0 && dv_old_orig_len > 0) 1434 {
646 { 1435 delete_elements (dim, ia(dim));
647 Array<octave_idx_type> ra_idx (dimensions.length (), 0); 1436 }
648 1437 else
649 if (n > dv_old_orig_len) 1438 {
650 { 1439 (*current_liboctave_error_handler)
651 dv_old.resize (n); 1440 ("A null assignment can only have one non-colon index.");
652 1441 }
653 for (octave_idx_type i = dv_old_orig_len; i < n; i++) 1442 }
654 dv_old.elem (i) = 1; 1443
655 } 1444 }
656 1445
657 for (octave_idx_type i = 0; i < ts; i++) 1446 // FIXME: Remove these methods or implement them using assign.
658 {
659 if (index_in_bounds (ra_idx, dv_old))
660 rep->elem (i) = old_data[get_scalar_idx (ra_idx, dv_old)];
661
662 increment_index (ra_idx, dimensions);
663 }
664 }
665
666 if (--old_rep->count <= 0)
667 delete old_rep;
668 }
669
670 template <class T>
671 void
672 Array<T>::resize_no_fill (octave_idx_type r, octave_idx_type c)
673 {
674 if (r < 0 || c < 0)
675 {
676 (*current_liboctave_error_handler)
677 ("can't resize to negative dimension");
678 return;
679 }
680
681 int n = ndims ();
682
683 if (n == 0)
684 dimensions = dim_vector (0, 0);
685
686 assert (ndims () == 2);
687
688 if (r == dim1 () && c == dim2 ())
689 return;
690
691 typename Array<T>::ArrayRep *old_rep = Array<T>::rep;
692 const T *old_data = data ();
693
694 octave_idx_type old_d1 = dim1 ();
695 octave_idx_type old_d2 = dim2 ();
696 octave_idx_type old_len = length ();
697
698 octave_idx_type ts = get_size (r, c);
699
700 rep = new typename Array<T>::ArrayRep (ts);
701
702 dimensions = dim_vector (r, c);
703
704 if (ts > 0 && old_data && old_len > 0)
705 {
706 octave_idx_type min_r = old_d1 < r ? old_d1 : r;
707 octave_idx_type min_c = old_d2 < c ? old_d2 : c;
708
709 for (octave_idx_type j = 0; j < min_c; j++)
710 for (octave_idx_type i = 0; i < min_r; i++)
711 xelem (i, j) = old_data[old_d1*j+i];
712 }
713
714 if (--old_rep->count <= 0)
715 delete old_rep;
716 }
717
718 template <class T>
719 void
720 Array<T>::resize_no_fill (octave_idx_type r, octave_idx_type c, octave_idx_type p)
721 {
722 if (r < 0 || c < 0 || p < 0)
723 {
724 (*current_liboctave_error_handler)
725 ("can't resize to negative dimension");
726 return;
727 }
728
729 int n = ndims ();
730
731 if (n == 0)
732 dimensions = dim_vector (0, 0, 0);
733
734 assert (ndims () == 3);
735
736 if (r == dim1 () && c == dim2 () && p == dim3 ())
737 return;
738
739 typename Array<T>::ArrayRep *old_rep = rep;
740 const T *old_data = data ();
741
742 octave_idx_type old_d1 = dim1 ();
743 octave_idx_type old_d2 = dim2 ();
744 octave_idx_type old_d3 = dim3 ();
745 octave_idx_type old_len = length ();
746
747 octave_idx_type ts = get_size (get_size (r, c), p);
748
749 rep = new typename Array<T>::ArrayRep (ts);
750
751 dimensions = dim_vector (r, c, p);
752
753 if (ts > 0 && old_data && old_len > 0)
754 {
755 octave_idx_type min_r = old_d1 < r ? old_d1 : r;
756 octave_idx_type min_c = old_d2 < c ? old_d2 : c;
757 octave_idx_type min_p = old_d3 < p ? old_d3 : p;
758
759 for (octave_idx_type k = 0; k < min_p; k++)
760 for (octave_idx_type j = 0; j < min_c; j++)
761 for (octave_idx_type i = 0; i < min_r; i++)
762 xelem (i, j, k) = old_data[old_d1*(old_d2*k+j)+i];
763 }
764
765 if (--old_rep->count <= 0)
766 delete old_rep;
767 }
768
769 template <class T>
770 void
771 Array<T>::resize_and_fill (octave_idx_type n, const T& val)
772 {
773 if (n < 0)
774 {
775 (*current_liboctave_error_handler)
776 ("can't resize to negative dimension");
777 return;
778 }
779
780 if (n == length ())
781 return;
782
783 typename Array<T>::ArrayRep *old_rep = rep;
784 const T *old_data = data ();
785 octave_idx_type old_len = length ();
786
787 rep = new typename Array<T>::ArrayRep (n);
788
789 dimensions = dim_vector (n);
790
791 if (n > 0)
792 {
793 octave_idx_type min_len = old_len < n ? old_len : n;
794
795 if (old_data && old_len > 0)
796 {
797 for (octave_idx_type i = 0; i < min_len; i++)
798 xelem (i) = old_data[i];
799 }
800
801 for (octave_idx_type i = old_len; i < n; i++)
802 xelem (i) = val;
803 }
804
805 if (--old_rep->count <= 0)
806 delete old_rep;
807 }
808
809 template <class T>
810 void
811 Array<T>::resize_and_fill (octave_idx_type r, octave_idx_type c, const T& val)
812 {
813 if (r < 0 || c < 0)
814 {
815 (*current_liboctave_error_handler)
816 ("can't resize to negative dimension");
817 return;
818 }
819
820 if (ndims () == 0)
821 dimensions = dim_vector (0, 0);
822
823 assert (ndims () == 2);
824
825 if (r == dim1 () && c == dim2 ())
826 return;
827
828 typename Array<T>::ArrayRep *old_rep = Array<T>::rep;
829 const T *old_data = data ();
830
831 octave_idx_type old_d1 = dim1 ();
832 octave_idx_type old_d2 = dim2 ();
833 octave_idx_type old_len = length ();
834
835 octave_idx_type ts = get_size (r, c);
836
837 rep = new typename Array<T>::ArrayRep (ts);
838
839 dimensions = dim_vector (r, c);
840
841 if (ts > 0)
842 {
843 octave_idx_type min_r = old_d1 < r ? old_d1 : r;
844 octave_idx_type min_c = old_d2 < c ? old_d2 : c;
845
846 if (old_data && old_len > 0)
847 {
848 for (octave_idx_type j = 0; j < min_c; j++)
849 for (octave_idx_type i = 0; i < min_r; i++)
850 xelem (i, j) = old_data[old_d1*j+i];
851 }
852
853 for (octave_idx_type j = 0; j < min_c; j++)
854 for (octave_idx_type i = min_r; i < r; i++)
855 xelem (i, j) = val;
856
857 for (octave_idx_type j = min_c; j < c; j++)
858 for (octave_idx_type i = 0; i < r; i++)
859 xelem (i, j) = val;
860 }
861
862 if (--old_rep->count <= 0)
863 delete old_rep;
864 }
865
866 template <class T>
867 void
868 Array<T>::resize_and_fill (octave_idx_type r, octave_idx_type c, octave_idx_type p, const T& val)
869 {
870 if (r < 0 || c < 0 || p < 0)
871 {
872 (*current_liboctave_error_handler)
873 ("can't resize to negative dimension");
874 return;
875 }
876
877 if (ndims () == 0)
878 dimensions = dim_vector (0, 0, 0);
879
880 assert (ndims () == 3);
881
882 if (r == dim1 () && c == dim2 () && p == dim3 ())
883 return;
884
885 typename Array<T>::ArrayRep *old_rep = rep;
886 const T *old_data = data ();
887
888 octave_idx_type old_d1 = dim1 ();
889 octave_idx_type old_d2 = dim2 ();
890 octave_idx_type old_d3 = dim3 ();
891
892 octave_idx_type old_len = length ();
893
894 octave_idx_type ts = get_size (get_size (r, c), p);
895
896 rep = new typename Array<T>::ArrayRep (ts);
897
898 dimensions = dim_vector (r, c, p);
899
900 if (ts > 0)
901 {
902 octave_idx_type min_r = old_d1 < r ? old_d1 : r;
903 octave_idx_type min_c = old_d2 < c ? old_d2 : c;
904 octave_idx_type min_p = old_d3 < p ? old_d3 : p;
905
906 if (old_data && old_len > 0)
907 for (octave_idx_type k = 0; k < min_p; k++)
908 for (octave_idx_type j = 0; j < min_c; j++)
909 for (octave_idx_type i = 0; i < min_r; i++)
910 xelem (i, j, k) = old_data[old_d1*(old_d2*k+j)+i];
911
912 // FIXME -- if the copy constructor is expensive, this
913 // may win. Otherwise, it may make more sense to just copy the
914 // value everywhere when making the new ArrayRep.
915
916 for (octave_idx_type k = 0; k < min_p; k++)
917 for (octave_idx_type j = min_c; j < c; j++)
918 for (octave_idx_type i = 0; i < min_r; i++)
919 xelem (i, j, k) = val;
920
921 for (octave_idx_type k = 0; k < min_p; k++)
922 for (octave_idx_type j = 0; j < c; j++)
923 for (octave_idx_type i = min_r; i < r; i++)
924 xelem (i, j, k) = val;
925
926 for (octave_idx_type k = min_p; k < p; k++)
927 for (octave_idx_type j = 0; j < c; j++)
928 for (octave_idx_type i = 0; i < r; i++)
929 xelem (i, j, k) = val;
930 }
931
932 if (--old_rep->count <= 0)
933 delete old_rep;
934 }
935
936 template <class T>
937 void
938 Array<T>::resize_and_fill (const dim_vector& dv, const T& val)
939 {
940 octave_idx_type n = dv.length ();
941
942 for (octave_idx_type i = 0; i < n; i++)
943 {
944 if (dv(i) < 0)
945 {
946 (*current_liboctave_error_handler)
947 ("can't resize to negative dimension");
948 return;
949 }
950 }
951
952 bool same_size = true;
953
954 if (dimensions.length () != n)
955 {
956 same_size = false;
957 }
958 else
959 {
960 for (octave_idx_type i = 0; i < n; i++)
961 {
962 if (dv(i) != dimensions(i))
963 {
964 same_size = false;
965 break;
966 }
967 }
968 }
969
970 if (same_size)
971 return;
972
973 typename Array<T>::ArrayRep *old_rep = rep;
974 const T *old_data = data ();
975
976 octave_idx_type len = get_size (dv);
977
978 rep = new typename Array<T>::ArrayRep (len);
979
980 dim_vector dv_old = dimensions;
981 octave_idx_type dv_old_orig_len = dv_old.length ();
982 dimensions = dv;
983
984 if (len > 0 && dv_old_orig_len > 0)
985 {
986 Array<octave_idx_type> ra_idx (dimensions.length (), 0);
987
988 if (n > dv_old_orig_len)
989 {
990 dv_old.resize (n);
991
992 for (octave_idx_type i = dv_old_orig_len; i < n; i++)
993 dv_old.elem (i) = 1;
994 }
995
996 for (octave_idx_type i = 0; i < len; i++)
997 {
998 if (index_in_bounds (ra_idx, dv_old))
999 rep->elem (i) = old_data[get_scalar_idx (ra_idx, dv_old)];
1000 else
1001 rep->elem (i) = val;
1002
1003 increment_index (ra_idx, dimensions);
1004 }
1005 }
1006 else
1007 for (octave_idx_type i = 0; i < len; i++)
1008 rep->elem (i) = val;
1009
1010 if (--old_rep->count <= 0)
1011 delete old_rep;
1012 }
1013 1447
1014 template <class T> 1448 template <class T>
1015 Array<T>& 1449 Array<T>&
1016 Array<T>::insert (const Array<T>& a, octave_idx_type r, octave_idx_type c) 1450 Array<T>::insert (const Array<T>& a, octave_idx_type r, octave_idx_type c)
1017 { 1451 {
1191 (*current_liboctave_error_handler) 1625 (*current_liboctave_error_handler)
1192 ("Array<T>::insert: invalid indexing operation"); 1626 ("Array<T>::insert: invalid indexing operation");
1193 1627
1194 return *this; 1628 return *this;
1195 } 1629 }
1630
1196 1631
1197 template <class T> 1632 template <class T>
1198 Array<T> 1633 Array<T>
1199 Array<T>::transpose (void) const 1634 Array<T>::transpose (void) const
1200 { 1635 {
1401 new_dims(i) = dimensions(i); 1836 new_dims(i) = dimensions(i);
1402 } 1837 }
1403 1838
1404 if (nd != new_dims.length ()) 1839 if (nd != new_dims.length ())
1405 dimensions = new_dims; 1840 dimensions = new_dims;
1406 }
1407
1408 template <class T>
1409 void
1410 Array<T>::clear_index (void) const
1411 {
1412 delete [] idx;
1413 idx = 0;
1414 idx_count = 0;
1415 }
1416
1417 template <class T>
1418 void
1419 Array<T>::set_index (const idx_vector& idx_arg) const
1420 {
1421 int nd = ndims ();
1422
1423 if (! idx && nd > 0)
1424 idx = new idx_vector [nd];
1425
1426 if (idx_count < nd)
1427 {
1428 idx[idx_count++] = idx_arg;
1429 }
1430 else
1431 {
1432 idx_vector *new_idx = new idx_vector [idx_count+1];
1433
1434 for (int i = 0; i < idx_count; i++)
1435 new_idx[i] = idx[i];
1436
1437 new_idx[idx_count++] = idx_arg;
1438
1439 delete [] idx;
1440
1441 idx = new_idx;
1442 }
1443 }
1444
1445 template <class T>
1446 void
1447 Array<T>::maybe_delete_elements (idx_vector& idx_arg)
1448 {
1449 switch (ndims ())
1450 {
1451 case 1:
1452 maybe_delete_elements_1 (idx_arg);
1453 break;
1454
1455 case 2:
1456 maybe_delete_elements_2 (idx_arg);
1457 break;
1458
1459 default:
1460 (*current_liboctave_error_handler)
1461 ("Array<T>::maybe_delete_elements: invalid operation");
1462 break;
1463 }
1464 }
1465
1466 template <class T>
1467 void
1468 Array<T>::maybe_delete_elements_1 (idx_vector& idx_arg)
1469 {
1470 octave_idx_type len = length ();
1471
1472 if (len == 0)
1473 return;
1474
1475 if (idx_arg.is_colon_equiv (len, 1))
1476 resize_no_fill (0);
1477 else
1478 {
1479 int num_to_delete = idx_arg.length (len);
1480
1481 if (num_to_delete != 0)
1482 {
1483 octave_idx_type new_len = len;
1484
1485 octave_idx_type iidx = 0;
1486
1487 for (octave_idx_type i = 0; i < len; i++)
1488 if (i == idx_arg.elem (iidx))
1489 {
1490 iidx++;
1491 new_len--;
1492
1493 if (iidx == num_to_delete)
1494 break;
1495 }
1496
1497 if (new_len > 0)
1498 {
1499 T *new_data = new T [new_len];
1500
1501 octave_idx_type ii = 0;
1502 iidx = 0;
1503 for (octave_idx_type i = 0; i < len; i++)
1504 {
1505 if (iidx < num_to_delete && i == idx_arg.elem (iidx))
1506 iidx++;
1507 else
1508 {
1509 new_data[ii] = xelem (i);
1510 ii++;
1511 }
1512 }
1513
1514 if (--rep->count <= 0)
1515 delete rep;
1516
1517 rep = new typename Array<T>::ArrayRep (new_data, new_len);
1518
1519 dimensions.resize (1);
1520 dimensions(0) = new_len;
1521 }
1522 else
1523 (*current_liboctave_error_handler)
1524 ("A(idx) = []: index out of range");
1525 }
1526 }
1527 }
1528
1529 template <class T>
1530 void
1531 Array<T>::maybe_delete_elements_2 (idx_vector& idx_arg)
1532 {
1533 assert (ndims () == 2);
1534
1535 octave_idx_type nr = dim1 ();
1536 octave_idx_type nc = dim2 ();
1537
1538 if (idx_arg.is_colon ())
1539 {
1540 // A(:) = [] always gives 0-by-0 matrix, even if A was empty.
1541 resize_no_fill (0, 0);
1542 return;
1543 }
1544
1545 octave_idx_type n;
1546 if (nr == 1)
1547 n = nc;
1548 else if (nc == 1)
1549 n = nr;
1550 else if (! idx_arg.orig_empty ())
1551 {
1552 // Reshape to row vector for Matlab compatibility.
1553
1554 n = nr * nc;
1555 nr = 1;
1556 nc = n;
1557 }
1558 else
1559 return;
1560
1561 idx_arg.sort (true);
1562
1563 if (idx_arg.is_colon_equiv (n, 1))
1564 {
1565 if (nr == 1)
1566 resize_no_fill (1, 0);
1567 else if (nc == 1)
1568 resize_no_fill (0, 1);
1569 return;
1570 }
1571
1572 octave_idx_type num_to_delete = idx_arg.length (n);
1573
1574 if (num_to_delete != 0)
1575 {
1576 octave_idx_type new_n = n;
1577
1578 octave_idx_type iidx = 0;
1579
1580 for (octave_idx_type i = 0; i < n; i++)
1581 if (i == idx_arg.elem (iidx))
1582 {
1583 iidx++;
1584 new_n--;
1585
1586 if (iidx == num_to_delete)
1587 break;
1588 }
1589
1590 if (new_n > 0)
1591 {
1592 T *new_data = new T [new_n];
1593
1594 octave_idx_type ii = 0;
1595 iidx = 0;
1596 for (octave_idx_type i = 0; i < n; i++)
1597 {
1598 if (iidx < num_to_delete && i == idx_arg.elem (iidx))
1599 iidx++;
1600 else
1601 {
1602 new_data[ii] = xelem (i);
1603
1604 ii++;
1605 }
1606 }
1607
1608 if (--(Array<T>::rep)->count <= 0)
1609 delete Array<T>::rep;
1610
1611 Array<T>::rep = new typename Array<T>::ArrayRep (new_data, new_n);
1612
1613 dimensions.resize (2);
1614
1615 if (nr == 1)
1616 {
1617 dimensions(0) = 1;
1618 dimensions(1) = new_n;
1619 }
1620 else
1621 {
1622 dimensions(0) = new_n;
1623 dimensions(1) = 1;
1624 }
1625 }
1626 else
1627 (*current_liboctave_error_handler)
1628 ("A(idx) = []: index out of range");
1629 }
1630 }
1631
1632 template <class T>
1633 void
1634 Array<T>::maybe_delete_elements (idx_vector& idx_i, idx_vector& idx_j)
1635 {
1636 assert (ndims () == 2);
1637
1638 octave_idx_type nr = dim1 ();
1639 octave_idx_type nc = dim2 ();
1640
1641 if (idx_i.is_colon () && idx_j.is_colon ())
1642 {
1643 // A special case: A(:,:). Matlab gives 0-by-nc here, but perhaps we
1644 // should not?
1645 resize_no_fill (0, nc);
1646 }
1647 else if (idx_i.is_colon ())
1648 {
1649 idx_j.sort (true); // sort in advance to speed-up the following check
1650
1651 if (idx_j.is_colon_equiv (nc, 1))
1652 resize_no_fill (nr, 0);
1653 else
1654 {
1655 octave_idx_type num_to_delete = idx_j.length (nc);
1656
1657 if (num_to_delete != 0)
1658 {
1659 octave_idx_type new_nc = nc;
1660
1661 octave_idx_type iidx = 0;
1662
1663 for (octave_idx_type j = 0; j < nc; j++)
1664 if (j == idx_j.elem (iidx))
1665 {
1666 iidx++;
1667 new_nc--;
1668
1669 if (iidx == num_to_delete)
1670 break;
1671 }
1672
1673 if (new_nc > 0)
1674 {
1675 T *new_data = new T [nr * new_nc];
1676
1677 octave_idx_type jj = 0;
1678 iidx = 0;
1679 for (octave_idx_type j = 0; j < nc; j++)
1680 {
1681 if (iidx < num_to_delete && j == idx_j.elem (iidx))
1682 iidx++;
1683 else
1684 {
1685 for (octave_idx_type i = 0; i < nr; i++)
1686 new_data[nr*jj+i] = xelem (i, j);
1687 jj++;
1688 }
1689 }
1690
1691 if (--(Array<T>::rep)->count <= 0)
1692 delete Array<T>::rep;
1693
1694 Array<T>::rep = new typename Array<T>::ArrayRep (new_data, nr * new_nc);
1695
1696 dimensions.resize (2);
1697 dimensions(1) = new_nc;
1698 }
1699 else
1700 (*current_liboctave_error_handler)
1701 ("A(idx) = []: index out of range");
1702 }
1703 }
1704 }
1705 else if (idx_j.is_colon ())
1706 {
1707 idx_i.sort (true); // sort in advance to speed-up the following check
1708
1709 if (idx_i.is_colon_equiv (nr, 1))
1710 resize_no_fill (0, nc);
1711 else
1712 {
1713 octave_idx_type num_to_delete = idx_i.length (nr);
1714
1715 if (num_to_delete != 0)
1716 {
1717 octave_idx_type new_nr = nr;
1718
1719 octave_idx_type iidx = 0;
1720
1721 for (octave_idx_type i = 0; i < nr; i++)
1722 if (i == idx_i.elem (iidx))
1723 {
1724 iidx++;
1725 new_nr--;
1726
1727 if (iidx == num_to_delete)
1728 break;
1729 }
1730
1731 if (new_nr > 0)
1732 {
1733 T *new_data = new T [new_nr * nc];
1734
1735 octave_idx_type ii = 0;
1736 iidx = 0;
1737 for (octave_idx_type i = 0; i < nr; i++)
1738 {
1739 if (iidx < num_to_delete && i == idx_i.elem (iidx))
1740 iidx++;
1741 else
1742 {
1743 for (octave_idx_type j = 0; j < nc; j++)
1744 new_data[new_nr*j+ii] = xelem (i, j);
1745 ii++;
1746 }
1747 }
1748
1749 if (--(Array<T>::rep)->count <= 0)
1750 delete Array<T>::rep;
1751
1752 Array<T>::rep = new typename Array<T>::ArrayRep (new_data, new_nr * nc);
1753
1754 dimensions.resize (2);
1755 dimensions(0) = new_nr;
1756 }
1757 else
1758 (*current_liboctave_error_handler)
1759 ("A(idx) = []: index out of range");
1760 }
1761 }
1762 }
1763 else if (! (idx_i.orig_empty () || idx_j.orig_empty ()))
1764 {
1765 (*current_liboctave_error_handler)
1766 ("a null assignment can have only one non-colon index");
1767 }
1768 }
1769
1770 template <class T>
1771 void
1772 Array<T>::maybe_delete_elements (idx_vector&, idx_vector&, idx_vector&)
1773 {
1774 assert (0);
1775 }
1776
1777 template <class T>
1778 void
1779 Array<T>::maybe_delete_elements (Array<idx_vector>& ra_idx)
1780 {
1781 octave_idx_type n_idx = ra_idx.length ();
1782
1783 // Special case matrices
1784 if (ndims () == 2)
1785 {
1786 if (n_idx == 1)
1787 {
1788 maybe_delete_elements (ra_idx (0));
1789 return;
1790 }
1791 else if (n_idx == 2)
1792 {
1793 maybe_delete_elements (ra_idx (0), ra_idx (1));
1794 return;
1795 }
1796 }
1797
1798 dim_vector lhs_dims = dims ();
1799
1800 int n_lhs_dims = lhs_dims.length ();
1801
1802 if (lhs_dims.all_zero ())
1803 return;
1804
1805 if (n_idx == 1 && ra_idx(0).is_colon ())
1806 {
1807 resize (dim_vector (0, 0));
1808 return;
1809 }
1810
1811 if (n_idx > n_lhs_dims)
1812 {
1813 for (int i = n_idx; i < n_lhs_dims; i++)
1814 {
1815 // Ensure that extra indices are either colon or 1.
1816
1817 if (! ra_idx(i).is_colon_equiv (1, 1))
1818 {
1819 (*current_liboctave_error_handler)
1820 ("index exceeds array dimensions");
1821 return;
1822 }
1823 }
1824
1825 ra_idx.resize (n_lhs_dims);
1826
1827 n_idx = n_lhs_dims;
1828 }
1829
1830 Array<int> idx_is_colon (n_idx, 0);
1831
1832 Array<int> idx_is_colon_equiv (n_idx, 0);
1833
1834 // Initialization of colon arrays.
1835
1836 for (octave_idx_type i = 0; i < n_idx; i++)
1837 {
1838 if (ra_idx(i).orig_empty ()) return;
1839 idx_is_colon_equiv(i) = ra_idx(i).is_colon_equiv (lhs_dims(i), 1);
1840
1841 idx_is_colon(i) = ra_idx(i).is_colon ();
1842 }
1843
1844 bool idx_ok = true;
1845
1846 // Check for index out of bounds.
1847
1848 for (octave_idx_type i = 0 ; i < n_idx - 1; i++)
1849 {
1850 if (! (idx_is_colon(i) || idx_is_colon_equiv(i)))
1851 {
1852 ra_idx(i).sort (true);
1853
1854 if (ra_idx(i).max () > lhs_dims(i))
1855 {
1856 (*current_liboctave_error_handler)
1857 ("index exceeds array dimensions");
1858
1859 idx_ok = false;
1860 break;
1861 }
1862 else if (ra_idx(i).min () < 0) // I believe this is checked elsewhere
1863 {
1864 (*current_liboctave_error_handler)
1865 ("index must be one or larger");
1866
1867 idx_ok = false;
1868 break;
1869 }
1870 }
1871 }
1872
1873 if (n_idx <= n_lhs_dims)
1874 {
1875 octave_idx_type last_idx = ra_idx(n_idx-1).max ();
1876
1877 octave_idx_type sum_el = lhs_dims(n_idx-1);
1878
1879 for (octave_idx_type i = n_idx; i < n_lhs_dims; i++)
1880 sum_el *= lhs_dims(i);
1881
1882 if (last_idx > sum_el - 1)
1883 {
1884 (*current_liboctave_error_handler)
1885 ("index exceeds array dimensions");
1886
1887 idx_ok = false;
1888 }
1889 }
1890
1891 if (idx_ok)
1892 {
1893 if (n_idx > 1
1894 && (all_ones (idx_is_colon)))
1895 {
1896 // A(:,:,:) -- we are deleting elements in all dimensions, so
1897 // the result is [](0x0x0).
1898
1899 dim_vector newdim = dims ();
1900 newdim(0) = 0;
1901
1902 resize (newdim);
1903 }
1904
1905 else if (n_idx > 1
1906 && num_ones (idx_is_colon) == n_idx - 1
1907 && num_ones (idx_is_colon_equiv) == n_idx)
1908 {
1909 // A(:,:,j) -- we are deleting elements in one dimension by
1910 // enumerating them.
1911 //
1912 // If we enumerate all of the elements, we should have zero
1913 // elements in that dimension with the same number of elements
1914 // in the other dimensions that we started with.
1915
1916 dim_vector temp_dims;
1917 temp_dims.resize (n_idx);
1918
1919 for (octave_idx_type i = 0; i < n_idx; i++)
1920 {
1921 if (idx_is_colon (i))
1922 temp_dims(i) = lhs_dims(i);
1923 else
1924 temp_dims(i) = 0;
1925 }
1926
1927 resize (temp_dims);
1928 }
1929 else if (n_idx > 1 && num_ones (idx_is_colon) == n_idx - 1)
1930 {
1931 // We have colons in all indices except for one.
1932 // This index tells us which slice to delete
1933
1934 if (n_idx < n_lhs_dims)
1935 {
1936 // Collapse dimensions beyond last index.
1937
1938 if (! (ra_idx(n_idx-1).is_colon ()))
1939 (*current_liboctave_warning_with_id_handler)
1940 ("Octave:fortran-indexing",
1941 "fewer indices than dimensions for N-d array");
1942
1943 for (octave_idx_type i = n_idx; i < n_lhs_dims; i++)
1944 lhs_dims(n_idx-1) *= lhs_dims(i);
1945
1946 lhs_dims.resize (n_idx);
1947
1948 // Reshape *this.
1949 dimensions = lhs_dims;
1950 }
1951
1952 int non_col = 0;
1953
1954 // Find the non-colon column.
1955
1956 for (octave_idx_type i = 0; i < n_idx; i++)
1957 {
1958 if (! idx_is_colon(i))
1959 non_col = i;
1960 }
1961
1962 // The length of the non-colon dimension.
1963
1964 octave_idx_type non_col_dim = lhs_dims (non_col);
1965
1966 octave_idx_type num_to_delete = ra_idx(non_col).length (lhs_dims (non_col));
1967
1968 if (num_to_delete > 0)
1969 {
1970 int temp = lhs_dims.num_ones ();
1971
1972 if (non_col_dim == 1)
1973 temp--;
1974
1975 if (temp == n_idx - 1 && num_to_delete == non_col_dim)
1976 {
1977 // We have A with (1x1x4), where A(1,:,1:4)
1978 // Delete all (0x0x0)
1979
1980 dim_vector zero_dims (n_idx, 0);
1981
1982 resize (zero_dims);
1983 }
1984 else
1985 {
1986 // New length of non-colon dimension
1987 // (calculated in the next for loop)
1988
1989 octave_idx_type new_dim = non_col_dim;
1990
1991 octave_idx_type iidx = 0;
1992
1993 for (octave_idx_type j = 0; j < non_col_dim; j++)
1994 if (j == ra_idx(non_col).elem (iidx))
1995 {
1996 iidx++;
1997
1998 new_dim--;
1999
2000 if (iidx == num_to_delete)
2001 break;
2002 }
2003
2004 // Creating the new nd array after deletions.
2005
2006 if (new_dim > 0)
2007 {
2008 // Calculate number of elements in new array.
2009
2010 octave_idx_type num_new_elem=1;
2011
2012 for (int i = 0; i < n_idx; i++)
2013 {
2014 if (i == non_col)
2015 num_new_elem *= new_dim;
2016
2017 else
2018 num_new_elem *= lhs_dims(i);
2019 }
2020
2021 T *new_data = new T [num_new_elem];
2022
2023 Array<octave_idx_type> result_idx (n_lhs_dims, 0);
2024
2025 dim_vector new_lhs_dim = lhs_dims;
2026
2027 new_lhs_dim(non_col) = new_dim;
2028
2029 octave_idx_type num_elem = 1;
2030
2031 octave_idx_type numidx = 0;
2032
2033 octave_idx_type n = length ();
2034
2035 for (int i = 0; i < n_lhs_dims; i++)
2036 if (i != non_col)
2037 num_elem *= lhs_dims(i);
2038
2039 num_elem *= ra_idx(non_col).capacity ();
2040
2041 for (octave_idx_type i = 0; i < n; i++)
2042 {
2043 if (numidx < num_elem
2044 && is_in (result_idx(non_col), ra_idx(non_col)))
2045 numidx++;
2046
2047 else
2048 {
2049 Array<octave_idx_type> temp_result_idx = result_idx;
2050
2051 octave_idx_type num_lgt = how_many_lgt (result_idx(non_col),
2052 ra_idx(non_col));
2053
2054 temp_result_idx(non_col) -= num_lgt;
2055
2056 octave_idx_type kidx
2057 = ::compute_index (temp_result_idx, new_lhs_dim);
2058
2059 new_data[kidx] = xelem (result_idx);
2060 }
2061
2062 increment_index (result_idx, lhs_dims);
2063 }
2064
2065 if (--rep->count <= 0)
2066 delete rep;
2067
2068 rep = new typename Array<T>::ArrayRep (new_data,
2069 num_new_elem);
2070
2071 dimensions = new_lhs_dim;
2072 }
2073 }
2074 }
2075 }
2076 else if (n_idx == 1)
2077 {
2078 // This handle cases where we only have one index (not
2079 // colon). The index denotes which elements we should
2080 // delete in the array which can be of any dimension. We
2081 // return a column vector, except for the case where we are
2082 // operating on a row vector. The elements are numerated
2083 // column by column.
2084 //
2085 // A(3,3,3)=2;
2086 // A(3:5) = []; A(6)=[]
2087
2088 octave_idx_type lhs_numel = numel ();
2089
2090 idx_vector idx_vec = ra_idx(0);
2091
2092 idx_vec.freeze (lhs_numel, 0, true);
2093
2094 idx_vec.sort (true);
2095
2096 octave_idx_type num_to_delete = idx_vec.length (lhs_numel);
2097
2098 if (num_to_delete > 0)
2099 {
2100 octave_idx_type new_numel = lhs_numel - num_to_delete;
2101
2102 T *new_data = new T[new_numel];
2103
2104 Array<octave_idx_type> lhs_ra_idx (ndims (), 0);
2105
2106 octave_idx_type ii = 0;
2107 octave_idx_type iidx = 0;
2108
2109 for (octave_idx_type i = 0; i < lhs_numel; i++)
2110 {
2111 if (iidx < num_to_delete && i == idx_vec.elem (iidx))
2112 {
2113 iidx++;
2114 }
2115 else
2116 {
2117 new_data[ii++] = xelem (lhs_ra_idx);
2118 }
2119
2120 increment_index (lhs_ra_idx, lhs_dims);
2121 }
2122
2123 if (--(Array<T>::rep)->count <= 0)
2124 delete Array<T>::rep;
2125
2126 Array<T>::rep = new typename Array<T>::ArrayRep (new_data, new_numel);
2127
2128 dimensions.resize (2);
2129
2130 if (lhs_dims.length () == 2 && lhs_dims(1) == 1)
2131 {
2132 dimensions(0) = new_numel;
2133 dimensions(1) = 1;
2134 }
2135 else
2136 {
2137 dimensions(0) = 1;
2138 dimensions(1) = new_numel;
2139 }
2140 }
2141 }
2142 else if (num_ones (idx_is_colon) < n_idx)
2143 {
2144 (*current_liboctave_error_handler)
2145 ("a null assignment can have only one non-colon index");
2146 }
2147 }
2148 }
2149
2150 template <class T>
2151 Array<T>
2152 Array<T>::value (void) const
2153 {
2154 Array<T> retval;
2155
2156 int n_idx = index_count ();
2157
2158 if (n_idx == 2)
2159 {
2160 idx_vector *tmp = get_idx ();
2161
2162 idx_vector idx_i = tmp[0];
2163 idx_vector idx_j = tmp[1];
2164
2165 retval = index (idx_i, idx_j);
2166 }
2167 else if (n_idx == 1)
2168 {
2169 retval = index (idx[0]);
2170 }
2171 else
2172 {
2173 clear_index ();
2174
2175 (*current_liboctave_error_handler)
2176 ("Array<T>::value: invalid number of indices specified");
2177 }
2178
2179 clear_index ();
2180
2181 return retval;
2182 }
2183
2184 template <class T>
2185 Array<T>
2186 Array<T>::index (idx_vector& idx_arg, int resize_ok, const T& rfv) const
2187 {
2188 Array<T> retval;
2189
2190 dim_vector dv = idx_arg.orig_dimensions ();
2191
2192 if (dv.length () > 2 || ndims () > 2)
2193 retval = indexN (idx_arg, resize_ok, rfv);
2194 else
2195 {
2196 switch (ndims ())
2197 {
2198 case 1:
2199 retval = index1 (idx_arg, resize_ok, rfv);
2200 break;
2201
2202 case 2:
2203 retval = index2 (idx_arg, resize_ok, rfv);
2204 break;
2205
2206 default:
2207 (*current_liboctave_error_handler)
2208 ("invalid array (internal error)");
2209 break;
2210 }
2211 }
2212
2213 return retval;
2214 }
2215
2216 template <class T>
2217 Array<T>
2218 Array<T>::index1 (idx_vector& idx_arg, int resize_ok, const T& rfv) const
2219 {
2220 Array<T> retval;
2221
2222 octave_idx_type len = length ();
2223
2224 octave_idx_type n = idx_arg.freeze (len, "vector", resize_ok);
2225
2226 if (idx_arg)
2227 {
2228 if (idx_arg.is_colon_equiv (len))
2229 {
2230 retval = *this;
2231 }
2232 else if (n == 0)
2233 {
2234 retval.resize_no_fill (0);
2235 }
2236 else
2237 {
2238 retval.resize_no_fill (n);
2239
2240 for (octave_idx_type i = 0; i < n; i++)
2241 {
2242 octave_idx_type ii = idx_arg.elem (i);
2243 if (ii >= len)
2244 retval.elem (i) = rfv;
2245 else
2246 retval.elem (i) = elem (ii);
2247 }
2248 }
2249 }
2250
2251 // idx_vector::freeze() printed an error message for us.
2252
2253 return retval;
2254 }
2255
2256 template <class T>
2257 Array<T>
2258 Array<T>::index2 (idx_vector& idx_arg, int resize_ok, const T& rfv) const
2259 {
2260 Array<T> retval;
2261
2262 assert (ndims () == 2);
2263
2264 octave_idx_type nr = dim1 ();
2265 octave_idx_type nc = dim2 ();
2266
2267 octave_idx_type orig_len = nr * nc;
2268
2269 dim_vector idx_orig_dims = idx_arg.orig_dimensions ();
2270
2271 octave_idx_type idx_orig_rows = idx_arg.orig_rows ();
2272 octave_idx_type idx_orig_columns = idx_arg.orig_columns ();
2273
2274 if (idx_arg.is_colon ())
2275 {
2276 // Fast magic colon processing.
2277
2278 octave_idx_type result_nr = nr * nc;
2279 octave_idx_type result_nc = 1;
2280
2281 retval = Array<T> (*this, dim_vector (result_nr, result_nc));
2282 }
2283 else if (nr == 1 && nc == 1)
2284 {
2285 Array<T> tmp = Array<T>::index1 (idx_arg, resize_ok);
2286
2287 octave_idx_type len = tmp.length ();
2288
2289 if (len >= idx_orig_dims.numel ())
2290 retval = Array<T> (tmp, idx_orig_dims);
2291 }
2292 else if (nr == 1 || nc == 1)
2293 {
2294 // If indexing a vector with a matrix, return value has same
2295 // shape as the index. Otherwise, it has same orientation as
2296 // indexed object.
2297
2298 Array<T> tmp = Array<T>::index1 (idx_arg, resize_ok);
2299
2300 octave_idx_type len = tmp.length ();
2301
2302 if (idx_orig_rows == 1 || idx_orig_columns == 1)
2303 {
2304 if (nr == 1)
2305 retval = Array<T> (tmp, dim_vector (1, len));
2306 else
2307 retval = Array<T> (tmp, dim_vector (len, 1));
2308 }
2309 else if (len >= idx_orig_dims.numel ())
2310 retval = Array<T> (tmp, idx_orig_dims);
2311 }
2312 else
2313 {
2314 (*current_liboctave_warning_with_id_handler)
2315 ("Octave:fortran-indexing", "single index used for matrix");
2316
2317 // This code is only for indexing matrices. The vector
2318 // cases are handled above.
2319
2320 idx_arg.freeze (nr * nc, "matrix", resize_ok);
2321
2322 if (idx_arg)
2323 {
2324 octave_idx_type result_nr = idx_orig_rows;
2325 octave_idx_type result_nc = idx_orig_columns;
2326
2327 retval.resize_no_fill (result_nr, result_nc);
2328
2329 octave_idx_type k = 0;
2330 for (octave_idx_type j = 0; j < result_nc; j++)
2331 {
2332 for (octave_idx_type i = 0; i < result_nr; i++)
2333 {
2334 octave_idx_type ii = idx_arg.elem (k++);
2335 if (ii >= orig_len)
2336 retval.elem (i, j) = rfv;
2337 else
2338 {
2339 octave_idx_type fr = ii % nr;
2340 octave_idx_type fc = (ii - fr) / nr;
2341 retval.elem (i, j) = elem (fr, fc);
2342 }
2343 }
2344 }
2345 }
2346 // idx_vector::freeze() printed an error message for us.
2347 }
2348
2349 return retval;
2350 }
2351
2352 template <class T>
2353 Array<T>
2354 Array<T>::indexN (idx_vector& ra_idx, int resize_ok, const T& rfv) const
2355 {
2356 Array<T> retval;
2357
2358 dim_vector dv = dims ();
2359
2360 int n_dims = dv.length ();
2361
2362 octave_idx_type orig_len = dv.numel ();
2363
2364 dim_vector idx_orig_dims = ra_idx.orig_dimensions ();
2365
2366 if (ra_idx.is_colon ())
2367 {
2368 // Fast magic colon processing.
2369
2370 retval = Array<T> (*this, dim_vector (orig_len, 1));
2371 }
2372 else
2373 {
2374 bool vec_equiv = vector_equivalent (dv);
2375
2376 if (! (vec_equiv || ra_idx.is_colon ()))
2377 (*current_liboctave_warning_with_id_handler)
2378 ("Octave:fortran-indexing", "single index used for N-d array");
2379
2380 octave_idx_type frozen_len
2381 = ra_idx.freeze (orig_len, "nd-array", resize_ok);
2382
2383 if (ra_idx)
2384 {
2385 dim_vector result_dims;
2386
2387 if (vec_equiv && ! orig_len == 1)
2388 {
2389 result_dims = dv;
2390
2391 for (int i = 0; i < n_dims; i++)
2392 {
2393 if (result_dims(i) != 1)
2394 {
2395 // All but this dim should be one.
2396 result_dims(i) = frozen_len;
2397 break;
2398 }
2399 }
2400 }
2401 else
2402 result_dims = idx_orig_dims;
2403
2404 result_dims.chop_trailing_singletons ();
2405
2406 retval.resize (result_dims);
2407
2408 octave_idx_type n = result_dims.numel ();
2409
2410 octave_idx_type k = 0;
2411
2412 for (octave_idx_type i = 0; i < n; i++)
2413 {
2414 octave_idx_type ii = ra_idx.elem (k++);
2415
2416 if (ii >= orig_len)
2417 retval.elem (i) = rfv;
2418 else
2419 retval.elem (i) = elem (ii);
2420 }
2421 }
2422 }
2423
2424 return retval;
2425 }
2426
2427 template <class T>
2428 Array<T>
2429 Array<T>::index (idx_vector& idx_i, idx_vector& idx_j, int resize_ok,
2430 const T& rfv) const
2431 {
2432 Array<T> retval;
2433
2434 if (ndims () != 2)
2435 {
2436 Array<idx_vector> ra_idx (2);
2437 ra_idx(0) = idx_i;
2438 ra_idx(1) = idx_j;
2439 return index (ra_idx, resize_ok, rfv);
2440 }
2441
2442 octave_idx_type nr = dim1 ();
2443 octave_idx_type nc = dim2 ();
2444
2445 octave_idx_type n = idx_i.freeze (nr, "row", resize_ok);
2446 octave_idx_type m = idx_j.freeze (nc, "column", resize_ok);
2447
2448 if (idx_i && idx_j)
2449 {
2450 if (idx_i.orig_empty () || idx_j.orig_empty () || n == 0 || m == 0)
2451 {
2452 retval.resize_no_fill (n, m);
2453 }
2454 else if (idx_i.is_colon_equiv (nr) && idx_j.is_colon_equiv (nc))
2455 {
2456 retval = *this;
2457 }
2458 else
2459 {
2460 retval.resize_no_fill (n, m);
2461
2462 for (octave_idx_type j = 0; j < m; j++)
2463 {
2464 octave_idx_type jj = idx_j.elem (j);
2465 for (octave_idx_type i = 0; i < n; i++)
2466 {
2467 octave_idx_type ii = idx_i.elem (i);
2468 if (ii >= nr || jj >= nc)
2469 retval.elem (i, j) = rfv;
2470 else
2471 retval.elem (i, j) = elem (ii, jj);
2472 }
2473 }
2474 }
2475 }
2476
2477 // idx_vector::freeze() printed an error message for us.
2478
2479 return retval;
2480 }
2481
2482 template <class T>
2483 Array<T>
2484 Array<T>::index (Array<idx_vector>& ra_idx, int resize_ok, const T& rfv) const
2485 {
2486 // This function handles all calls with more than one idx.
2487 // For (3x3x3), the call can be A(2,5), A(2,:,:), A(3,2,3) etc.
2488
2489 Array<T> retval;
2490
2491 int n_dims = dimensions.length ();
2492
2493 // Remove trailing singletons in ra_idx, but leave at least ndims
2494 // elements.
2495
2496 octave_idx_type ra_idx_len = ra_idx.length ();
2497
2498 bool trim_trailing_singletons = true;
2499 for (octave_idx_type j = ra_idx_len; j > n_dims; j--)
2500 {
2501 idx_vector iidx = ra_idx (ra_idx_len-1);
2502 if (iidx.capacity () == 1 && trim_trailing_singletons)
2503 ra_idx_len--;
2504 else
2505 trim_trailing_singletons = false;
2506
2507 if (! resize_ok)
2508 {
2509 for (octave_idx_type i = 0; i < iidx.capacity (); i++)
2510 if (iidx (i) != 0)
2511 {
2512 (*current_liboctave_error_handler)
2513 ("index exceeds N-d array dimensions");
2514
2515 return retval;
2516 }
2517 }
2518 }
2519
2520 ra_idx.resize (ra_idx_len);
2521
2522 dim_vector new_dims = dims ();
2523 dim_vector frozen_lengths;
2524
2525 if (!ra_idx (ra_idx_len - 1).orig_empty () && ra_idx_len < n_dims)
2526 frozen_lengths = short_freeze (ra_idx, dimensions, resize_ok);
2527 else
2528 {
2529 new_dims.resize (ra_idx_len, 1);
2530 frozen_lengths = freeze (ra_idx, new_dims, resize_ok);
2531 }
2532
2533 if (all_ok (ra_idx))
2534 {
2535 if (any_orig_empty (ra_idx) || frozen_lengths.any_zero ())
2536 {
2537 frozen_lengths.chop_trailing_singletons ();
2538
2539 retval.resize (frozen_lengths);
2540 }
2541 else if (frozen_lengths.length () == n_dims
2542 && all_colon_equiv (ra_idx, dimensions))
2543 {
2544 retval = *this;
2545 }
2546 else
2547 {
2548 dim_vector frozen_lengths_for_resize = frozen_lengths;
2549
2550 frozen_lengths_for_resize.chop_trailing_singletons ();
2551
2552 retval.resize (frozen_lengths_for_resize);
2553
2554 octave_idx_type n = retval.length ();
2555
2556 Array<octave_idx_type> result_idx (ra_idx.length (), 0);
2557
2558 Array<octave_idx_type> elt_idx;
2559
2560 for (octave_idx_type i = 0; i < n; i++)
2561 {
2562 elt_idx = get_elt_idx (ra_idx, result_idx);
2563
2564 octave_idx_type numelem_elt = get_scalar_idx (elt_idx, new_dims);
2565
2566 if (numelem_elt >= length () || numelem_elt < 0)
2567 retval.elem (i) = rfv;
2568 else
2569 retval.elem (i) = elem (numelem_elt);
2570
2571 increment_index (result_idx, frozen_lengths);
2572
2573 }
2574 }
2575 }
2576
2577 return retval;
2578 } 1841 }
2579 1842
2580 template <class T> 1843 template <class T>
2581 bool 1844 bool
2582 ascending_compare (T a, T b) 1845 ascending_compare (T a, T b)
2849 } 2112 }
2850 2113
2851 if (nnr == 1) 2114 if (nnr == 1)
2852 { 2115 {
2853 octave_idx_type n = nnc + std::abs (k); 2116 octave_idx_type n = nnc + std::abs (k);
2854 d = Array<T> (dim_vector (n, n), resize_fill_value (T ())); 2117 d = Array<T> (dim_vector (n, n), resize_fill_value ());
2855 2118
2856 for (octave_idx_type i = 0; i < nnc; i++) 2119 for (octave_idx_type i = 0; i < nnc; i++)
2857 d.xelem (i+roff, i+coff) = elem (0, i); 2120 d.xelem (i+roff, i+coff) = elem (0, i);
2858 } 2121 }
2859 else 2122 else
2860 { 2123 {
2861 octave_idx_type n = nnr + std::abs (k); 2124 octave_idx_type n = nnr + std::abs (k);
2862 d = Array<T> (dim_vector (n, n), resize_fill_value (T ())); 2125 d = Array<T> (dim_vector (n, n), resize_fill_value ());
2863 2126
2864 for (octave_idx_type i = 0; i < nnr; i++) 2127 for (octave_idx_type i = 0; i < nnr; i++)
2865 d.xelem (i+roff, i+coff) = elem (i, 0); 2128 d.xelem (i+roff, i+coff) = elem (i, 0);
2866 } 2129 }
2867 } 2130 }
2868 } 2131 }
2869 2132
2870 return d; 2133 return d;
2871 }
2872
2873 // FIXME -- this is a mess.
2874
2875 template <class LT, class RT>
2876 int
2877 assign (Array<LT>& lhs, const Array<RT>& rhs, const LT& rfv)
2878 {
2879 int n_idx = lhs.index_count ();
2880
2881 // kluge...
2882 if (lhs.ndims () == 0)
2883 lhs.resize_no_fill (0, 0);
2884
2885 return (lhs.ndims () == 2
2886 && (n_idx == 1
2887 || (n_idx < 3
2888 && rhs.ndims () == 2
2889 && rhs.rows () == 0 && rhs.columns () == 0)))
2890 ? assign2 (lhs, rhs, rfv) : assignN (lhs, rhs, rfv);
2891 }
2892
2893 template <class LT, class RT>
2894 int
2895 assign1 (Array<LT>& lhs, const Array<RT>& rhs, const LT& rfv)
2896 {
2897 int retval = 1;
2898
2899 idx_vector *tmp = lhs.get_idx ();
2900
2901 idx_vector lhs_idx = tmp[0];
2902
2903 octave_idx_type lhs_len = lhs.length ();
2904 octave_idx_type rhs_len = rhs.length ();
2905
2906 octave_idx_type n = lhs_idx.freeze (lhs_len, "vector", true);
2907
2908 if (n != 0)
2909 {
2910 dim_vector lhs_dims = lhs.dims ();
2911
2912 if (lhs_len != 0
2913 || lhs_dims.all_zero ()
2914 || (lhs_dims.length () == 2 && lhs_dims(0) < 2))
2915 {
2916 if (rhs_len == n || rhs_len == 1)
2917 {
2918 lhs.make_unique ();
2919
2920 octave_idx_type max_idx = lhs_idx.max () + 1;
2921 if (max_idx > lhs_len)
2922 lhs.resize_and_fill (max_idx, rfv);
2923 }
2924
2925 if (rhs_len == n)
2926 {
2927 lhs.make_unique ();
2928
2929 if (lhs_idx.is_colon ())
2930 {
2931 for (octave_idx_type i = 0; i < n; i++)
2932 lhs.xelem (i) = rhs.elem (i);
2933 }
2934 else
2935 {
2936 for (octave_idx_type i = 0; i < n; i++)
2937 {
2938 octave_idx_type ii = lhs_idx.elem (i);
2939 lhs.xelem (ii) = rhs.elem (i);
2940 }
2941 }
2942 }
2943 else if (rhs_len == 1)
2944 {
2945 lhs.make_unique ();
2946
2947 RT scalar = rhs.elem (0);
2948
2949 if (lhs_idx.is_colon ())
2950 {
2951 for (octave_idx_type i = 0; i < n; i++)
2952 lhs.xelem (i) = scalar;
2953 }
2954 else
2955 {
2956 for (octave_idx_type i = 0; i < n; i++)
2957 {
2958 octave_idx_type ii = lhs_idx.elem (i);
2959 lhs.xelem (ii) = scalar;
2960 }
2961 }
2962 }
2963 else
2964 {
2965 lhs.clear_index ();
2966
2967 (*current_liboctave_error_handler)
2968 ("A(I) = X: X must be a scalar or a vector with same length as I");
2969
2970 retval = 0;
2971 }
2972 }
2973 else
2974 {
2975 lhs.clear_index ();
2976
2977 (*current_liboctave_error_handler)
2978 ("A(I) = X: unable to resize A");
2979
2980 retval = 0;
2981 }
2982 }
2983 else if (lhs_idx.is_colon ())
2984 {
2985 dim_vector lhs_dims = lhs.dims ();
2986
2987 if (lhs_dims.all_zero ())
2988 {
2989 lhs.make_unique ();
2990
2991 lhs.resize_no_fill (rhs_len);
2992
2993 for (octave_idx_type i = 0; i < rhs_len; i++)
2994 lhs.xelem (i) = rhs.elem (i);
2995 }
2996 else if (rhs_len != lhs_len)
2997 {
2998 lhs.clear_index ();
2999
3000 (*current_liboctave_error_handler)
3001 ("A(:) = X: A must be the same size as X");
3002 }
3003 }
3004 else if (! (rhs_len == 1 || rhs_len == 0))
3005 {
3006 lhs.clear_index ();
3007
3008 (*current_liboctave_error_handler)
3009 ("A([]) = X: X must also be an empty matrix or a scalar");
3010
3011 retval = 0;
3012 }
3013
3014 lhs.clear_index ();
3015
3016 return retval;
3017 }
3018
3019 #define MAYBE_RESIZE_LHS \
3020 do \
3021 { \
3022 octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : idx_i.max () + 1; \
3023 octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : idx_j.max () + 1; \
3024 \
3025 octave_idx_type new_nr = max_row_idx > lhs_nr ? max_row_idx : lhs_nr; \
3026 octave_idx_type new_nc = max_col_idx > lhs_nc ? max_col_idx : lhs_nc; \
3027 \
3028 lhs.resize_and_fill (new_nr, new_nc, rfv); \
3029 } \
3030 while (0)
3031
3032 template <class LT, class RT>
3033 int
3034 assign2 (Array<LT>& lhs, const Array<RT>& rhs, const LT& rfv)
3035 {
3036 int retval = 1;
3037
3038 int n_idx = lhs.index_count ();
3039
3040 octave_idx_type lhs_nr = lhs.rows ();
3041 octave_idx_type lhs_nc = lhs.cols ();
3042
3043 Array<RT> xrhs = rhs;
3044
3045 octave_idx_type rhs_nr = xrhs.rows ();
3046 octave_idx_type rhs_nc = xrhs.cols ();
3047
3048 if (xrhs.ndims () > 2)
3049 {
3050 xrhs = xrhs.squeeze ();
3051
3052 dim_vector dv_tmp = xrhs.dims ();
3053
3054 switch (dv_tmp.length ())
3055 {
3056 case 1:
3057 // FIXME -- this case should be unnecessary, because
3058 // squeeze should always return an object with 2 dimensions.
3059 if (rhs_nr == 1)
3060 rhs_nc = dv_tmp.elem (0);
3061 break;
3062
3063 case 2:
3064 rhs_nr = dv_tmp.elem (0);
3065 rhs_nc = dv_tmp.elem (1);
3066 break;
3067
3068 default:
3069 lhs.clear_index ();
3070 (*current_liboctave_error_handler)
3071 ("Array<T>::assign2: Dimension mismatch");
3072 return 0;
3073 }
3074 }
3075
3076 bool rhs_is_scalar = rhs_nr == 1 && rhs_nc == 1;
3077
3078 idx_vector *tmp = lhs.get_idx ();
3079
3080 idx_vector idx_i;
3081 idx_vector idx_j;
3082
3083 if (n_idx > 1)
3084 idx_j = tmp[1];
3085
3086 if (n_idx > 0)
3087 idx_i = tmp[0];
3088
3089 if (n_idx == 2)
3090 {
3091 octave_idx_type n = idx_i.freeze (lhs_nr, "row", true);
3092 octave_idx_type m = idx_j.freeze (lhs_nc, "column", true);
3093
3094 int idx_i_is_colon = idx_i.is_colon ();
3095 int idx_j_is_colon = idx_j.is_colon ();
3096
3097 if (lhs_nr == 0 && lhs_nc == 0)
3098 {
3099 if (idx_i_is_colon)
3100 n = rhs_nr;
3101
3102 if (idx_j_is_colon)
3103 m = rhs_nc;
3104 }
3105
3106 if (idx_i && idx_j)
3107 {
3108 if (rhs_is_scalar && n >= 0 && m >= 0)
3109 {
3110 // No need to do anything if either of the indices
3111 // are empty.
3112
3113 if (n > 0 && m > 0)
3114 {
3115 lhs.make_unique ();
3116
3117 MAYBE_RESIZE_LHS;
3118
3119 RT scalar = xrhs.elem (0, 0);
3120
3121 for (octave_idx_type j = 0; j < m; j++)
3122 {
3123 octave_idx_type jj = idx_j.elem (j);
3124 for (octave_idx_type i = 0; i < n; i++)
3125 {
3126 octave_idx_type ii = idx_i.elem (i);
3127 lhs.xelem (ii, jj) = scalar;
3128 }
3129 }
3130 }
3131 }
3132 else if ((n == 1 || m == 1)
3133 && (rhs_nr == 1 || rhs_nc == 1)
3134 && n * m == rhs_nr * rhs_nc)
3135 {
3136 lhs.make_unique ();
3137
3138 MAYBE_RESIZE_LHS;
3139
3140 if (n > 0 && m > 0)
3141 {
3142 octave_idx_type k = 0;
3143
3144 for (octave_idx_type j = 0; j < m; j++)
3145 {
3146 octave_idx_type jj = idx_j.elem (j);
3147 for (octave_idx_type i = 0; i < n; i++)
3148 {
3149 octave_idx_type ii = idx_i.elem (i);
3150 lhs.xelem (ii, jj) = xrhs.elem (k++);
3151 }
3152 }
3153 }
3154 }
3155 else if (n == rhs_nr && m == rhs_nc)
3156 {
3157 lhs.make_unique ();
3158
3159 MAYBE_RESIZE_LHS;
3160
3161 if (n > 0 && m > 0)
3162 {
3163 for (octave_idx_type j = 0; j < m; j++)
3164 {
3165 octave_idx_type jj = idx_j.elem (j);
3166 for (octave_idx_type i = 0; i < n; i++)
3167 {
3168 octave_idx_type ii = idx_i.elem (i);
3169 lhs.xelem (ii, jj) = xrhs.elem (i, j);
3170 }
3171 }
3172 }
3173 }
3174 else if (n == 0 && m == 0)
3175 {
3176 if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0)))
3177 {
3178 lhs.clear_index ();
3179
3180 (*current_liboctave_error_handler)
3181 ("A([], []) = X: X must be an empty matrix or a scalar");
3182
3183 retval = 0;
3184 }
3185 }
3186 else
3187 {
3188 lhs.clear_index ();
3189
3190 (*current_liboctave_error_handler)
3191 ("A(I, J) = X: X must be a scalar or the number of elements in I must match the number of rows in X and the number of elements in J must match the number of columns in X");
3192
3193 retval = 0;
3194 }
3195 }
3196 // idx_vector::freeze() printed an error message for us.
3197 }
3198 else if (n_idx == 1)
3199 {
3200 int lhs_is_empty = lhs_nr == 0 || lhs_nc == 0;
3201
3202 if (lhs_is_empty || (lhs_nr == 1 && lhs_nc == 1))
3203 {
3204 octave_idx_type lhs_len = lhs.length ();
3205
3206 idx_i.freeze (lhs_len, 0, true);
3207
3208 if (idx_i)
3209 {
3210 if (lhs_is_empty
3211 && idx_i.is_colon ()
3212 && ! (rhs_nr == 1 || rhs_nc == 1))
3213 {
3214 (*current_liboctave_warning_with_id_handler)
3215 ("Octave:fortran-indexing",
3216 "A(:) = X: X is not a vector or scalar");
3217 }
3218 else
3219 {
3220 octave_idx_type idx_nr = idx_i.orig_rows ();
3221 octave_idx_type idx_nc = idx_i.orig_columns ();
3222
3223 if (! (rhs_nr == idx_nr && rhs_nc == idx_nc))
3224 (*current_liboctave_warning_with_id_handler)
3225 ("Octave:fortran-indexing",
3226 "A(I) = X: X does not have same shape as I");
3227 }
3228
3229 if (assign1 (lhs, xrhs, rfv))
3230 {
3231 octave_idx_type len = lhs.length ();
3232
3233 if (len > 0)
3234 {
3235 // The following behavior is much simplified
3236 // over previous versions of Octave. It
3237 // seems to be compatible with Matlab.
3238
3239 lhs.dimensions = dim_vector (1, lhs.length ());
3240 }
3241 }
3242 else
3243 retval = 0;
3244 }
3245 // idx_vector::freeze() printed an error message for us.
3246 }
3247 else if (lhs_nr == 1)
3248 {
3249 idx_i.freeze (lhs_nc, "vector", true);
3250
3251 if (idx_i)
3252 {
3253 if (assign1 (lhs, xrhs, rfv))
3254 lhs.dimensions = dim_vector (1, lhs.length ());
3255 else
3256 retval = 0;
3257 }
3258 // idx_vector::freeze() printed an error message for us.
3259 }
3260 else if (lhs_nc == 1)
3261 {
3262 idx_i.freeze (lhs_nr, "vector", true);
3263
3264 if (idx_i)
3265 {
3266 if (assign1 (lhs, xrhs, rfv))
3267 lhs.dimensions = dim_vector (lhs.length (), 1);
3268 else
3269 retval = 0;
3270 }
3271 // idx_vector::freeze() printed an error message for us.
3272 }
3273 else
3274 {
3275 if (! idx_i.is_colon ())
3276 (*current_liboctave_warning_with_id_handler)
3277 ("Octave:fortran-indexing", "single index used for matrix");
3278
3279 octave_idx_type len = idx_i.freeze (lhs_nr * lhs_nc, "matrix");
3280
3281 if (idx_i)
3282 {
3283 if (len == 0)
3284 {
3285 if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0)))
3286 {
3287 lhs.clear_index ();
3288
3289 (*current_liboctave_error_handler)
3290 ("A([]) = X: X must be an empty matrix or scalar");
3291
3292 retval = 0;
3293 }
3294 }
3295 else if (len == rhs_nr * rhs_nc)
3296 {
3297 lhs.make_unique ();
3298
3299 if (idx_i.is_colon ())
3300 {
3301 for (octave_idx_type i = 0; i < len; i++)
3302 lhs.xelem (i) = xrhs.elem (i);
3303 }
3304 else
3305 {
3306 for (octave_idx_type i = 0; i < len; i++)
3307 {
3308 octave_idx_type ii = idx_i.elem (i);
3309 lhs.xelem (ii) = xrhs.elem (i);
3310 }
3311 }
3312 }
3313 else if (rhs_is_scalar)
3314 {
3315 lhs.make_unique ();
3316
3317 RT scalar = rhs.elem (0, 0);
3318
3319 if (idx_i.is_colon ())
3320 {
3321 for (octave_idx_type i = 0; i < len; i++)
3322 lhs.xelem (i) = scalar;
3323 }
3324 else
3325 {
3326 for (octave_idx_type i = 0; i < len; i++)
3327 {
3328 octave_idx_type ii = idx_i.elem (i);
3329 lhs.xelem (ii) = scalar;
3330 }
3331 }
3332 }
3333 else
3334 {
3335 lhs.clear_index ();
3336
3337 (*current_liboctave_error_handler)
3338 ("A(I) = X: X must be a scalar or a matrix with the same size as I");
3339
3340 retval = 0;
3341 }
3342 }
3343 // idx_vector::freeze() printed an error message for us.
3344 }
3345 }
3346 else
3347 {
3348 (*current_liboctave_error_handler)
3349 ("invalid number of indices for matrix expression");
3350
3351 retval = 0;
3352 }
3353
3354 lhs.clear_index ();
3355
3356 return retval;
3357 }
3358
3359 template <class LT, class RT>
3360 int
3361 assignN (Array<LT>& lhs, const Array<RT>& rhs, const LT& rfv)
3362 {
3363 int retval = 1;
3364
3365 dim_vector rhs_dims = rhs.dims ();
3366
3367 octave_idx_type rhs_dims_len = rhs_dims.length ();
3368
3369 bool rhs_is_scalar = is_scalar (rhs_dims);
3370
3371 int n_idx = lhs.index_count ();
3372
3373 idx_vector *idx_vex = lhs.get_idx ();
3374
3375 Array<idx_vector> idx = conv_to_array (idx_vex, n_idx);
3376
3377 if (n_idx == 0)
3378 {
3379 lhs.clear_index ();
3380
3381 (*current_liboctave_error_handler)
3382 ("invalid number of indices for matrix expression");
3383
3384 retval = 0;
3385 }
3386 else if (n_idx == 1)
3387 {
3388 idx_vector iidx = idx(0);
3389 int iidx_is_colon = iidx.is_colon ();
3390
3391 if (! iidx_is_colon)
3392 (*current_liboctave_warning_with_id_handler)
3393 ("Octave:fortran-indexing", "single index used for N-d array");
3394
3395 octave_idx_type lhs_len = lhs.length ();
3396
3397 octave_idx_type len = iidx.freeze (lhs_len, "N-d arrray");
3398
3399 if (iidx)
3400 {
3401 if (len == 0)
3402 {
3403 if (! (rhs_dims.all_ones () || rhs_dims.any_zero ()))
3404 {
3405 lhs.clear_index ();
3406
3407 (*current_liboctave_error_handler)
3408 ("A([]) = X: X must be an empty matrix or scalar");
3409
3410 retval = 0;
3411 }
3412 }
3413 else if (len == rhs.length ())
3414 {
3415 lhs.make_unique ();
3416
3417 if (iidx_is_colon)
3418 {
3419 for (octave_idx_type i = 0; i < len; i++)
3420 lhs.xelem (i) = rhs.elem (i);
3421 }
3422 else
3423 {
3424 for (octave_idx_type i = 0; i < len; i++)
3425 {
3426 octave_idx_type ii = iidx.elem (i);
3427
3428 lhs.xelem (ii) = rhs.elem (i);
3429 }
3430 }
3431 }
3432 else if (rhs_is_scalar)
3433 {
3434 RT scalar = rhs.elem (0);
3435
3436 lhs.make_unique ();
3437
3438 if (iidx_is_colon)
3439 {
3440 for (octave_idx_type i = 0; i < len; i++)
3441 lhs.xelem (i) = scalar;
3442 }
3443 else
3444 {
3445 for (octave_idx_type i = 0; i < len; i++)
3446 {
3447 octave_idx_type ii = iidx.elem (i);
3448
3449 lhs.xelem (ii) = scalar;
3450 }
3451 }
3452 }
3453 else
3454 {
3455 lhs.clear_index ();
3456
3457 (*current_liboctave_error_handler)
3458 ("A(I) = X: X must be a scalar or a matrix with the same size as I");
3459
3460 retval = 0;
3461 }
3462
3463 // idx_vector::freeze() printed an error message for us.
3464 }
3465 }
3466 else
3467 {
3468 // Maybe expand to more dimensions.
3469
3470 dim_vector lhs_dims = lhs.dims ();
3471
3472 octave_idx_type lhs_dims_len = lhs_dims.length ();
3473
3474 dim_vector final_lhs_dims = lhs_dims;
3475
3476 dim_vector frozen_len;
3477
3478 octave_idx_type orig_lhs_dims_len = lhs_dims_len;
3479
3480 bool orig_empty = lhs_dims.all_zero ();
3481
3482 if (n_idx < lhs_dims_len)
3483 {
3484 // Collapse dimensions beyond last index. Note that we
3485 // delay resizing LHS until we know that the assignment will
3486 // succeed.
3487
3488 if (! (idx(n_idx-1).is_colon ()))
3489 (*current_liboctave_warning_with_id_handler)
3490 ("Octave:fortran-indexing",
3491 "fewer indices than dimensions for N-d array");
3492
3493 for (int i = n_idx; i < lhs_dims_len; i++)
3494 lhs_dims(n_idx-1) *= lhs_dims(i);
3495
3496 lhs_dims.resize (n_idx);
3497
3498 lhs_dims_len = lhs_dims.length ();
3499 }
3500
3501 // Resize.
3502
3503 dim_vector new_dims;
3504 new_dims.resize (n_idx);
3505
3506 if (orig_empty)
3507 {
3508 if (rhs_is_scalar)
3509 {
3510 for (int i = 0; i < n_idx; i++)
3511 {
3512 if (idx(i).is_colon ())
3513 new_dims(i) = 1;
3514 else
3515 new_dims(i) = idx(i).orig_empty () ? 0 : idx(i).max () + 1;
3516 }
3517 }
3518 else if (is_vector (rhs_dims))
3519 {
3520 int ncolon = 0;
3521 int fcolon = 0;
3522 octave_idx_type new_dims_numel = 1;
3523 int new_dims_vec = 0;
3524 for (int i = 0; i < n_idx; i++)
3525 if (idx(i).is_colon ())
3526 {
3527 ncolon ++;
3528 if (ncolon == 1)
3529 fcolon = i;
3530 }
3531 else
3532 {
3533 octave_idx_type cap = idx(i).capacity ();
3534 new_dims_numel *= cap;
3535 if (cap != 1)
3536 new_dims_vec ++;
3537 }
3538
3539 if (ncolon == n_idx)
3540 {
3541 new_dims = rhs_dims;
3542 new_dims.resize (n_idx);
3543 for (int i = rhs_dims_len; i < n_idx; i++)
3544 new_dims (i) = 1;
3545 }
3546 else
3547 {
3548 octave_idx_type rhs_dims_numel = rhs_dims.numel ();
3549
3550 for (int i = 0; i < n_idx; i++)
3551 new_dims(i) = idx(i).orig_empty () ? 0 : idx(i).max () + 1;
3552
3553 if (new_dims_numel != rhs_dims_numel &&
3554 ncolon > 0 && new_dims_numel == 1)
3555 {
3556 if (ncolon == rhs_dims_len)
3557 {
3558 int k = 0;
3559 for (int i = 0; i < n_idx; i++)
3560 if (idx(i).is_colon ())
3561 new_dims (i) = rhs_dims (k++);
3562 }
3563 else
3564 new_dims (fcolon) = rhs_dims_numel;
3565 }
3566 else if (new_dims_numel != rhs_dims_numel || new_dims_vec > 1)
3567 {
3568 lhs.clear_index ();
3569
3570 (*current_liboctave_error_handler)
3571 ("A(IDX-LIST) = RHS: mismatched index and RHS dimension");
3572 return retval;
3573 }
3574 }
3575 }
3576 else
3577 {
3578 int k = 0;
3579 for (int i = 0; i < n_idx; i++)
3580 {
3581 if (idx(i).is_colon ())
3582 {
3583 if (k < rhs_dims_len)
3584 new_dims(i) = rhs_dims(k++);
3585 else
3586 new_dims(i) = 1;
3587 }
3588 else
3589 {
3590 octave_idx_type nelem = idx(i).capacity ();
3591
3592 if (nelem >= 1
3593 && (k < rhs_dims_len && nelem == rhs_dims(k)))
3594 k++;
3595 else if (nelem != 1)
3596 {
3597 lhs.clear_index ();
3598
3599 (*current_liboctave_error_handler)
3600 ("A(IDX-LIST) = RHS: mismatched index and RHS dimension");
3601 return retval;
3602 }
3603 new_dims(i) = idx(i).orig_empty () ? 0 :
3604 idx(i).max () + 1;
3605 }
3606 }
3607 }
3608 }
3609 else
3610 {
3611 for (int i = 0; i < n_idx; i++)
3612 {
3613 // We didn't start out with all zero dimensions, so if
3614 // index is a colon, it refers to the current LHS
3615 // dimension. Otherwise, it is OK to enlarge to a
3616 // dimension given by the largest index, but if that
3617 // index is a colon the new dimension is singleton.
3618
3619 if (i < lhs_dims_len
3620 && (idx(i).is_colon ()
3621 || idx(i).orig_empty ()
3622 || idx(i).max () < lhs_dims(i)))
3623 new_dims(i) = lhs_dims(i);
3624 else if (! idx(i).is_colon ())
3625 new_dims(i) = idx(i).max () + 1;
3626 else
3627 new_dims(i) = 1;
3628 }
3629 }
3630
3631 if (retval != 0)
3632 {
3633 if (! orig_empty
3634 && n_idx < orig_lhs_dims_len
3635 && new_dims(n_idx-1) != lhs_dims(n_idx-1))
3636 {
3637 // We reshaped and the last dimension changed. This has to
3638 // be an error, because we don't know how to undo that
3639 // later...
3640
3641 lhs.clear_index ();
3642
3643 (*current_liboctave_error_handler)
3644 ("array index %d (= %d) for assignment requires invalid resizing operation",
3645 n_idx, new_dims(n_idx-1));
3646
3647 retval = 0;
3648 }
3649 else
3650 {
3651 // Determine final dimensions for LHS and reset the
3652 // current size of the LHS. Note that we delay actually
3653 // resizing LHS until we know that the assignment will
3654 // succeed.
3655
3656 if (n_idx < orig_lhs_dims_len)
3657 {
3658 for (int i = 0; i < n_idx-1; i++)
3659 final_lhs_dims(i) = new_dims(i);
3660 }
3661 else
3662 final_lhs_dims = new_dims;
3663
3664 lhs_dims_len = new_dims.length ();
3665
3666 frozen_len = freeze (idx, new_dims, true);
3667
3668 for (int i = 0; i < idx.length (); i++)
3669 {
3670 if (! idx(i))
3671 {
3672 retval = 0;
3673 lhs.clear_index ();
3674 return retval;
3675 }
3676 }
3677
3678 if (rhs_is_scalar)
3679 {
3680 lhs.make_unique ();
3681
3682 if (n_idx < orig_lhs_dims_len)
3683 lhs = lhs.reshape (lhs_dims);
3684
3685 lhs.resize_and_fill (new_dims, rfv);
3686
3687 if (! final_lhs_dims.any_zero ())
3688 {
3689 RT scalar = rhs.elem (0);
3690
3691 if (n_idx == 1)
3692 {
3693 idx_vector iidx = idx(0);
3694
3695 octave_idx_type len = frozen_len(0);
3696
3697 if (iidx.is_colon ())
3698 {
3699 for (octave_idx_type i = 0; i < len; i++)
3700 lhs.xelem (i) = scalar;
3701 }
3702 else
3703 {
3704 for (octave_idx_type i = 0; i < len; i++)
3705 {
3706 octave_idx_type ii = iidx.elem (i);
3707
3708 lhs.xelem (ii) = scalar;
3709 }
3710 }
3711 }
3712 else if (lhs_dims_len == 2 && n_idx == 2)
3713 {
3714 idx_vector idx_i = idx(0);
3715 idx_vector idx_j = idx(1);
3716
3717 octave_idx_type i_len = frozen_len(0);
3718 octave_idx_type j_len = frozen_len(1);
3719
3720 if (idx_i.is_colon())
3721 {
3722 for (octave_idx_type j = 0; j < j_len; j++)
3723 {
3724 octave_idx_type off = new_dims (0) *
3725 idx_j.elem (j);
3726 for (octave_idx_type i = 0; i < i_len; i++)
3727 lhs.xelem (i + off) = scalar;
3728 }
3729 }
3730 else
3731 {
3732 for (octave_idx_type j = 0; j < j_len; j++)
3733 {
3734 octave_idx_type off = new_dims (0) *
3735 idx_j.elem (j);
3736 for (octave_idx_type i = 0; i < i_len; i++)
3737 {
3738 octave_idx_type ii = idx_i.elem (i);
3739 lhs.xelem (ii + off) = scalar;
3740 }
3741 }
3742 }
3743 }
3744 else
3745 {
3746 octave_idx_type n = Array<LT>::get_size (frozen_len);
3747
3748 Array<octave_idx_type> result_idx (lhs_dims_len, 0);
3749
3750 for (octave_idx_type i = 0; i < n; i++)
3751 {
3752 Array<octave_idx_type> elt_idx = get_elt_idx (idx, result_idx);
3753
3754 lhs.xelem (elt_idx) = scalar;
3755
3756 increment_index (result_idx, frozen_len);
3757 }
3758 }
3759 }
3760 }
3761 else
3762 {
3763 // RHS is matrix or higher dimension.
3764
3765 octave_idx_type n = Array<LT>::get_size (frozen_len);
3766
3767 if (n != rhs.numel ())
3768 {
3769 lhs.clear_index ();
3770
3771 (*current_liboctave_error_handler)
3772 ("A(IDX-LIST) = X: X must be a scalar or size of X must equal number of elements indexed by IDX-LIST");
3773
3774 retval = 0;
3775 }
3776 else
3777 {
3778 lhs.make_unique ();
3779
3780 if (n_idx < orig_lhs_dims_len)
3781 lhs = lhs.reshape (lhs_dims);
3782
3783 lhs.resize_and_fill (new_dims, rfv);
3784
3785 if (! final_lhs_dims.any_zero ())
3786 {
3787 if (n_idx == 1)
3788 {
3789 idx_vector iidx = idx(0);
3790
3791 octave_idx_type len = frozen_len(0);
3792
3793 if (iidx.is_colon ())
3794 {
3795 for (octave_idx_type i = 0; i < len; i++)
3796 lhs.xelem (i) = rhs.elem (i);
3797 }
3798 else
3799 {
3800 for (octave_idx_type i = 0; i < len; i++)
3801 {
3802 octave_idx_type ii = iidx.elem (i);
3803
3804 lhs.xelem (ii) = rhs.elem (i);
3805 }
3806 }
3807 }
3808 else if (lhs_dims_len == 2 && n_idx == 2)
3809 {
3810 idx_vector idx_i = idx(0);
3811 idx_vector idx_j = idx(1);
3812
3813 octave_idx_type i_len = frozen_len(0);
3814 octave_idx_type j_len = frozen_len(1);
3815 octave_idx_type k = 0;
3816
3817 if (idx_i.is_colon())
3818 {
3819 for (octave_idx_type j = 0; j < j_len; j++)
3820 {
3821 octave_idx_type off = new_dims (0) *
3822 idx_j.elem (j);
3823 for (octave_idx_type i = 0;
3824 i < i_len; i++)
3825 lhs.xelem (i + off) = rhs.elem (k++);
3826 }
3827 }
3828 else
3829 {
3830 for (octave_idx_type j = 0; j < j_len; j++)
3831 {
3832 octave_idx_type off = new_dims (0) *
3833 idx_j.elem (j);
3834 for (octave_idx_type i = 0; i < i_len; i++)
3835 {
3836 octave_idx_type ii = idx_i.elem (i);
3837 lhs.xelem (ii + off) = rhs.elem (k++);
3838 }
3839 }
3840 }
3841
3842 }
3843 else
3844 {
3845 n = Array<LT>::get_size (frozen_len);
3846
3847 Array<octave_idx_type> result_idx (lhs_dims_len, 0);
3848
3849 for (octave_idx_type i = 0; i < n; i++)
3850 {
3851 Array<octave_idx_type> elt_idx = get_elt_idx (idx, result_idx);
3852
3853 lhs.xelem (elt_idx) = rhs.elem (i);
3854
3855 increment_index (result_idx, frozen_len);
3856 }
3857 }
3858 }
3859 }
3860 }
3861 }
3862 }
3863
3864 lhs.clear_index ();
3865
3866 if (retval != 0)
3867 lhs = lhs.reshape (final_lhs_dims);
3868 }
3869
3870 if (retval != 0)
3871 lhs.chop_trailing_singletons ();
3872
3873 lhs.clear_index ();
3874
3875 return retval;
3876 } 2134 }
3877 2135
3878 template <class T> 2136 template <class T>
3879 void 2137 void
3880 Array<T>::print_info (std::ostream& os, const std::string& prefix) const 2138 Array<T>::print_info (std::ostream& os, const std::string& prefix) const