// SPDX-License-Identifier: Apache-2.0 // // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au) // Copyright 2008-2016 National ICT Australia (NICTA) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ------------------------------------------------------------------------ //! \addtogroup SpSubview //! @{ /////////////////////////////////////////////////////////////////////////////// // SpSubview::iterator_base implementation // /////////////////////////////////////////////////////////////////////////////// template inline SpSubview::iterator_base::iterator_base(const SpSubview& in_M) : M(&in_M) , internal_col(0) , internal_pos(0) { // Technically this iterator is invalid (it may not point to a valid element) } template inline SpSubview::iterator_base::iterator_base(const SpSubview& in_M, const uword in_col, const uword in_pos) : M(&in_M) , internal_col(in_col) , internal_pos(in_pos) { // Nothing to do. } /////////////////////////////////////////////////////////////////////////////// // SpSubview::const_iterator implementation // /////////////////////////////////////////////////////////////////////////////// template inline SpSubview::const_iterator::const_iterator(const SpSubview& in_M, const uword initial_pos) : iterator_base(in_M, 0, initial_pos) { // Corner case for empty subviews. if(in_M.n_nonzero == 0) { iterator_base::internal_col = in_M.n_cols; skip_pos = in_M.m.n_nonzero; return; } // Figure out the row and column of the position. // lskip_pos holds the number of values which aren't part of this subview. const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; const uword ln_rows = iterator_base::M->n_rows; const uword ln_cols = iterator_base::M->n_cols; uword cur_pos = 0; // off by one because we might be searching for pos 0 uword lskip_pos = iterator_base::M->m.col_ptrs[aux_col]; uword cur_col = 0; while(cur_pos < (iterator_base::internal_pos + 1)) { // Have we stepped forward a column (or multiple columns)? while(((lskip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } // See if the current position is in the subview. const uword row_index = iterator_base::M->m.row_indices[cur_pos + lskip_pos]; if(row_index < aux_row) { ++lskip_pos; // not valid } else if(row_index < (aux_row + ln_rows)) { ++cur_pos; // valid, in the subview } else { // skip to end of column const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]; lskip_pos += (next_colptr - (cur_pos + lskip_pos)); } } iterator_base::internal_col = cur_col; skip_pos = lskip_pos; } template inline SpSubview::const_iterator::const_iterator(const SpSubview& in_M, const uword in_row, const uword in_col) : iterator_base(in_M, in_col, 0) { // Corner case for empty subviews. if(in_M.n_nonzero == 0) { // We must be at the last position. iterator_base::internal_col = in_M.n_cols; skip_pos = in_M.m.n_nonzero; return; } // We have a destination we want to be just after, but don't know what position that is. // Because we have to count the points in this subview and not in this subview, this becomes a little difficult and slow. const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; const uword ln_rows = iterator_base::M->n_rows; const uword ln_cols = iterator_base::M->n_cols; uword cur_pos = 0; skip_pos = iterator_base::M->m.col_ptrs[aux_col]; uword cur_col = 0; // Skip any empty columns. while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } while(cur_col < in_col) { // See if the current position is in the subview. const uword row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos]; if(row_index < aux_row) { ++skip_pos; } else if(row_index < (aux_row + ln_rows)) { ++cur_pos; } else { // skip to end of column const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]; skip_pos += (next_colptr - (cur_pos + skip_pos)); } // Have we stepped forward a column (or multiple columns)? while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } } // Now we are either on the right column or ahead of it. if(cur_col == in_col) { // We have to find the right row index. uword row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos]; while((row_index < (in_row + aux_row))) { if(row_index < aux_row) { ++skip_pos; } else { ++cur_pos; } // Ensure we didn't step forward a column; if we did, we need to stop. while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } if(cur_col != in_col) { break; } row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos]; } } // Now we need to find the next valid position in the subview. uword row_index; while(true) { const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]; row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos]; // Are we at the last position? if(cur_col >= ln_cols) { cur_col = ln_cols; // Make sure we will be pointing at the last element in the parent matrix. skip_pos = iterator_base::M->m.n_nonzero - iterator_base::M->n_nonzero; break; } if(row_index < aux_row) { ++skip_pos; } else if(row_index < (aux_row + ln_rows)) { break; // found } else { skip_pos += (next_colptr - (cur_pos + skip_pos)); } // Did we move any columns? while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } } // It is possible we have moved another column. while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols)) { ++cur_col; } iterator_base::internal_pos = cur_pos; iterator_base::internal_col = cur_col; } template inline SpSubview::const_iterator::const_iterator(const SpSubview& in_M, uword in_row, uword in_col, uword in_pos, uword in_skip_pos) : iterator_base(in_M, in_col, in_pos) , skip_pos(in_skip_pos) { arma_ignore(in_row); // Nothing to do. } template inline SpSubview::const_iterator::const_iterator(const const_iterator& other) : iterator_base(*other.M, other.internal_col, other.internal_pos) , skip_pos(other.skip_pos) { // Nothing to do. } template arma_inline eT SpSubview::const_iterator::operator*() const { return iterator_base::M->m.values[iterator_base::internal_pos + skip_pos]; } template inline typename SpSubview::const_iterator& SpSubview::const_iterator::operator++() { const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; const uword ln_rows = iterator_base::M->n_rows; const uword ln_cols = iterator_base::M->n_cols; uword cur_col = iterator_base::internal_col; uword cur_pos = iterator_base::internal_pos + 1; uword lskip_pos = skip_pos; uword row_index; while(true) { const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]; row_index = iterator_base::M->m.row_indices[cur_pos + lskip_pos]; // Did we move any columns? while((cur_col < ln_cols) && ((lskip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1])) { ++cur_col; } // Are we at the last position? if(cur_col >= ln_cols) { cur_col = ln_cols; // Make sure we will be pointing at the last element in the parent matrix. lskip_pos = iterator_base::M->m.n_nonzero - iterator_base::M->n_nonzero; break; } if(row_index < aux_row) { ++lskip_pos; } else if(row_index < (aux_row + ln_rows)) { break; // found } else { lskip_pos += (next_colptr - (cur_pos + lskip_pos)); } } iterator_base::internal_pos = cur_pos; iterator_base::internal_col = cur_col; skip_pos = lskip_pos; return *this; } template inline typename SpSubview::const_iterator SpSubview::const_iterator::operator++(int) { typename SpSubview::const_iterator tmp(*this); ++(*this); return tmp; } template inline typename SpSubview::const_iterator& SpSubview::const_iterator::operator--() { const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; const uword ln_rows = iterator_base::M->n_rows; uword cur_col = iterator_base::internal_col; uword cur_pos = iterator_base::internal_pos - 1; // Special condition for end of iterator. if((skip_pos + cur_pos + 1) == iterator_base::M->m.n_nonzero) { // We are at the last element. So we need to set skip_pos back to what it // would be if we didn't manually modify it back in operator++(). skip_pos = iterator_base::M->m.col_ptrs[cur_col + aux_col] - iterator_base::internal_pos; } uword row_index; while(true) { const uword colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col]; row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos]; // Did we move back any columns? while((skip_pos + cur_pos) < iterator_base::M->m.col_ptrs[cur_col + aux_col]) { --cur_col; } if(row_index < aux_row) { skip_pos -= (colptr - (cur_pos + skip_pos) + 1); } else if(row_index < (aux_row + ln_rows)) { break; // found } else { --skip_pos; } } iterator_base::internal_pos = cur_pos; iterator_base::internal_col = cur_col; return *this; } template inline typename SpSubview::const_iterator SpSubview::const_iterator::operator--(int) { typename SpSubview::const_iterator tmp(*this); --(*this); return tmp; } template inline bool SpSubview::const_iterator::operator==(const const_iterator& rhs) const { return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator!=(const const_iterator& rhs) const { return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator==(const typename SpMat::const_iterator& rhs) const { return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator!=(const typename SpMat::const_iterator& rhs) const { return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator==(const const_row_iterator& rhs) const { return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator!=(const const_row_iterator& rhs) const { return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator==(const typename SpMat::const_row_iterator& rhs) const { return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_iterator::operator!=(const typename SpMat::const_row_iterator& rhs) const { return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col); } /////////////////////////////////////////////////////////////////////////////// // SpSubview::iterator implementation // /////////////////////////////////////////////////////////////////////////////// template inline SpValProxy< SpSubview > SpSubview::iterator::operator*() { return SpValProxy< SpSubview >( const_iterator::row(), iterator_base::col(), access::rw(*iterator_base::M), &(access::rw(iterator_base::M->m.values[iterator_base::internal_pos + const_iterator::skip_pos]))); } template inline typename SpSubview::iterator& SpSubview::iterator::operator++() { const_iterator::operator++(); return *this; } template inline typename SpSubview::iterator SpSubview::iterator::operator++(int) { typename SpSubview::iterator tmp(*this); const_iterator::operator++(); return tmp; } template inline typename SpSubview::iterator& SpSubview::iterator::operator--() { const_iterator::operator--(); return *this; } template inline typename SpSubview::iterator SpSubview::iterator::operator--(int) { typename SpSubview::iterator tmp(*this); const_iterator::operator--(); return tmp; } /////////////////////////////////////////////////////////////////////////////// // SpSubview::const_row_iterator implementation // /////////////////////////////////////////////////////////////////////////////// template inline SpSubview::const_row_iterator::const_row_iterator() : iterator_base() , internal_row(0) , actual_pos(0) { } template inline SpSubview::const_row_iterator::const_row_iterator(const SpSubview& in_M, uword initial_pos) : iterator_base(in_M, 0, initial_pos) , internal_row(0) , actual_pos(0) { // Corner case for the end of a subview. if(initial_pos == in_M.n_nonzero) { iterator_base::internal_col = 0; internal_row = in_M.n_rows; return; } const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; // We don't count zeros in our position count, so we have to find the nonzero // value corresponding to the given initial position, and we also have to skip // any nonzero elements that aren't a part of the subview. uword cur_pos = std::numeric_limits::max(); uword cur_actual_pos = 0; // Since we don't know where the elements are in each row, we have to loop // across all columns looking for elements in row 0 and add to our sum, then // in row 1, and so forth, until we get to the desired position. for(uword row = 0; row < iterator_base::M->n_rows; ++row) { for(uword col = 0; col < iterator_base::M->n_cols; ++col) { // Find the first element with row greater than or equal to row + aux_row. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, row + aux_row); const uword offset = uword(pos_ptr - start_ptr); if(iterator_base::M->m.row_indices[col_offset + offset] == row + aux_row) { cur_actual_pos = col_offset + offset; // Increment position portably. if(cur_pos == std::numeric_limits::max()) cur_pos = 0; else ++cur_pos; // Do we terminate? if(cur_pos == initial_pos) { internal_row = row; iterator_base::internal_col = col; iterator_base::internal_pos = cur_pos; actual_pos = cur_actual_pos; return; } } } } } // This shouldn't happen. iterator_base::internal_pos = iterator_base::M->n_nonzero; iterator_base::internal_col = 0; internal_row = iterator_base::M->n_rows; actual_pos = iterator_base::M->n_nonzero; } template inline SpSubview::const_row_iterator::const_row_iterator(const SpSubview& in_M, uword in_row, uword in_col) : iterator_base(in_M, in_col, 0) , internal_row(0) , actual_pos(0) { // Start our search in the given row. We need to find two things: // // 1. The first nonzero element (iterating by rows) after (in_row, in_col). // 2. The number of nonzero elements (iterating by rows) that come before // (in_row, in_col). // // We'll find these simultaneously, though we will have to loop over all // columns. const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; // This will hold the total number of points in the subview with rows less // than in_row. uword cur_pos = 0; uword cur_min_row = iterator_base::M->n_rows; uword cur_min_col = 0; uword cur_actual_pos = 0; for(uword col = 0; col < iterator_base::M->n_cols; ++col) { // Find the first element with row greater than or equal to in_row. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { // First let us find the first element that is in the subview. const uword* first_subview_ptr = std::lower_bound(start_ptr, end_ptr, aux_row); if(first_subview_ptr != end_ptr && (*first_subview_ptr) < aux_row + iterator_base::M->n_rows) { // There exists at least one element in the subview. const uword* pos_ptr = std::lower_bound(first_subview_ptr, end_ptr, aux_row + in_row); // This is the number of elements in the subview with row index less // than in_row. cur_pos += uword(pos_ptr - first_subview_ptr); if(pos_ptr != end_ptr && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // This is the row index of the first element in the column with row // index greater than or equal to in_row + aux_row. if((*pos_ptr) - aux_row < cur_min_row) { // If we are in the desired row but before the desired column, we // can't take this. if(col >= in_col) { cur_min_row = (*pos_ptr) - aux_row; cur_min_col = col; cur_actual_pos = col_offset + (pos_ptr - start_ptr); } } } } } } // Now we know what the minimum row is. internal_row = cur_min_row; iterator_base::internal_col = cur_min_col; iterator_base::internal_pos = cur_pos; actual_pos = cur_actual_pos; } template inline SpSubview::const_row_iterator::const_row_iterator(const const_row_iterator& other) : iterator_base(*other.M, other.internal_col, other.internal_pos) , internal_row(other.internal_row) , actual_pos(other.actual_pos) { // Nothing to do. } template inline typename SpSubview::const_row_iterator& SpSubview::const_row_iterator::operator++() { // We just need to find the next nonzero element. ++iterator_base::internal_pos; // If we have exceeded the bounds, update accordingly. if(iterator_base::internal_pos >= iterator_base::M->n_nonzero) { internal_row = iterator_base::M->n_rows; iterator_base::internal_col = 0; actual_pos = iterator_base::M->n_nonzero; return *this; } const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; const uword M_n_cols = iterator_base::M->n_cols; // Otherwise, we need to search. We have to loop over all of the columns in // the subview. uword next_min_row = iterator_base::M->n_rows; uword next_min_col = 0; uword next_actual_pos = 0; for(uword col = iterator_base::internal_col + 1; col < M_n_cols; ++col) { // Find the first element with row greater than or equal to row. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { // Find the first element in the column with row greater than or equal to // the current row. Since this is a subview, it's possible that we may // find rows past the end of the subview. const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row); if(pos_ptr != end_ptr) { // We found something; is the row index correct? if((*pos_ptr) == internal_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // Exact match---so we are done. iterator_base::internal_col = col; actual_pos = col_offset + (pos_ptr - start_ptr); return *this; } else if((*pos_ptr) < next_min_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // The first element in this column is in a subsequent row, but it's // the minimum row we've seen so far. next_min_row = (*pos_ptr) - aux_row; next_min_col = col; next_actual_pos = col_offset + (pos_ptr - start_ptr); } else if((*pos_ptr) == next_min_row + aux_row && col < next_min_col && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // The first element in this column is in a subsequent row that we // already have another elemnt for, but the column index is less so // this element will come first. next_min_col = col; next_actual_pos = col_offset + (pos_ptr - start_ptr); } } } } // Restart the search in the next row. for(uword col = 0; col <= iterator_base::internal_col; ++col) { // Find the first element with row greater than or equal to row + 1. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row + 1); if(pos_ptr != end_ptr) { // We found something in the column, but is the row index correct? if((*pos_ptr) == internal_row + aux_row + 1 && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // Exact match---so we are done. iterator_base::internal_col = col; internal_row++; actual_pos = col_offset + (pos_ptr - start_ptr); return *this; } else if((*pos_ptr) < next_min_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // The first element in this column is in a subsequent row, but it's // the minimum row we've seen so far. next_min_row = (*pos_ptr) - aux_row; next_min_col = col; next_actual_pos = col_offset + (pos_ptr - start_ptr); } else if((*pos_ptr) == next_min_row + aux_row && col < next_min_col && (*pos_ptr) < aux_row + iterator_base::M->n_rows) { // We've found a better column. next_min_col = col; next_actual_pos = col_offset + (pos_ptr - start_ptr); } } } } iterator_base::internal_col = next_min_col; internal_row = next_min_row; actual_pos = next_actual_pos; return *this; } template inline typename SpSubview::const_row_iterator SpSubview::const_row_iterator::operator++(int) { typename SpSubview::const_row_iterator tmp(*this); ++(*this); return tmp; } template inline typename SpSubview::const_row_iterator& SpSubview::const_row_iterator::operator--() { if(iterator_base::internal_pos == 0) { // We are already at the beginning. return *this; } iterator_base::internal_pos--; const uword aux_col = iterator_base::M->aux_col1; const uword aux_row = iterator_base::M->aux_row1; // We have to search backwards. uword max_row = 0; uword max_col = 0; uword next_actual_pos = 0; for(uword col = iterator_base::internal_col; col >= 1; --col) { // Find the first element with row greater than or equal to in_row + 1. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col - 1]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { // There are elements in this column. const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row + 1); if(pos_ptr != start_ptr) { if(*(pos_ptr - 1) > max_row + aux_row) { // There are elements in this column with row index < internal_row. max_row = *(pos_ptr - 1) - aux_row; max_col = col - 1; next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr); } else if(*(pos_ptr - 1) == max_row + aux_row && (col - 1) >= max_col) { max_col = col - 1; next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr); } } } } for(uword col = iterator_base::M->n_cols - 1; col >= iterator_base::internal_col; --col) { // Find the first element with row greater than or equal to row + 1. const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ]; const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1]; const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset]; const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset]; if(start_ptr != end_ptr) { // There are elements in this column. const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row); if(pos_ptr != start_ptr) { // There are elements in this column with row index < internal_row. if(*(pos_ptr - 1) > max_row + aux_row) { max_row = *(pos_ptr - 1) - aux_row; max_col = col; next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr); } else if(*(pos_ptr - 1) == max_row + aux_row && col >= max_col) { max_col = col; next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr); } } } if(col == 0) // Catch edge case that the loop termination condition won't. { break; } } iterator_base::internal_col = max_col; internal_row = max_row; actual_pos = next_actual_pos; return *this; } template inline typename SpSubview::const_row_iterator SpSubview::const_row_iterator::operator--(int) { typename SpSubview::const_row_iterator tmp(*this); --(*this); return tmp; } template inline bool SpSubview::const_row_iterator::operator==(const const_iterator& rhs) const { return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator!=(const const_iterator& rhs) const { return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator==(const typename SpMat::const_iterator& rhs) const { return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator!=(const typename SpMat::const_iterator& rhs) const { return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator==(const const_row_iterator& rhs) const { return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator!=(const const_row_iterator& rhs) const { return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator==(const typename SpMat::const_row_iterator& rhs) const { return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col); } template inline bool SpSubview::const_row_iterator::operator!=(const typename SpMat::const_row_iterator& rhs) const { return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col); } /////////////////////////////////////////////////////////////////////////////// // SpSubview::row_iterator implementation // /////////////////////////////////////////////////////////////////////////////// template inline SpValProxy< SpSubview > SpSubview::row_iterator::operator*() { return SpValProxy< SpSubview >( const_row_iterator::internal_row, iterator_base::internal_col, access::rw(*iterator_base::M), &access::rw(iterator_base::M->m.values[const_row_iterator::actual_pos])); } template inline typename SpSubview::row_iterator& SpSubview::row_iterator::operator++() { const_row_iterator::operator++(); return *this; } template inline typename SpSubview::row_iterator SpSubview::row_iterator::operator++(int) { typename SpSubview::row_iterator tmp(*this); ++(*this); return tmp; } template inline typename SpSubview::row_iterator& SpSubview::row_iterator::operator--() { const_row_iterator::operator--(); return *this; } template inline typename SpSubview::row_iterator SpSubview::row_iterator::operator--(int) { typename SpSubview::row_iterator tmp(*this); --(*this); return tmp; } //! @}