Mercurial > hg > octave-lyh
changeset 8150:283989f2da9b
make null assignment matlab compatible
line wrap: on
line diff
--- a/liboctave/Array.cc +++ b/liboctave/Array.cc @@ -1758,7 +1758,7 @@ } } } - else + else if (! (idx_i.orig_empty () || idx_j.orig_empty ())) { (*current_liboctave_error_handler) ("a null assignment can have only one non-colon index"); @@ -1778,6 +1778,21 @@ { octave_idx_type n_idx = ra_idx.length (); + // Special case matrices + if (ndims () == 2) + { + if (n_idx == 1) + { + maybe_delete_elements (ra_idx (0)); + return; + } + else if (n_idx == 2) + { + maybe_delete_elements (ra_idx (0), ra_idx (1)); + return; + } + } + dim_vector lhs_dims = dims (); int n_lhs_dims = lhs_dims.length (); @@ -1818,6 +1833,7 @@ for (octave_idx_type i = 0; i < n_idx; i++) { + if (ra_idx(i).orig_empty ()) return; idx_is_colon_equiv(i) = ra_idx(i).is_colon_equiv (lhs_dims(i), 1); idx_is_colon(i) = ra_idx(i).is_colon (); @@ -1873,18 +1889,15 @@ if (idx_ok) { if (n_idx > 1 - && (all_ones (idx_is_colon) || all_ones (idx_is_colon_equiv))) + && (all_ones (idx_is_colon))) { // A(:,:,:) -- we are deleting elements in all dimensions, so // the result is [](0x0x0). - dim_vector zeros; - zeros.resize (n_idx); - - for (int i = 0; i < n_idx; i++) - zeros(i) = 0; - - resize (zeros, rfv); + dim_vector newdim = dims (); + newdim(0) = 0; + + resize (newdim, rfv); } else if (n_idx > 1 @@ -3089,102 +3102,95 @@ } if (idx_i && idx_j) - { - if (rhs_nr == 0 && rhs_nc == 0) - { - lhs.maybe_delete_elements (idx_i, idx_j); - } - else - { - if (rhs_is_scalar && n >= 0 && m >= 0) - { - // No need to do anything if either of the indices - // are empty. - - if (n > 0 && m > 0) - { - lhs.make_unique (); - - MAYBE_RESIZE_LHS; - - RT scalar = xrhs.elem (0, 0); - - for (octave_idx_type j = 0; j < m; j++) - { - octave_idx_type jj = idx_j.elem (j); - for (octave_idx_type i = 0; i < n; i++) - { - octave_idx_type ii = idx_i.elem (i); - lhs.xelem (ii, jj) = scalar; - } - } - } - } - else if ((n == 1 || m == 1) - && (rhs_nr == 1 || rhs_nc == 1) - && n * m == rhs_nr * rhs_nc) - { - lhs.make_unique (); - - MAYBE_RESIZE_LHS; - - if (n > 0 && m > 0) - { - octave_idx_type k = 0; - - for (octave_idx_type j = 0; j < m; j++) - { - octave_idx_type jj = idx_j.elem (j); - for (octave_idx_type i = 0; i < n; i++) - { - octave_idx_type ii = idx_i.elem (i); - lhs.xelem (ii, jj) = xrhs.elem (k++); - } - } - } - } - else if (n == rhs_nr && m == rhs_nc) - { - lhs.make_unique (); - - MAYBE_RESIZE_LHS; - - if (n > 0 && m > 0) - { - for (octave_idx_type j = 0; j < m; j++) - { - octave_idx_type jj = idx_j.elem (j); - for (octave_idx_type i = 0; i < n; i++) - { - octave_idx_type ii = idx_i.elem (i); - lhs.xelem (ii, jj) = xrhs.elem (i, j); - } - } - } - } - else if (n == 0 && m == 0) - { - if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0))) - { - lhs.clear_index (); - - (*current_liboctave_error_handler) - ("A([], []) = X: X must be an empty matrix or a scalar"); - - retval = 0; - } - } - else - { - lhs.clear_index (); - - (*current_liboctave_error_handler) - ("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"); - - retval = 0; - } - } - } + { + if (rhs_is_scalar && n >= 0 && m >= 0) + { + // No need to do anything if either of the indices + // are empty. + + if (n > 0 && m > 0) + { + lhs.make_unique (); + + MAYBE_RESIZE_LHS; + + RT scalar = xrhs.elem (0, 0); + + for (octave_idx_type j = 0; j < m; j++) + { + octave_idx_type jj = idx_j.elem (j); + for (octave_idx_type i = 0; i < n; i++) + { + octave_idx_type ii = idx_i.elem (i); + lhs.xelem (ii, jj) = scalar; + } + } + } + } + else if ((n == 1 || m == 1) + && (rhs_nr == 1 || rhs_nc == 1) + && n * m == rhs_nr * rhs_nc) + { + lhs.make_unique (); + + MAYBE_RESIZE_LHS; + + if (n > 0 && m > 0) + { + octave_idx_type k = 0; + + for (octave_idx_type j = 0; j < m; j++) + { + octave_idx_type jj = idx_j.elem (j); + for (octave_idx_type i = 0; i < n; i++) + { + octave_idx_type ii = idx_i.elem (i); + lhs.xelem (ii, jj) = xrhs.elem (k++); + } + } + } + } + else if (n == rhs_nr && m == rhs_nc) + { + lhs.make_unique (); + + MAYBE_RESIZE_LHS; + + if (n > 0 && m > 0) + { + for (octave_idx_type j = 0; j < m; j++) + { + octave_idx_type jj = idx_j.elem (j); + for (octave_idx_type i = 0; i < n; i++) + { + octave_idx_type ii = idx_i.elem (i); + lhs.xelem (ii, jj) = xrhs.elem (i, j); + } + } + } + } + else if (n == 0 && m == 0) + { + if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0))) + { + lhs.clear_index (); + + (*current_liboctave_error_handler) + ("A([], []) = X: X must be an empty matrix or a scalar"); + + retval = 0; + } + } + else + { + lhs.clear_index (); + + (*current_liboctave_error_handler) + ("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"); + + retval = 0; + } + } // idx_vector::freeze() printed an error message for us. } else if (n_idx == 1) @@ -3198,49 +3204,42 @@ idx_i.freeze (lhs_len, 0, true); if (idx_i) - { - if (rhs_nr == 0 && rhs_nc == 0) - { - lhs.maybe_delete_elements (idx_i); - } - else - { - if (lhs_is_empty - && idx_i.is_colon () - && ! (rhs_nr == 1 || rhs_nc == 1)) - { - (*current_liboctave_warning_with_id_handler) - ("Octave:fortran-indexing", - "A(:) = X: X is not a vector or scalar"); - } - else - { - octave_idx_type idx_nr = idx_i.orig_rows (); - octave_idx_type idx_nc = idx_i.orig_columns (); - - if (! (rhs_nr == idx_nr && rhs_nc == idx_nc)) - (*current_liboctave_warning_with_id_handler) - ("Octave:fortran-indexing", - "A(I) = X: X does not have same shape as I"); - } - - if (assign1 (lhs, xrhs, rfv)) - { - octave_idx_type len = lhs.length (); - - if (len > 0) - { - // The following behavior is much simplified - // over previous versions of Octave. It - // seems to be compatible with Matlab. - - lhs.dimensions = dim_vector (1, lhs.length ()); - } - } - else - retval = 0; - } - } + { + if (lhs_is_empty + && idx_i.is_colon () + && ! (rhs_nr == 1 || rhs_nc == 1)) + { + (*current_liboctave_warning_with_id_handler) + ("Octave:fortran-indexing", + "A(:) = X: X is not a vector or scalar"); + } + else + { + octave_idx_type idx_nr = idx_i.orig_rows (); + octave_idx_type idx_nc = idx_i.orig_columns (); + + if (! (rhs_nr == idx_nr && rhs_nc == idx_nc)) + (*current_liboctave_warning_with_id_handler) + ("Octave:fortran-indexing", + "A(I) = X: X does not have same shape as I"); + } + + if (assign1 (lhs, xrhs, rfv)) + { + octave_idx_type len = lhs.length (); + + if (len > 0) + { + // The following behavior is much simplified + // over previous versions of Octave. It + // seems to be compatible with Matlab. + + lhs.dimensions = dim_vector (1, lhs.length ()); + } + } + else + retval = 0; + } // idx_vector::freeze() printed an error message for us. } else if (lhs_nr == 1) @@ -3248,17 +3247,12 @@ idx_i.freeze (lhs_nc, "vector", true); if (idx_i) - { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else - { - if (assign1 (lhs, xrhs, rfv)) - lhs.dimensions = dim_vector (1, lhs.length ()); - else - retval = 0; - } - } + { + if (assign1 (lhs, xrhs, rfv)) + lhs.dimensions = dim_vector (1, lhs.length ()); + else + retval = 0; + } // idx_vector::freeze() printed an error message for us. } else if (lhs_nc == 1) @@ -3267,15 +3261,10 @@ if (idx_i) { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else - { - if (assign1 (lhs, xrhs, rfv)) - lhs.dimensions = dim_vector (lhs.length (), 1); - else - retval = 0; - } + if (assign1 (lhs, xrhs, rfv)) + lhs.dimensions = dim_vector (lhs.length (), 1); + else + retval = 0; } // idx_vector::freeze() printed an error message for us. } @@ -3289,9 +3278,7 @@ if (idx_i) { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else if (len == 0) + if (len == 0) { if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0))) {
--- a/liboctave/Array.h +++ b/liboctave/Array.h @@ -502,8 +502,6 @@ void maybe_delete_elements (Array<idx_vector>& ra_idx, const T& rfv); - void maybe_delete_elements (octave_idx_type dim, idx_vector& i); - Array<T> value (void) const; Array<T> index (idx_vector& i, int resize_ok = 0,
--- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,12 @@ +2008-09-26 Jaroslav Hajek <highegg@gmail.com> + + * Array.cc (assign1, assign2, assignN): Do not call + maybe_delete_elements. + (maybe_delete_elements (Array<idx_vector>&)): Call the 1D and 2D + special handlers if possible. + * Sparse.cc (assign1, assign2, assignN): Do not call + maybe_delete_elements. + 2008-09-22 Brian Gough <bjg@gnu.org> * oct-rand.cc (initialize_mersenne_twister): Use separate
--- a/liboctave/Sparse.cc +++ b/liboctave/Sparse.cc @@ -2865,354 +2865,347 @@ } if (idx_i && idx_j) - { - if (rhs_nr == 0 && rhs_nc == 0) - { - lhs.maybe_delete_elements (idx_i, idx_j); - } - else - { - if (rhs_nr == 1 && rhs_nc == 1 && n >= 0 && m >= 0) - { - if (n > 0 && m > 0) - { - idx_i.sort (true); - n = idx_i.length (n); - idx_j.sort (true); - m = idx_j.length (m); - - octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : - idx_i.max () + 1; - octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : - idx_j.max () + 1; - octave_idx_type new_nr = max_row_idx > lhs_nr ? - max_row_idx : lhs_nr; - octave_idx_type new_nc = max_col_idx > lhs_nc ? - max_col_idx : lhs_nc; - RT scalar = rhs.elem (0, 0); - - // Count the number of non-zero terms - octave_idx_type new_nzmx = lhs.nnz (); - for (octave_idx_type j = 0; j < m; j++) - { - octave_idx_type jj = idx_j.elem (j); - if (jj < lhs_nc) - { - for (octave_idx_type i = 0; i < n; i++) - { - OCTAVE_QUIT; - - octave_idx_type ii = idx_i.elem (i); - - if (ii < lhs_nr) - { - for (octave_idx_type k = c_lhs.cidx(jj); - k < c_lhs.cidx(jj+1); k++) - { - if (c_lhs.ridx(k) == ii) - new_nzmx--; - if (c_lhs.ridx(k) >= ii) - break; - } - } - } - } - } - - if (scalar != RT()) - new_nzmx += m * n; - - Sparse<LT> stmp (new_nr, new_nc, new_nzmx); - - octave_idx_type jji = 0; - octave_idx_type jj = idx_j.elem (jji); - octave_idx_type kk = 0; - stmp.cidx(0) = 0; - for (octave_idx_type j = 0; j < new_nc; j++) - { - if (jji < m && jj == j) - { - octave_idx_type iii = 0; - octave_idx_type ii = idx_i.elem (iii); - octave_idx_type ppp = 0; - octave_idx_type ppi = (j >= lhs_nc ? 0 : - c_lhs.cidx(j+1) - - c_lhs.cidx(j)); - octave_idx_type pp = (ppp < ppi ? - c_lhs.ridx(c_lhs.cidx(j)+ppp) : - new_nr); - while (ppp < ppi || iii < n) - { - if (iii < n && ii <= pp) - { - if (scalar != RT ()) - { - stmp.data(kk) = scalar; - stmp.ridx(kk++) = ii; - } - if (ii == pp) - pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); - if (++iii < n) - ii = idx_i.elem(iii); - } - else - { - stmp.data(kk) = - c_lhs.data(c_lhs.cidx(j)+ppp); - stmp.ridx(kk++) = pp; - pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); - } - } - if (++jji < m) - jj = idx_j.elem(jji); - } - else if (j < lhs_nc) - { - for (octave_idx_type i = c_lhs.cidx(j); - i < c_lhs.cidx(j+1); i++) - { - stmp.data(kk) = c_lhs.data(i); - stmp.ridx(kk++) = c_lhs.ridx(i); - } - } - stmp.cidx(j+1) = kk; - } - - lhs = stmp; - } - else - { + { + if (rhs_nr == 1 && rhs_nc == 1 && n >= 0 && m >= 0) + { + if (n > 0 && m > 0) + { + idx_i.sort (true); + n = idx_i.length (n); + idx_j.sort (true); + m = idx_j.length (m); + + octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : + idx_i.max () + 1; + octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : + idx_j.max () + 1; + octave_idx_type new_nr = max_row_idx > lhs_nr ? + max_row_idx : lhs_nr; + octave_idx_type new_nc = max_col_idx > lhs_nc ? + max_col_idx : lhs_nc; + RT scalar = rhs.elem (0, 0); + + // Count the number of non-zero terms + octave_idx_type new_nzmx = lhs.nnz (); + for (octave_idx_type j = 0; j < m; j++) + { + octave_idx_type jj = idx_j.elem (j); + if (jj < lhs_nc) + { + for (octave_idx_type i = 0; i < n; i++) + { + OCTAVE_QUIT; + + octave_idx_type ii = idx_i.elem (i); + + if (ii < lhs_nr) + { + for (octave_idx_type k = c_lhs.cidx(jj); + k < c_lhs.cidx(jj+1); k++) + { + if (c_lhs.ridx(k) == ii) + new_nzmx--; + if (c_lhs.ridx(k) >= ii) + break; + } + } + } + } + } + + if (scalar != RT()) + new_nzmx += m * n; + + Sparse<LT> stmp (new_nr, new_nc, new_nzmx); + + octave_idx_type jji = 0; + octave_idx_type jj = idx_j.elem (jji); + octave_idx_type kk = 0; + stmp.cidx(0) = 0; + for (octave_idx_type j = 0; j < new_nc; j++) + { + if (jji < m && jj == j) + { + octave_idx_type iii = 0; + octave_idx_type ii = idx_i.elem (iii); + octave_idx_type ppp = 0; + octave_idx_type ppi = (j >= lhs_nc ? 0 : + c_lhs.cidx(j+1) - + c_lhs.cidx(j)); + octave_idx_type pp = (ppp < ppi ? + c_lhs.ridx(c_lhs.cidx(j)+ppp) : + new_nr); + while (ppp < ppi || iii < n) + { + if (iii < n && ii <= pp) + { + if (scalar != RT ()) + { + stmp.data(kk) = scalar; + stmp.ridx(kk++) = ii; + } + if (ii == pp) + pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); + if (++iii < n) + ii = idx_i.elem(iii); + } + else + { + stmp.data(kk) = + c_lhs.data(c_lhs.cidx(j)+ppp); + stmp.ridx(kk++) = pp; + pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); + } + } + if (++jji < m) + jj = idx_j.elem(jji); + } + else if (j < lhs_nc) + { + for (octave_idx_type i = c_lhs.cidx(j); + i < c_lhs.cidx(j+1); i++) + { + stmp.data(kk) = c_lhs.data(i); + stmp.ridx(kk++) = c_lhs.ridx(i); + } + } + stmp.cidx(j+1) = kk; + } + + lhs = stmp; + } + else + { #if 0 - // FIXME -- the following code will make this - // function behave the same as the full matrix - // case for things like - // - // x = sparse (ones (2)); - // x([],3) = 2; - // - // x = - // - // Compressed Column Sparse (rows = 2, cols = 3, nnz = 4) - // - // (1, 1) -> 1 - // (2, 1) -> 1 - // (1, 2) -> 1 - // (2, 2) -> 1 - // - // However, Matlab doesn't resize in this case - // even though it does in the full matrix case. - - if (n > 0) - { - octave_idx_type max_row_idx = idx_i_is_colon ? - rhs_nr : idx_i.max () + 1; - octave_idx_type new_nr = max_row_idx > lhs_nr ? - max_row_idx : lhs_nr; - octave_idx_type new_nc = lhs_nc; - - lhs.resize (new_nr, new_nc); - } - else if (m > 0) - { - octave_idx_type max_col_idx = idx_j_is_colon ? - rhs_nc : idx_j.max () + 1; - octave_idx_type new_nr = lhs_nr; - octave_idx_type new_nc = max_col_idx > lhs_nc ? - max_col_idx : lhs_nc; - - lhs.resize (new_nr, new_nc); - } + // FIXME -- the following code will make this + // function behave the same as the full matrix + // case for things like + // + // x = sparse (ones (2)); + // x([],3) = 2; + // + // x = + // + // Compressed Column Sparse (rows = 2, cols = 3, nnz = 4) + // + // (1, 1) -> 1 + // (2, 1) -> 1 + // (1, 2) -> 1 + // (2, 2) -> 1 + // + // However, Matlab doesn't resize in this case + // even though it does in the full matrix case. + + if (n > 0) + { + octave_idx_type max_row_idx = idx_i_is_colon ? + rhs_nr : idx_i.max () + 1; + octave_idx_type new_nr = max_row_idx > lhs_nr ? + max_row_idx : lhs_nr; + octave_idx_type new_nc = lhs_nc; + + lhs.resize (new_nr, new_nc); + } + else if (m > 0) + { + octave_idx_type max_col_idx = idx_j_is_colon ? + rhs_nc : idx_j.max () + 1; + octave_idx_type new_nr = lhs_nr; + octave_idx_type new_nc = max_col_idx > lhs_nc ? + max_col_idx : lhs_nc; + + lhs.resize (new_nr, new_nc); + } #endif - } - } - else if (n == rhs_nr && m == rhs_nc) - { - if (n > 0 && m > 0) - { - octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : - idx_i.max () + 1; - octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : - idx_j.max () + 1; - octave_idx_type new_nr = max_row_idx > lhs_nr ? - max_row_idx : lhs_nr; - octave_idx_type new_nc = max_col_idx > lhs_nc ? - max_col_idx : lhs_nc; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_i, n); - if (! idx_i.is_colon ()) - { - // Ok here we have to be careful with the indexing, - // to treat cases like "a([3,2,1],:) = b", and still - // handle the need for strict sorting of the sparse - // elements. - OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *, - sidx, n); - OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort, - sidxX, n); - - for (octave_idx_type i = 0; i < n; i++) - { - sidx[i] = &sidxX[i]; - sidx[i]->i = idx_i.elem(i); - sidx[i]->idx = i; - } - - OCTAVE_QUIT; - octave_sort<octave_idx_vector_sort *> - sort (octave_idx_vector_comp); - - sort.sort (sidx, n); - - intNDArray<octave_idx_type> new_idx (dim_vector (n,1)); - - for (octave_idx_type i = 0; i < n; i++) - { - new_idx.xelem(i) = sidx[i]->i + 1; - rhs_idx_i[i] = sidx[i]->idx; - } - - idx_i = idx_vector (new_idx); - } - else - for (octave_idx_type i = 0; i < n; i++) - rhs_idx_i[i] = i; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_j, m); - if (! idx_j.is_colon ()) - { - // Ok here we have to be careful with the indexing, - // to treat cases like "a([3,2,1],:) = b", and still - // handle the need for strict sorting of the sparse - // elements. - OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *, - sidx, m); - OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort, - sidxX, m); - - for (octave_idx_type i = 0; i < m; i++) - { - sidx[i] = &sidxX[i]; - sidx[i]->i = idx_j.elem(i); - sidx[i]->idx = i; - } - - OCTAVE_QUIT; - octave_sort<octave_idx_vector_sort *> - sort (octave_idx_vector_comp); - - sort.sort (sidx, m); - - intNDArray<octave_idx_type> new_idx (dim_vector (m,1)); - - for (octave_idx_type i = 0; i < m; i++) - { - new_idx.xelem(i) = sidx[i]->i + 1; - rhs_idx_j[i] = sidx[i]->idx; - } - - idx_j = idx_vector (new_idx); - } - else - for (octave_idx_type i = 0; i < m; i++) - rhs_idx_j[i] = i; - - // Maximum number of non-zero elements - octave_idx_type new_nzmx = lhs.nnz() + rhs.nnz(); - - Sparse<LT> stmp (new_nr, new_nc, new_nzmx); - - octave_idx_type jji = 0; - octave_idx_type jj = idx_j.elem (jji); - octave_idx_type kk = 0; - stmp.cidx(0) = 0; - for (octave_idx_type j = 0; j < new_nc; j++) - { - if (jji < m && jj == j) - { - octave_idx_type iii = 0; - octave_idx_type ii = idx_i.elem (iii); - octave_idx_type ppp = 0; - octave_idx_type ppi = (j >= lhs_nc ? 0 : - c_lhs.cidx(j+1) - - c_lhs.cidx(j)); - octave_idx_type pp = (ppp < ppi ? - c_lhs.ridx(c_lhs.cidx(j)+ppp) : - new_nr); - while (ppp < ppi || iii < n) - { - if (iii < n && ii <= pp) - { - if (iii < n - 1 && - idx_i.elem (iii + 1) == ii) - { - iii++; - ii = idx_i.elem(iii); - continue; - } - - RT rtmp = rhs.elem (rhs_idx_i[iii], - rhs_idx_j[jji]); - if (rtmp != RT ()) - { - stmp.data(kk) = rtmp; - stmp.ridx(kk++) = ii; - } - if (ii == pp) - pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); - if (++iii < n) - ii = idx_i.elem(iii); - } - else - { - stmp.data(kk) = - c_lhs.data(c_lhs.cidx(j)+ppp); - stmp.ridx(kk++) = pp; - pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); - } - } - if (++jji < m) - jj = idx_j.elem(jji); - } - else if (j < lhs_nc) - { - for (octave_idx_type i = c_lhs.cidx(j); - i < c_lhs.cidx(j+1); i++) - { - stmp.data(kk) = c_lhs.data(i); - stmp.ridx(kk++) = c_lhs.ridx(i); - } - } - stmp.cidx(j+1) = kk; - } - - stmp.maybe_compress(); - lhs = stmp; - } - } - else if (n == 0 && m == 0) - { - if (! ((rhs_nr == 1 && rhs_nc == 1) - || (rhs_nr == 0 || rhs_nc == 0))) - { - (*current_liboctave_error_handler) - ("A([], []) = X: X must be an empty matrix or a scalar"); - - retval = 0; - } - } - else - { - (*current_liboctave_error_handler) - ("A(I, J) = X: X must be a scalar or the number of elements in I must"); - (*current_liboctave_error_handler) - ("match the number of rows in X and the number of elements in J must"); - (*current_liboctave_error_handler) - ("match the number of columns in X"); - - retval = 0; - } - } - } + } + } + else if (n == rhs_nr && m == rhs_nc) + { + if (n > 0 && m > 0) + { + octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : + idx_i.max () + 1; + octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : + idx_j.max () + 1; + octave_idx_type new_nr = max_row_idx > lhs_nr ? + max_row_idx : lhs_nr; + octave_idx_type new_nc = max_col_idx > lhs_nc ? + max_col_idx : lhs_nc; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_i, n); + if (! idx_i.is_colon ()) + { + // Ok here we have to be careful with the indexing, + // to treat cases like "a([3,2,1],:) = b", and still + // handle the need for strict sorting of the sparse + // elements. + OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *, + sidx, n); + OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort, + sidxX, n); + + for (octave_idx_type i = 0; i < n; i++) + { + sidx[i] = &sidxX[i]; + sidx[i]->i = idx_i.elem(i); + sidx[i]->idx = i; + } + + OCTAVE_QUIT; + octave_sort<octave_idx_vector_sort *> + sort (octave_idx_vector_comp); + + sort.sort (sidx, n); + + intNDArray<octave_idx_type> new_idx (dim_vector (n,1)); + + for (octave_idx_type i = 0; i < n; i++) + { + new_idx.xelem(i) = sidx[i]->i + 1; + rhs_idx_i[i] = sidx[i]->idx; + } + + idx_i = idx_vector (new_idx); + } + else + for (octave_idx_type i = 0; i < n; i++) + rhs_idx_i[i] = i; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_j, m); + if (! idx_j.is_colon ()) + { + // Ok here we have to be careful with the indexing, + // to treat cases like "a([3,2,1],:) = b", and still + // handle the need for strict sorting of the sparse + // elements. + OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *, + sidx, m); + OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort, + sidxX, m); + + for (octave_idx_type i = 0; i < m; i++) + { + sidx[i] = &sidxX[i]; + sidx[i]->i = idx_j.elem(i); + sidx[i]->idx = i; + } + + OCTAVE_QUIT; + octave_sort<octave_idx_vector_sort *> + sort (octave_idx_vector_comp); + + sort.sort (sidx, m); + + intNDArray<octave_idx_type> new_idx (dim_vector (m,1)); + + for (octave_idx_type i = 0; i < m; i++) + { + new_idx.xelem(i) = sidx[i]->i + 1; + rhs_idx_j[i] = sidx[i]->idx; + } + + idx_j = idx_vector (new_idx); + } + else + for (octave_idx_type i = 0; i < m; i++) + rhs_idx_j[i] = i; + + // Maximum number of non-zero elements + octave_idx_type new_nzmx = lhs.nnz() + rhs.nnz(); + + Sparse<LT> stmp (new_nr, new_nc, new_nzmx); + + octave_idx_type jji = 0; + octave_idx_type jj = idx_j.elem (jji); + octave_idx_type kk = 0; + stmp.cidx(0) = 0; + for (octave_idx_type j = 0; j < new_nc; j++) + { + if (jji < m && jj == j) + { + octave_idx_type iii = 0; + octave_idx_type ii = idx_i.elem (iii); + octave_idx_type ppp = 0; + octave_idx_type ppi = (j >= lhs_nc ? 0 : + c_lhs.cidx(j+1) - + c_lhs.cidx(j)); + octave_idx_type pp = (ppp < ppi ? + c_lhs.ridx(c_lhs.cidx(j)+ppp) : + new_nr); + while (ppp < ppi || iii < n) + { + if (iii < n && ii <= pp) + { + if (iii < n - 1 && + idx_i.elem (iii + 1) == ii) + { + iii++; + ii = idx_i.elem(iii); + continue; + } + + RT rtmp = rhs.elem (rhs_idx_i[iii], + rhs_idx_j[jji]); + if (rtmp != RT ()) + { + stmp.data(kk) = rtmp; + stmp.ridx(kk++) = ii; + } + if (ii == pp) + pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); + if (++iii < n) + ii = idx_i.elem(iii); + } + else + { + stmp.data(kk) = + c_lhs.data(c_lhs.cidx(j)+ppp); + stmp.ridx(kk++) = pp; + pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr); + } + } + if (++jji < m) + jj = idx_j.elem(jji); + } + else if (j < lhs_nc) + { + for (octave_idx_type i = c_lhs.cidx(j); + i < c_lhs.cidx(j+1); i++) + { + stmp.data(kk) = c_lhs.data(i); + stmp.ridx(kk++) = c_lhs.ridx(i); + } + } + stmp.cidx(j+1) = kk; + } + + stmp.maybe_compress(); + lhs = stmp; + } + } + else if (n == 0 && m == 0) + { + if (! ((rhs_nr == 1 && rhs_nc == 1) + || (rhs_nr == 0 || rhs_nc == 0))) + { + (*current_liboctave_error_handler) + ("A([], []) = X: X must be an empty matrix or a scalar"); + + retval = 0; + } + } + else + { + (*current_liboctave_error_handler) + ("A(I, J) = X: X must be a scalar or the number of elements in I must"); + (*current_liboctave_error_handler) + ("match the number of rows in X and the number of elements in J must"); + (*current_liboctave_error_handler) + ("match the number of columns in X"); + + retval = 0; + } + } // idx_vector::freeze() printed an error message for us. } else if (n_idx == 1) @@ -3226,37 +3219,29 @@ octave_idx_type n = idx_i.freeze (lhs_len, 0, true); if (idx_i) - { - if (rhs_nr == 0 && rhs_nc == 0) - { - if (n != 0 && (lhs_nr != 0 || lhs_nc != 0)) - lhs.maybe_delete_elements (idx_i); - } - else - { - if (lhs_is_empty - && idx_i.is_colon () - && ! (rhs_nr == 1 || rhs_nc == 1)) - { - (*current_liboctave_warning_with_id_handler) - ("Octave:fortran-indexing", - "A(:) = X: X is not a vector or scalar"); - } - else - { - octave_idx_type idx_nr = idx_i.orig_rows (); - octave_idx_type idx_nc = idx_i.orig_columns (); - - if (! (rhs_nr == idx_nr && rhs_nc == idx_nc)) - (*current_liboctave_warning_with_id_handler) - ("Octave:fortran-indexing", - "A(I) = X: X does not have same shape as I"); - } - - if (! assign1 (lhs, rhs)) - retval = 0; - } - } + { + if (lhs_is_empty + && idx_i.is_colon () + && ! (rhs_nr == 1 || rhs_nc == 1)) + { + (*current_liboctave_warning_with_id_handler) + ("Octave:fortran-indexing", + "A(:) = X: X is not a vector or scalar"); + } + else + { + octave_idx_type idx_nr = idx_i.orig_rows (); + octave_idx_type idx_nc = idx_i.orig_columns (); + + if (! (rhs_nr == idx_nr && rhs_nc == idx_nc)) + (*current_liboctave_warning_with_id_handler) + ("Octave:fortran-indexing", + "A(I) = X: X does not have same shape as I"); + } + + if (! assign1 (lhs, rhs)) + retval = 0; + } // idx_vector::freeze() printed an error message for us. } else if (lhs_nr == 1) @@ -3264,12 +3249,10 @@ idx_i.freeze (lhs_nc, "vector", true); if (idx_i) - { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else if (! assign1 (lhs, rhs)) - retval = 0; - } + { + if (! assign1 (lhs, rhs)) + retval = 0; + } // idx_vector::freeze() printed an error message for us. } else if (lhs_nc == 1) @@ -3278,9 +3261,7 @@ if (idx_i) { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else if (! assign1 (lhs, rhs)) + if (! assign1 (lhs, rhs)) retval = 0; } // idx_vector::freeze() printed an error message for us. @@ -3297,9 +3278,7 @@ if (idx_i) { - if (rhs_nr == 0 && rhs_nc == 0) - lhs.maybe_delete_elements (idx_i); - else if (len == 0) + if (len == 0) { if (! ((rhs_nr == 1 && rhs_nc == 1) || (rhs_nr == 0 || rhs_nc == 0)))
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,58 @@ +2008-09-26 Jaroslav Hajek <highegg@gmail.com> + + * ov-null-mat.h: New header file. + * ov-null-mat.cc: New source. + * ov.h (octave_value::is_null_value, octave_value::non_null_value, + octave_value::make_non_null_value): + Declare new member functions. + * ov.cc (octave_value:non_null_value, octave_value::make_non_null_value): + Define them. + (octave_value::assign (assign_op op, const octave_value& rhs)): + (register_types): Register null types. + Call non_null_value (). + * oct-obj.cc (octave_value_list::normalize_null_values): New member + function. + * oct-obj.h (octave_value_list::normalize_null_values): Declare it. + * ov-base.h (is_null_value): New virtual member function. + * ops.h (NULLASSIGNOPDECL, DEFNULLASSIGNOP_FN): New macros. + * ov-base-mat.cc (octave_base_mat<MT>::delete_elements): New member func. + * ov-base-mat.h: Declare it. + * ov-base-sparse.cc (octave_base_sparse<MT>::delete_elements): New member func. + * ov-base-sparse.h: Declare it. + * ov-cell.cc (octave_cell:subsasgn): Handle null values. + * ov-struct.cc (octave_cell:subsasgn): Handle null values. + * ov-builtin.cc (octave_builtin::do_multi_index_op): Normalize return + values. + * pt-misc.cc (tree_parameter_list::define_from_arg_vector): Call + octave_lvalue::define instead of octave_lvalue::assign. + * pt-decl.h (tree_decl_elt::rvalue): Call non_null_value (). + * OPERATORS/op-int.h (OCTAVE_INT_NULL_ASSIGN_OPS, + OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS): New macros. + * OPERATORS/op-m-m.cc: Install & define assignment & conversion operators. + * OPERATORS/op-bm-bm.cc: Dtto. + * OPERATORS/op-cell.cc: Dtto. + * OPERATORS/op-cm-cm.cc: Dtto. + * OPERATORS/op-cs-cs.cc: Dtto. + * OPERATORS/op-fcm-fcm.cc: Dtto. + * OPERATORS/op-fcs-fcs.cc: Dtto. + * OPERATORS/op-fm-fm.cc: Dtto. + * OPERATORS/op-fs-fs.cc: Dtto. + * OPERATORS/op-int.h: Dtto. + * OPERATORS/op-m-m.cc: Dtto. + * OPERATORS/op-range.cc: Dtto. + * OPERATORS/op-s-s.cc: Dtto. + * OPERATORS/op-scm-scm.cc: Dtto. + * OPERATORS/op-sm-sm.cc: Dtto. + * OPERATORS/op-str-str.cc: Dtto. + * OPERATORS/op-i16-i16.cc: Dtto. + * OPERATORS/op-i32-i32.cc: Dtto. + * OPERATORS/op-i64-i64.cc: Dtto. + * OPERATORS/op-i8-i8.cc: Dtto. + * OPERATORS/op-ui16-ui16.cc: Dtto. + * OPERATORS/op-ui32-ui32.cc: Dtto. + * OPERATORS/op-ui64-ui64.cc: Dtto. + * OPERATORS/op-ui8-ui8.cc: Dtto. + 2008-09-25 David Bateman <dbateman@free.fr> * pt-mat.cc (class tm_row_const): Add any_class test
--- a/src/Makefile.in +++ b/src/Makefile.in @@ -100,7 +100,7 @@ OV_INCLUDES := ov-re-mat.h ov-cx-mat.h ov-ch-mat.h ov-cs-list.h ov-list.h \ ov-struct.h ov-scalar.h ov-range.h ov-complex.h \ ov-colon.h ov-base.h ov-base-mat.h ov-base-scalar.h \ - ov-str-mat.h ov-bool-mat.h ov-bool.h \ + ov-str-mat.h ov-bool-mat.h ov-null-mat.h ov-bool.h \ ov-cell.h ov.h ov-fcn.h ov-builtin.h ov-dld-fcn.h \ ov-mex-fcn.h ov-usr-fcn.h ov-fcn-handle.h \ ov-fcn-inline.h ov-class.h ov-typeinfo.h ov-type-conv.h \ @@ -181,7 +181,7 @@ ov-cs-list.cc ov-list.cc ov-re-mat.cc ov-cx-mat.cc \ ov-range.cc ov-scalar.cc ov-complex.cc ov-str-mat.cc \ ov-struct.cc \ - ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-cell.cc \ + ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-null-mat.cc ov-cell.cc \ ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc \ ov-mex-fcn.cc ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc \ ov-class.cc ov-typeinfo.cc \
--- a/src/OPERATORS/op-bm-bm.cc +++ b/src/OPERATORS/op-bm-bm.cc @@ -44,6 +44,7 @@ #include "ov-uint32.h" #include "ov-uint64.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -86,6 +87,8 @@ DEFNDASSIGNOP_FN (assign, bool_matrix, bool_matrix, bool_array, assign) +DEFNULLASSIGNOP_FN (null_assign, bool_matrix, delete_elements) + static octave_value oct_assignop_conv_and_assign (octave_base_value& a1, const octave_value_list& idx, @@ -150,6 +153,10 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint16_matrix, conv_and_assign); INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint32_matrix, conv_and_assign); INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint64_matrix, conv_and_assign); + + INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_sq_str, null_assign); } /*
--- a/src/OPERATORS/op-cell.cc +++ b/src/OPERATORS/op-cell.cc @@ -31,6 +31,7 @@ #include "ov-scalar.h" #include "ov-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" // cell ops. @@ -82,6 +83,8 @@ DEFASSIGNANYOP_FN (assign, cell, assign); +DEFNULLASSIGNOP_FN (null_assign, cell, delete_elements) + void install_cell_ops (void) { @@ -94,6 +97,10 @@ INSTALL_CATOP (octave_matrix, octave_cell, matrix_cell); INSTALL_ASSIGNANYOP (op_asn_eq, octave_cell, assign); + + INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_sq_str, null_assign); } /*
--- a/src/OPERATORS/op-cm-cm.cc +++ b/src/OPERATORS/op-cm-cm.cc @@ -31,6 +31,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -160,6 +161,8 @@ DEFNDASSIGNOP_FN (assign, complex_matrix, complex_matrix, complex_array, assign) +DEFNULLASSIGNOP_FN (null_assign, complex_matrix, delete_elements) + CONVDECL (complex_matrix_to_float_complex_matrix) { CAST_CONV_ARG (const octave_complex_matrix&); @@ -206,6 +209,10 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_complex_matrix, assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_sq_str, null_assign); + INSTALL_CONVOP (octave_complex_matrix, octave_float_complex_matrix, complex_matrix_to_float_complex_matrix); }
--- a/src/OPERATORS/op-cs-cs.cc +++ b/src/OPERATORS/op-cs-cs.cc @@ -32,6 +32,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -219,6 +220,10 @@ INSTALL_ASSIGNCONV (octave_complex, octave_complex, octave_complex_matrix); + INSTALL_ASSIGNCONV (octave_complex, octave_null_matrix, octave_complex_matrix); + INSTALL_ASSIGNCONV (octave_complex, octave_null_str, octave_complex_matrix); + INSTALL_ASSIGNCONV (octave_complex, octave_null_sq_str, octave_complex_matrix); + INSTALL_CONVOP (octave_complex, octave_float_complex_matrix, complex_to_float_complex); }
--- a/src/OPERATORS/op-fcm-fcm.cc +++ b/src/OPERATORS/op-fcm-fcm.cc @@ -31,6 +31,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -186,6 +187,8 @@ DEFNDASSIGNOP_FN (dbl_assign, complex_matrix, float_complex_matrix, complex_array, assign) +DEFNULLASSIGNOP_FN (null_assign, float_complex_matrix, delete_elements) + CONVDECL (float_complex_matrix_to_complex_matrix) { CAST_CONV_ARG (const octave_float_complex_matrix&); @@ -262,6 +265,13 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, octave_complex_matrix, dbl_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, + octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, + octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, + octave_null_sq_str, null_assign); + INSTALL_CONVOP (octave_float_complex_matrix, octave_complex_matrix, float_complex_matrix_to_complex_matrix); }
--- a/src/OPERATORS/op-fcs-fcs.cc +++ b/src/OPERATORS/op-fcs-fcs.cc @@ -32,6 +32,7 @@ #include "ov-flt-complex.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -232,6 +233,10 @@ INSTALL_ASSIGNCONV (octave_complex, octave_float_complex, octave_complex_matrix); + INSTALL_ASSIGNCONV (octave_float_complex, octave_null_matrix, octave_float_complex_matrix); + INSTALL_ASSIGNCONV (octave_float_complex, octave_null_str, octave_float_complex_matrix); + INSTALL_ASSIGNCONV (octave_float_complex, octave_null_sq_str, octave_float_complex_matrix); + INSTALL_CONVOP (octave_float_complex, octave_complex_matrix, float_complex_to_complex); }
--- a/src/OPERATORS/op-fm-fm.cc +++ b/src/OPERATORS/op-fm-fm.cc @@ -31,6 +31,7 @@ #include "ov-re-mat.h" #include "ov-flt-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -152,6 +153,8 @@ DEFNDASSIGNOP_FN (dbl_assign, matrix, float_matrix, array, assign) +DEFNULLASSIGNOP_FN (null_assign, float_matrix, delete_elements) + CONVDECL (float_matrix_to_matrix) { CAST_CONV_ARG (const octave_float_matrix&); @@ -203,6 +206,10 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_float_matrix, dbl_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_sq_str, null_assign); + INSTALL_CONVOP (octave_float_matrix, octave_matrix, float_matrix_to_matrix); }
--- a/src/OPERATORS/op-fs-fs.cc +++ b/src/OPERATORS/op-fs-fs.cc @@ -32,6 +32,7 @@ #include "ov-float.h" #include "ov-flt-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -166,6 +167,10 @@ INSTALL_ASSIGNCONV (octave_float_scalar, octave_float_scalar, octave_float_matrix); INSTALL_ASSIGNCONV (octave_scalar, octave_float_scalar, octave_matrix); + INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_matrix, octave_float_matrix); + INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_str, octave_float_matrix); + INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_sq_str, octave_float_matrix); + INSTALL_CONVOP (octave_float_scalar, octave_matrix, float_to_scalar); }
--- a/src/OPERATORS/op-i16-i16.cc +++ b/src/OPERATORS/op-i16-i16.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/OPERATORS/op-i32-i32.cc +++ b/src/OPERATORS/op-i32-i32.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/OPERATORS/op-i64-i64.cc +++ b/src/OPERATORS/op-i64-i64.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -135,6 +136,8 @@ OCTAVE_MM_INT_ASSIGN_OPS (mmui32, int64_, uint32_, uint32_) OCTAVE_MM_INT_ASSIGN_OPS (mmui64, int64_, uint64_, uint64_) +OCTAVE_INT_NULL_ASSIGN_OPS (int64) + OCTAVE_MIXED_INT_CMP_OPS (int64, int8) OCTAVE_MIXED_INT_CMP_OPS (int64, uint8) OCTAVE_MIXED_INT_CMP_OPS (int64, int16) @@ -200,6 +203,8 @@ OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui32, int64_, uint32_); OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui64, int64_, uint64_); + OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS (int64) + OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, int8); OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, uint8); OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, int16);
--- a/src/OPERATORS/op-i8-i8.cc +++ b/src/OPERATORS/op-i8-i8.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/OPERATORS/op-int.h +++ b/src/OPERATORS/op-int.h @@ -884,6 +884,9 @@ DEFNDASSIGNOP_FN (TYPE ## fcms_assign, float_complex_matrix, TYPE ## _scalar, float_complex_array, assign) \ DEFNDASSIGNOP_FN (TYPE ## fcmm_assign, float_complex_matrix, TYPE ## _matrix, float_complex_array, assign) +#define OCTAVE_INT_NULL_ASSIGN_OPS(TYPE) \ + DEFNULLASSIGNOP_FN (TYPE ## null_assign, TYPE ## _matrix, delete_elements) + #define OCTAVE_INT_OPS(TYPE) \ OCTAVE_SS_INT_OPS (TYPE) \ OCTAVE_SM_INT_OPS (TYPE) \ @@ -893,7 +896,8 @@ OCTAVE_RE_INT_ASSIGN_OPS (TYPE) \ OCTAVE_FLT_RE_INT_ASSIGN_OPS (TYPE) \ OCTAVE_CX_INT_ASSIGN_OPS (TYPE) \ - OCTAVE_FLT_CX_INT_ASSIGN_OPS (TYPE) + OCTAVE_FLT_CX_INT_ASSIGN_OPS (TYPE) \ + OCTAVE_INT_NULL_ASSIGN_OPS(TYPE) #define OCTAVE_INSTALL_S_INT_UNOPS(TYPE) \ INSTALL_UNOP (op_not, octave_ ## TYPE ## _scalar, s_not); \ @@ -1137,6 +1141,11 @@ INSTALL_ASSIGNCONV (octave_float_complex_scalar, octave_ ## TYPE ## _scalar, octave_complex_matrix) \ INSTALL_ASSIGNCONV (octave_float_complex_matrix, octave_ ## TYPE ## _matrix, octave_complex_matrix) +#define OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS(TYPE) \ + INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_matrix, TYPE ## null_assign) \ + INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_str, TYPE ## null_assign) \ + INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_sq_str, TYPE ## null_assign) + #define OCTAVE_INSTALL_INT_OPS(TYPE) \ OCTAVE_INSTALL_SS_INT_OPS (TYPE) \ OCTAVE_INSTALL_SM_INT_OPS (TYPE) \ @@ -1146,7 +1155,8 @@ OCTAVE_INSTALL_RE_INT_ASSIGN_OPS (TYPE) \ OCTAVE_INSTALL_FLT_RE_INT_ASSIGN_OPS (TYPE) \ OCTAVE_INSTALL_CX_INT_ASSIGN_OPS (TYPE) \ - OCTAVE_INSTALL_FLT_CX_INT_ASSIGN_OPS (TYPE) + OCTAVE_INSTALL_FLT_CX_INT_ASSIGN_OPS (TYPE) \ + OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS(TYPE) #define OCTAVE_INSTALL_SM_INT_ASSIGNCONV(TLHS, TRHS) \ INSTALL_ASSIGNCONV (octave_ ## TLHS ## _scalar, octave_ ## TRHS ## _scalar, octave_ ## TLHS ## _matrix) \
--- a/src/OPERATORS/op-m-m.cc +++ b/src/OPERATORS/op-m-m.cc @@ -31,6 +31,7 @@ #include "ov-re-mat.h" #include "ov-flt-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -130,6 +131,8 @@ DEFNDASSIGNOP_FN (assign, matrix, matrix, array, assign) DEFNDASSIGNOP_FN (sgl_assign, float_matrix, matrix, float_array, assign) +DEFNULLASSIGNOP_FN (null_assign, matrix, delete_elements) + CONVDECL (matrix_to_float_matrix) { CAST_CONV_ARG (const octave_matrix&); @@ -177,6 +180,10 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_matrix, assign); INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_matrix, sgl_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_sq_str, null_assign); + INSTALL_CONVOP (octave_matrix, octave_float_matrix, matrix_to_float_matrix); }
--- a/src/OPERATORS/op-range.cc +++ b/src/OPERATORS/op-range.cc @@ -38,6 +38,7 @@ #include "ov-bool.h" #include "ov-bool-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" // range unary ops. @@ -82,6 +83,13 @@ return new octave_float_matrix (FloatNDArray (v.array_value ())); } +CONVDECL (range_to_matrix) +{ + CAST_CONV_ARG (const octave_range&); + + return new octave_matrix (v.array_value ()); +} + void install_range_ops (void) { @@ -108,6 +116,17 @@ INSTALL_CATOP (octave_char_matrix, octave_range, chm_r); INSTALL_CONVOP (octave_range, octave_float_matrix, range_to_float_matrix); + + // FIXME: this would be unneccessary if octave_base_value::numeric_assign always tried converting + // lhs before rhs. + + INSTALL_ASSIGNCONV (octave_range, octave_null_matrix, octave_matrix); + INSTALL_ASSIGNCONV (octave_range, octave_null_str, octave_matrix); + INSTALL_ASSIGNCONV (octave_range, octave_null_sq_str, octave_matrix); + + // However, this should probably be here just in case we need it. + + INSTALL_WIDENOP (octave_range, octave_matrix, range_to_matrix); } /*
--- a/src/OPERATORS/op-s-s.cc +++ b/src/OPERATORS/op-s-s.cc @@ -33,6 +33,7 @@ #include "ov-re-mat.h" #include "ov-flt-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -163,6 +164,10 @@ INSTALL_ASSIGNCONV (octave_scalar, octave_scalar, octave_matrix); INSTALL_ASSIGNCONV (octave_float_scalar, octave_scalar, octave_float_matrix); + INSTALL_ASSIGNCONV (octave_scalar, octave_null_matrix, octave_matrix); + INSTALL_ASSIGNCONV (octave_scalar, octave_null_str, octave_matrix); + INSTALL_ASSIGNCONV (octave_scalar, octave_null_sq_str, octave_matrix); + INSTALL_CONVOP (octave_scalar, octave_float_matrix, scalar_to_float); }
--- a/src/OPERATORS/op-scm-scm.cc +++ b/src/OPERATORS/op-scm-scm.cc @@ -29,6 +29,7 @@ #include "oct-obj.h" #include "ov.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "sparse-xdiv.h" @@ -179,6 +180,8 @@ DEFASSIGNOP_FN (assign, sparse_complex_matrix, sparse_complex_matrix, assign) +DEFNULLASSIGNOP_FN (null_assign, sparse_complex_matrix, delete_elements) + void install_scm_scm_ops (void) { @@ -235,6 +238,13 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, octave_sparse_complex_matrix, assign); + + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, + octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, + octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, + octave_null_sq_str, null_assign); } /*
--- a/src/OPERATORS/op-sm-sm.cc +++ b/src/OPERATORS/op-sm-sm.cc @@ -30,6 +30,7 @@ #include "ov.h" #include "ov-typeinfo.h" #include "ov-re-mat.h" +#include "ov-null-mat.h" #include "ops.h" #include "sparse-xpow.h" @@ -148,6 +149,8 @@ DEFASSIGNOP_FN (assign, sparse_matrix, sparse_matrix, assign) +DEFNULLASSIGNOP_FN (null_assign, sparse_matrix, delete_elements) + void install_sm_sm_ops (void) { @@ -186,6 +189,10 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_sparse_matrix, assign); + + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_sq_str, null_assign); } /*
--- a/src/OPERATORS/op-str-str.cc +++ b/src/OPERATORS/op-str-str.cc @@ -30,6 +30,7 @@ #include "ov.h" #include "ov-str-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" // string unary ops. @@ -92,6 +93,8 @@ return octave_value (); } +DEFNULLASSIGNOP_FN (null_assign, char_matrix_str, delete_elements) + DEFNDCHARCATOP_FN (str_str, char_matrix_str, char_matrix_str, concat) void @@ -142,6 +145,14 @@ INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_char_matrix_sq_str, assign); INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_char_matrix_str, assign); INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_char_matrix_sq_str, assign); + + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_sq_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_matrix, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_str, null_assign); + INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_sq_str, null_assign); + } /*
--- a/src/OPERATORS/op-ui16-ui16.cc +++ b/src/OPERATORS/op-ui16-ui16.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/OPERATORS/op-ui32-ui32.cc +++ b/src/OPERATORS/op-ui32-ui32.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/OPERATORS/op-ui64-ui64.cc +++ b/src/OPERATORS/op-ui64-ui64.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -135,6 +136,8 @@ OCTAVE_MM_INT_ASSIGN_OPS (mmui32, uint64_, uint32_, uint32_) OCTAVE_MM_INT_ASSIGN_OPS (mmi64, uint64_, int64_, int64_) +OCTAVE_INT_NULL_ASSIGN_OPS (uint64) + OCTAVE_MIXED_INT_CMP_OPS (uint64, int8) OCTAVE_MIXED_INT_CMP_OPS (uint64, uint8) OCTAVE_MIXED_INT_CMP_OPS (uint64, int16) @@ -200,6 +203,8 @@ OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui32, uint64_, uint32_); OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmi64, uint64_, int64_); + OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS (uint64) + OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, int8); OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, uint8); OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, int16);
--- a/src/OPERATORS/op-ui8-ui8.cc +++ b/src/OPERATORS/op-ui8-ui8.cc @@ -77,6 +77,7 @@ #include "ov-cx-mat.h" #include "ov-flt-cx-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h"
--- a/src/oct-obj.cc +++ b/src/oct-obj.cc @@ -237,6 +237,14 @@ return argv; } +void +octave_value_list::normalize_null_values (void) +{ + octave_idx_type len = length (); + for (octave_idx_type i = 0; i < len; i++) + data[i].make_non_null_value (); +} + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/oct-obj.h +++ b/src/oct-obj.h @@ -121,6 +121,8 @@ string_vector name_tags (void) const { return names; } + void normalize_null_values (void); + private: static octave_allocator allocator;
--- a/src/ops.h +++ b/src/ops.h @@ -152,6 +152,12 @@ const octave_value_list& idx, \ const octave_base_value& a2) +#define NULLASSIGNOPDECL(name) \ + static octave_value \ + oct_assignop_ ## name (octave_base_value& a, \ + const octave_value_list& idx, \ + const octave_base_value&) + #define ASSIGNANYOPDECL(name) \ static octave_value \ oct_assignop_ ## name (octave_base_value& a1, \ @@ -170,6 +176,15 @@ return octave_value (); \ } +#define DEFNULLASSIGNOP_FN(name, t, f) \ + NULLASSIGNOPDECL (name) \ + { \ + CAST_UNOP_ARG (octave_ ## t&); \ + \ + v.f (idx); \ + return octave_value (); \ + } + #define DEFNDASSIGNOP_FN(name, t1, t2, e, f) \ ASSIGNOPDECL (name) \ { \
--- a/src/ov-base-mat.cc +++ b/src/ov-base-mat.cc @@ -206,6 +206,23 @@ } template <class MT> +void +octave_base_matrix<MT>::delete_elements (const octave_value_list& idx) +{ + octave_idx_type len = idx.length (); + + Array<idx_vector> ra_idx (len); + + for (octave_idx_type i = 0; i < len; i++) + ra_idx(i) = idx(i).index_vector (); + + matrix.maybe_delete_elements (ra_idx, MT::resize_fill_value ()); + + // Invalidate the matrix type + typ.invalidate_type (); +} + +template <class MT> octave_value octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const {
--- a/src/ov-base-mat.h +++ b/src/ov-base-mat.h @@ -88,6 +88,8 @@ void assign (const octave_value_list& idx, const MT& rhs); + void delete_elements (const octave_value_list& idx); + dim_vector dims (void) const { return matrix.dims (); } octave_idx_type nnz (void) const { return matrix.nnz (); }
--- a/src/ov-base-sparse.cc +++ b/src/ov-base-sparse.cc @@ -196,6 +196,23 @@ typ.invalidate_type (); } +template <class MT> +void +octave_base_sparse<MT>::delete_elements (const octave_value_list& idx) +{ + octave_idx_type len = idx.length (); + + Array<idx_vector> ra_idx (len); + + for (octave_idx_type i = 0; i < len; i++) + ra_idx(i) = idx(i).index_vector (); + + matrix.maybe_delete_elements (ra_idx); + + // Invalidate the matrix type + typ.invalidate_type (); +} + template <class T> octave_value octave_base_sparse<T>::resize (const dim_vector& dv, bool) const
--- a/src/ov-base-sparse.h +++ b/src/ov-base-sparse.h @@ -97,6 +97,8 @@ void assign (const octave_value_list& idx, const T& rhs); + void delete_elements (const octave_value_list& idx); + dim_vector dims (void) const { return matrix.dims (); } octave_value do_index_op (const octave_value_list& idx,
--- a/src/ov-base.h +++ b/src/ov-base.h @@ -286,6 +286,8 @@ virtual bool is_true (void) const { return false; } + virtual bool is_null_value (void) const { return false; } + virtual bool is_constant (void) const { return false; } virtual bool is_function_handle (void) const { return false; }
--- a/src/ov-builtin.cc +++ b/src/ov-builtin.cc @@ -105,6 +105,9 @@ try { retval = (*f) (args, nargout); + // Do not allow null values to be returned from functions. + // FIXME: perhaps true builtins should be allowed? + retval.normalize_null_values (); } catch (octave_execution_exception) {
--- a/src/ov-cell.cc +++ b/src/ov-cell.cc @@ -230,8 +230,8 @@ if (t_rhs.is_cell ()) octave_base_matrix<Cell>::assign (i, t_rhs.cell_value ()); else - if (t_rhs.is_empty ()) - octave_base_matrix<Cell>::assign (i, Cell()); + if (t_rhs.is_null_value ()) + octave_base_matrix<Cell>::delete_elements (i); else octave_base_matrix<Cell>::assign (i, Cell (t_rhs)); @@ -263,7 +263,8 @@ octave_base_matrix<Cell>::assign (i, tmp_cell); } else - octave_base_matrix<Cell>::assign (i, Cell (t_rhs)); + // Regularize a null matrix if stored into a struct component. + octave_base_matrix<Cell>::assign (i, Cell (t_rhs.non_null_value ())); if (! error_state) {
new file mode 100644 --- /dev/null +++ b/src/ov-null-mat.cc @@ -0,0 +1,111 @@ +/* + +Copyright (C) 2008 Jaroslav Hajek + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ov-null-mat.h" +#include "ops.h" +#include "defun.h" + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_matrix, "null_matrix", "double"); + +const octave_value octave_null_matrix::instance (new octave_null_matrix ()); + +static octave_base_value * +default_null_matrix_numeric_conversion_function (const octave_base_value& a) +{ + CAST_CONV_ARG (const octave_null_matrix&); + + return a.empty_clone (); +} + +octave_base_value::type_conv_fcn +octave_null_matrix::numeric_conversion_function (void) const +{ + return default_null_matrix_numeric_conversion_function; +} + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_str, "null_string", "char"); + +const octave_value octave_null_str::instance (new octave_null_str ()); + +static octave_base_value * +default_null_str_numeric_conversion_function (const octave_base_value& a) +{ + CAST_CONV_ARG (const octave_null_str&); + + return a.empty_clone (); +} + +octave_base_value::type_conv_fcn +octave_null_str::numeric_conversion_function (void) const +{ + return default_null_str_numeric_conversion_function; +} + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_sq_str, "null_sq_string", "char"); + +const octave_value octave_null_sq_str::instance (new octave_null_sq_str ()); + +static octave_base_value * +default_null_sq_str_numeric_conversion_function (const octave_base_value& a) +{ + CAST_CONV_ARG (const octave_null_sq_str&); + + return a.empty_clone (); +} + +octave_base_value::type_conv_fcn +octave_null_sq_str::numeric_conversion_function (void) const +{ + return default_null_sq_str_numeric_conversion_function; +} + +DEFUN (isnull, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} isnull (@var{x})\n\ +Return 1 if @var{x} is a special null matrix, string or single quoted string.\n\ +Indexed assignment with such a value as right-hand side should delete array elements.\n\ +This function should be used when overloading indexed assignment for user-defined \n\ +classes instead of @code{isempty}, to distinguish the cases:\n\ +@table @asis\n\ +@item @code{A(I) = []}\n\ +This should delete elements if @code{I} is nonempty.\n\ +@item @code{X = []; A(I) = X}\n\ +This should give an error if @code{I} is nonempty.\n\ +@end table\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1 && args(0).is_defined ()) + retval = args(0).is_null_value (); + else + print_usage (); + + return retval; +} +
new file mode 100644 --- /dev/null +++ b/src/ov-null-mat.h @@ -0,0 +1,100 @@ +/* + +Copyright (C) 2008 Jaroslav Hajek + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if !defined (octave_null_matrix_h) +#define octave_null_matrix_h 1 + +#include "ov.h" +#include "ov-re-mat.h" +#include "ov-str-mat.h" + +// Design rationale: +// The constructors are hidden. There is only one null matrix (or null string) object, +// that can have shallow copies. Cloning the object returns just a normal empty matrix, +// so all the shallow copies are, in fact, read-only. This conveniently ensures that any +// attempt to fiddle with the null matrix destroys its special status. + +// The special [] value. + +class +OCTINTERP_API +octave_null_matrix : public octave_matrix +{ + octave_null_matrix (void) : octave_matrix () { } + +public: + + static const octave_value instance; + + bool is_null_value (void) const { return true; } + + type_conv_fcn numeric_conversion_function (void) const; + +private: + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +// The special "" value + +class +OCTINTERP_API +octave_null_str : public octave_char_matrix_str +{ + octave_null_str (void) : octave_char_matrix_str () { } + +public: + + static const octave_value instance; + + bool is_null_value (void) const { return true; } + + type_conv_fcn numeric_conversion_function (void) const; + + +private: + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +// The special '' value + +class +OCTINTERP_API +octave_null_sq_str : public octave_char_matrix_sq_str +{ + octave_null_sq_str (void) : octave_char_matrix_sq_str () { } + +public: + + static const octave_value instance; + + bool is_null_value (void) const { return true; } + + type_conv_fcn numeric_conversion_function (void) const; + +private: + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +#endif
--- a/src/ov-struct.cc +++ b/src/ov-struct.cc @@ -344,7 +344,7 @@ } else { - if (t_rhs.is_empty()) + if (t_rhs.is_null_value()) { map.maybe_delete_elements (idx.front()); @@ -385,7 +385,8 @@ map.assign (key, tmp_cell); } else - map.assign (key, t_rhs); + // Regularize a null matrix if stored into a struct component. + map.assign (key, t_rhs.non_null_value ()); if (! error_state) {
--- a/src/ov-type-conv.h +++ b/src/ov-type-conv.h @@ -20,6 +20,56 @@ */ +static +octave_value +octave_type_conv_body (const octave_value &arg, const std::string& name, int t_result) +{ + int t_arg = arg.type_id (); + octave_value retval; + + if (t_arg == t_result || arg.class_name () == name) + { + retval = arg; + } + else + { + octave_base_value::type_conv_fcn cf + = octave_value_typeinfo::lookup_type_conv_op (t_arg, t_result); + + if (cf) + { + octave_base_value *tmp (cf (*(arg.internal_rep ()))); + + if (tmp) + { + retval = octave_value (tmp); + + retval.maybe_mutate (); + } + } + else + { + octave_base_value::type_conv_fcn cf + = arg.numeric_conversion_function (); + + if (cf) + { + octave_base_value *tmp (cf (*(arg.internal_rep ()))); + + if (tmp) + { + octave_value xarg (tmp); + + retval = octave_type_conv_body (xarg, name, t_result); + } + } + } + } + + return retval; +} + + #define OCTAVE_TYPE_CONV_BODY3(NAME, MATRIX_RESULT_T, SCALAR_RESULT_T) \ \ octave_value retval; \ @@ -30,41 +80,19 @@ { \ const octave_value arg = args(0); \ \ - int t_arg = arg.type_id (); \ - \ int t_result = MATRIX_RESULT_T::static_type_id (); \ \ - if (t_arg == t_result || arg.class_name () == #NAME) \ - { \ - retval = arg; \ - } \ - else \ + retval = octave_type_conv_body (arg, #NAME, t_result); \ + if (retval.is_undefined ()) \ { \ - octave_base_value::type_conv_fcn cf \ - = octave_value_typeinfo::lookup_type_conv_op (t_arg, t_result); \ - \ - if (cf) \ - { \ - octave_base_value *tmp (cf (*(arg.internal_rep ()))); \ + std::string arg_tname = arg.type_name (); \ \ - if (tmp) \ - { \ - retval = octave_value (tmp); \ + std::string result_tname = arg.numel () == 1 \ + ? SCALAR_RESULT_T::static_type_name () \ + : MATRIX_RESULT_T::static_type_name (); \ \ - retval.maybe_mutate (); \ - } \ - } \ - else \ - { \ - std::string arg_tname = arg.type_name (); \ - \ - std::string result_tname = arg.numel () == 1 \ - ? SCALAR_RESULT_T::static_type_name () \ - : MATRIX_RESULT_T::static_type_name (); \ - \ - gripe_invalid_conversion (arg_tname, result_tname); \ - } \ - } \ + gripe_invalid_conversion (arg_tname, result_tname); \ + } \ } \ else \ print_usage (); \
--- a/src/ov.cc +++ b/src/ov.cc @@ -69,6 +69,7 @@ #include "ov-fcn-handle.h" #include "ov-fcn-inline.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "defun.h" #include "error.h" @@ -1153,7 +1154,8 @@ octave_value::assign (assign_op op, const octave_value& rhs) { if (op == op_asn_eq) - operator = (rhs); + // Regularize a null matrix if stored into a variable. + operator = (rhs.non_null_value ()); else { // FIXME -- only do the following stuff if we can't find @@ -1516,6 +1518,28 @@ type_name (), "complex vector")); } + +octave_value +octave_value::non_null_value (void) const +{ + if (is_null_value ()) + return octave_value (rep->empty_clone ()); + else + return *this; +} + +void +octave_value::make_non_null_value (void) +{ + if (is_null_value ()) + { + octave_base_value *rc = rep->empty_clone (); + if (--rep->count == 0) + delete rep; + rep = rc; + } +} + int octave_value::write (octave_stream& os, int block_size, oct_data_conv::data_type output_type, int skip, @@ -2397,6 +2421,9 @@ octave_float_complex::register_type (); octave_float_matrix::register_type (); octave_float_complex_matrix::register_type (); + octave_null_matrix::register_type (); + octave_null_str::register_type (); + octave_null_sq_str::register_type (); } #if 0
--- a/src/ov.h +++ b/src/ov.h @@ -489,6 +489,9 @@ bool is_magic_colon (void) const { return rep->is_magic_colon (); } + bool is_null_value (void) const + { return rep->is_null_value (); } + // Are any or all of the elements in this constant nonzero? octave_value all (int dim = 0) const @@ -835,6 +838,14 @@ Array<FloatComplex> float_complex_vector_value (bool frc_str_conv = false, bool frc_vec_conv = false) const; + // Make a copy that is not a special null matrix + + octave_value non_null_value (void) const; + + // Ditto, but in place. + + void make_non_null_value (void); + // Conversions. These should probably be private. If a user of this // class wants a certain kind of constant, he should simply ask for // it, and we should convert it if possible.
--- a/src/parse.y +++ b/src/parse.y @@ -65,6 +65,7 @@ #include "oct-map.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" +#include "ov-null-mat.h" #include "toplev.h" #include "pager.h" #include "parse.h" @@ -577,13 +578,19 @@ matrix : '[' ']' { - $$ = new tree_constant (octave_value (Matrix ())); + $$ = new tree_constant (octave_null_matrix::instance); lexer_flags.looking_at_matrix_or_assign_lhs = false; lexer_flags.pending_local_variables.clear (); } | '[' ';' ']' { - $$ = new tree_constant (octave_value (Matrix ())); + $$ = new tree_constant (octave_null_matrix::instance); + lexer_flags.looking_at_matrix_or_assign_lhs = false; + lexer_flags.pending_local_variables.clear (); + } + | '[' ',' ']' + { + $$ = new tree_constant (octave_null_matrix::instance); lexer_flags.looking_at_matrix_or_assign_lhs = false; lexer_flags.pending_local_variables.clear (); } @@ -1721,9 +1728,17 @@ { std::string txt = tok_val->text (); - char delim = op == DQ_STRING ? '"' : '\''; - - octave_value tmp (txt, delim); + char delim = op == DQ_STRING ? '"' : '\''; + octave_value tmp (txt, delim); + + if (txt.empty ()) + { + if (op == DQ_STRING) + tmp = octave_null_str::instance; + else + tmp = octave_null_sq_str::instance; + } + retval = new tree_constant (tmp, l, c); if (op == DQ_STRING)
--- a/src/pt-decl.h +++ b/src/pt-decl.h @@ -65,7 +65,8 @@ bool lvalue_ok (void) { return id ? id->lvalue_ok () : false; } - octave_value rvalue (void) { return id ? id->rvalue () : octave_value (); } + // Do not allow functions return null values + octave_value rvalue (void) { return id ? id->rvalue ().non_null_value () : octave_value (); } octave_value_list rvalue (int nargout) {