// -*- C++ -*-
// $RCSfile: sparselink.C,v $
// $Revision: 1.3 $
// $Author: langer $
// $Date: 2000/09/06 20:11:48 $


/* This software was produced by NIST, an agency of the U.S. government,
 * and by statute is not subject to copyright in the United States.
 * Recipients of this software assume all responsibilities associated
 * with its operation, modification and maintenance. However, to
 * facilitate maintenance we ask that before distributing modifed
 * versions of this software, you first contact the authors at
 * oof_manager@ctcms.nist.gov. 
 */

#ifndef SPARSELINK_C
#define SPARSELINK_C

#include "sparselink.h"
#include "vec.h"
#include <iostream.h>

// fixed size
template <class TYPE>
SparseLinkMatrix<TYPE>::SparseLinkMatrix(const int n, const int m)
	    : nrows(n), ncols(m), nz(0), row(n, 0), stretchy(0)
{}

// variable size
template <class TYPE>
SparseLinkMatrix<TYPE>::SparseLinkMatrix()
    : nrows(0), ncols(0), nz(0), row(0), stretchy(1)
{}

template <class TYPE>
SparseLinkMatrix<TYPE>::~SparseLinkMatrix() {
    clear();
}

template <class TYPE>
void SparseLinkMatrix<TYPE>::setsize(int n, int m) {
  clear();
  nrows = n;
  ncols = m;
  row.resize(n, 0);
  stretchy = 0;
}

template <class TYPE>
void SparseLinkMatrix<TYPE>::clear() {
    for(int i=0; i<nrows; i++) {
	SLMentry<TYPE> *tmp = row[i], *next;
	while(tmp) {
	    next = tmp->next;
	    delete tmp;
	    tmp = next;
	}
	row[i] = 0;
    }
    if(stretchy) {
	row.resize(0);
	nrows = ncols = 0;
    }
    nz = 0;
}

// access function (i,j) creates space for element (i,j) if necessary

template <class TYPE>
TYPE &SparseLinkMatrix<TYPE>::operator()(const int i, const int j) {
    // look through list row(i)
    if(stretchy) {
	if(i >= nrows) {    // make space for new row
	    nrows = i+1;
	    row.resize(nrows, (SLMentry<TYPE>*) 0);
	}
	if(j >= ncols)
	    ncols = j+1;
    }
    
    SLMentry<TYPE> *next = row[i];
    SLMentry<TYPE> *last = 0;
    SLMentry<TYPE> *newentry;
    while(next && next->col < j) {
	last = next;
	next = next->next;
    }
    
    if(!next) { // got through the whole list without finding anything
	if(last) {
	    newentry = last->next = new SLMentry<TYPE>(j);
	    nz++;
	    return newentry->val;
	}
	// nothing in list yet
	newentry = row[i] = new SLMentry<TYPE>(j);
	nz++;
	return newentry->val;
    }
    else {	// insert before end of list
	if(next->col == j)    // entry already there
	    return next->val;
	
	if(last) {  // insert between last and next
	    newentry = last->next = new SLMentry<TYPE>(j);
	    nz++;
	    newentry->next = next;
	    return newentry->val;
	}
	// insert at beginning of list
	newentry = row[i] = new SLMentry<TYPE>(j);
	nz++;
	newentry->next = next;
	return newentry->val;
    }
}

template <class TYPE>
ostream &operator<<(ostream &os, const SparseLinkMatrix<TYPE> &slm) {
    for(int i=0; i<slm.nrows; i++) {
	for(SLMentry<TYPE> *e = slm.row[i]; e != 0; e = e->next)
	    os << i << " " << e->col << " " << e->val << endl;
    }
    return os;
}

// ------------------------------------------------- //

template <class TYPE>
SparseLinkIterator<TYPE>::SparseLinkIterator(const SparseLinkMatrix<TYPE> &m)
    : slm(&m), rownumber(0), element(0), onerow(0)
{
    nextrow();
}

template <class TYPE>
SparseLinkIterator<TYPE>::SparseLinkIterator(const SparseLinkMatrix<TYPE> &m, 
							    const int rowno)
    : slm(&m), rownumber(rowno), element(0), onerow(1)
{
    if(rowno >=0 && rowno < slm->nrows)
	element = slm->row[rowno];
}

template <class TYPE>
int SparseLinkIterator<TYPE>::operator()(int &i, int &j, TYPE &x) {
    if(!element)
	return 0;   // done
    else {
	i = rownumber;
	j = element->col;
	x = element->val;
	element = element->next;
	if(!element) {
	    rownumber++;
	    nextrow();
	}
	return 1;
    }
}

template <class TYPE>
void SparseLinkIterator<TYPE>::nextrow() {	// find next non-empty row
    if(onerow) return;
    while(rownumber < slm->nrows && !(element=slm->row[rownumber]))
	rownumber++;
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1