// Implementation of ChangeSorter. Lots of fun search methods.
#include <clientapi.h>
#include "changesorter.h"
ChangeSorter::ChangeSorter()
: head( NULL ), tail( NULL ), size( 0 ), arrsize( 0 )
{
}
// Destroy all nodes when destroying the list.
ChangeSorter::~ChangeSorter()
{
if ( head != NULL ) delete head;
}
// Insert a new change in the correct location to maintain
// sorted order. No duplicates allowed.
void ChangeSorter::AddChange( StrBuf& cbuf, FileRev* rev )
{
int n = cbuf.Atoi();
ChangeNode* cn = LookupChange( n );
if ( cn && cn->value == n ) return; //duplicate
//cn is the node before the point of insertion
ChangeNode* nn = new ChangeNode( cbuf, rev );
size++;
if ( !cn ) //insert at head
{
nn->next = head;
if ( head ) head->prev = nn;
else tail = nn;
head = nn;
return;
}
//otherwise, insert after cn
nn->next = cn->next;
if ( !cn->next ) tail = nn;
else cn->next->prev = nn;
nn->prev = cn;
cn->next = nn;
}
// Find the named change and mark it as having an arrow.
void ChangeSorter::MarkArrChange( StrBuf& cno )
{
int n = cno.Atoi();
ChangeNode* cn = LookupChange( n );
if ( cn && cn->value == n && !cn->hasarrow )
{
cn->hasarrow = true;
arrsize++;
}
}
// Store positional data about marked changes, so GetArrPos
// won't have to count them all every time.
void ChangeSorter::AlignArr()
{
if ( !arrsize ) return;
int arrcount = 1;
for ( ChangeNode* an = head ; an ; an = an->next )
{
if ( an->hasarrow ) an->arrpos = arrcount++;
}
}
// Same as GetPos, but for arrowed changes only.
int ChangeSorter::GetArrPos( StrBuf& inp )
{
int n = inp.Atoi();
ChangeNode* cn = LookupChange( n );
if ( cn && cn->value == n ) return cn->arrpos;
else return 0;
}
// Same as GetChange, but for arrowed changes only.
StrBuf ChangeSorter::GetArrChange( int pos )
{
for ( ChangeNode* an = head ; an ; an = an->next )
{
if ( an->arrpos == pos ) return an->change;
}
return StrBuf();
}
// Same as GetRev, but for arrowed changes only.
FileRev* ChangeSorter::GetArrRev( int pos )
{
for ( ChangeNode* an = head ; an ; an = an->next )
{
if ( an->arrpos == pos ) return an->frev;
}
return NULL;
}
// Get the index of the named change, with head = 1
int ChangeSorter::GetPos( StrBuf& input )
{
int n = input.Atoi();
int a = 1;
for ( ChangeNode* cn = head ; cn ; cn = cn->next )
{
if ( cn->value == n ) return a;
if ( cn->value > n ) return 0;
a++;
}
return 0;
}
// Inverse of GetPos.
StrBuf ChangeSorter::GetChange( int pos )
{
if ( ( pos < 1 ) || ( pos > size ) ) return StrBuf(); //error check
ChangeNode* cn = head;
for ( int a = 1 ; a <= size ; a++ )
{
if ( a == pos ) return cn->change;
if ( a > pos ) return StrBuf();
cn = cn->next;
}
return StrBuf();
}
// Return a FileRev from the changelist at the given pos.
FileRev* ChangeSorter::GetRev( int pos )
{
if ( ( pos < 1 ) || ( pos > size ) ) return NULL; //error check
ChangeNode* cn = head;
for ( int a = 1 ; a <= size ; a++ )
{
if ( a == pos ) return cn->frev;
if ( a > pos ) return NULL;
cn = cn->next;
}
return NULL;
}
// If change number n corresponds to a change in the list, return that
// node. Otherwise, return the one immediately before the spot where
// n should be inserted. If n should be placed at the head, return NULL.
ChangeNode* ChangeSorter::LookupChange( int n )
{
// bare-bones linear search implementation
for ( ChangeNode* cn = tail ; cn ; cn = cn->prev )
if ( cn->value <= n ) return cn;
return NULL;
}