#include "laddress.h"
#include <QDebug>
// LobAddress implementation here
LobAddress::LobAddress ()
{}
LobAddress::LobAddress ( const QString encoding )
{
//LobAddress result;
int i = 0;
while ( i < encoding.length() ) {
OmNode::OwnershipType stepType;
switch ( encoding[i++].toLatin1() ) {
case 'c': stepType = OmNode::AsChild; break;
case 'k': stepType = OmNode::AsKey; break;
case 'v': stepType = OmNode::AsValue; break;
case 's': continue; // self steps should be ignored
default : LobAddress(); return;// invalid step type, so return failure
}
int indexStart = i;
while ( ( i < encoding.length() ) && encoding[i].isDigit() )
i++;
if ( indexStart == i ) {
LobAddress(); // two letters in a row, or letter at end, so return failure
return;
}
unsigned int stepIndex = encoding.mid( indexStart, i-indexStart ).toUInt();
addStep( stepIndex, stepType );
}
//return result;
}
unsigned int LobAddress::stepIndex ( unsigned int i ) const
{
return stepIndices[i];
}
OmNode::OwnershipType LobAddress::stepType ( unsigned int i ) const
{
return stepTypes[i];
}
unsigned int LobAddress::numSteps () const
{
return stepIndices.count();
}
void LobAddress::addStep ( unsigned int index, OmNode::OwnershipType type )
{
if ( type == OmNode::None )
return;
stepIndices << index;
stepTypes << type;
}
LobAddress LobAddress::up () const
{
LobAddress result = *this;
result.stepIndices.removeLast();
result.stepTypes.removeLast();
return result;
}
LobAddress LobAddress::down () const
{
LobAddress result = *this;
result.stepIndices.removeFirst();
result.stepTypes.removeFirst();
return result;
}
LobAddress LobAddress::operator+ ( const LobAddress& other ) const
{
LobAddress result = *this;
result.stepIndices << other.stepIndices;
result.stepTypes << other.stepTypes;
return result;
}
bool LobAddress::operator< ( const LobAddress& other ) const
{
return strictOrderComparison( other, 0 );
}
bool LobAddress::strictOrderComparison ( const LobAddress& other, unsigned int i ) const
{
// they could be equal, which we will detect recursively by reaching a comparison
// of two empty lists, as this check notices:
if ( ( i >= numSteps() ) && ( i >= other.numSteps() ) )
return false;
// thus if i has fallen off the end of just one list, it is the lesser
if ( i >= numSteps() )
return true;
if ( i >= other.numSteps() )
return false;
// thus step i is in both lists, and we can compare it; we'll need this data:
unsigned int idx = stepIndex( i );
unsigned int oidx = other.stepIndex( i );
OmNode::OwnershipType type = stepType( i );
OmNode::OwnershipType otype = other.stepType( i );
// if both steps are to children, then judge by index, or recursively if indices equal:
if ( ( type == OmNode::AsChild ) && ( otype == OmNode::AsChild ) )
return ( idx == oidx ) ? strictOrderComparison( other, i + 1 ) : ( idx < oidx );
// if one is a child step and the other an attribute step, that determines order:
if ( type == OmNode::AsChild )
return false;
if ( otype == OmNode::AsChild )
return true;
// so both next steps are attributes; try to distinguish by index:
if ( idx != oidx )
return idx < oidx;
// so both next steps are to the same attribute; try to distinguish key from value:
if ( type != otype )
return type == OmNode::AsKey;
// so both are to the same key or value; recur
return strictOrderComparison( other, i + 1 );
}
bool LobAddress::operator== ( const LobAddress& other ) const
{
return ( stepIndices == other.stepIndices ) && ( stepTypes == other.stepTypes );
}
bool LobAddress::operator<= ( const LobAddress& other ) const
{
return ( *this < other ) || ( *this == other );
}
QString LobAddress::toString() const
{
QString result;
for ( int i = 0 ; i < stepIndices.count() ; i++ )
result += ( ( stepTypes[i] == OmNode::AsChild ) ? "c" :
( ( stepTypes[i] == OmNode::AsKey ) ? "k" : "v" ) )
+ QString::number( stepIndices[i] );
return result;
}
bool LobAddress::hasPrefix ( const LobAddress& other ) const{
if (numSteps() < other.numSteps()) return false;
for (unsigned int i = 0; i < other.numSteps(); i++)
if ((other.stepType(i) != stepType(i))
|| (other.stepIndex(i) != stepIndex(i)))
return false;
return true;
}
LobAddress LobAddress::addressInserted ( const LobAddress& loc ) const
{
LobAddress result = *this;
if ( !hasPrefix(loc.up())) return result;
if (numSteps() < loc.numSteps()) return result;
if ( (stepType(loc.numSteps()-1) != loc.stepType(loc.numSteps()-1))
&& (stepType(loc.numSteps()-1 ) != OmNode::AsKey || loc.stepType(loc.numSteps()-1)!= OmNode::AsValue)
&& (stepType(loc.numSteps()-1 ) != OmNode::AsValue || loc.stepType(loc.numSteps()-1)!= OmNode::AsKey))
return result;
if ( stepIndex(loc.numSteps()-1) >= loc.stepIndex(loc.numSteps()-1))
result.stepIndices[loc.numSteps()-1]++;
return result;
}
LobAddress LobAddress::addressRemoved ( const LobAddress& loc ) const
{
LobAddress result = *this;
if ( !hasPrefix(loc.up()) ) return result;
if (numSteps() < loc.numSteps()) return result;
if ( !stepType(loc.numSteps()-1) == loc.stepType(loc.numSteps()-1))
return result;
if ( stepIndex(loc.numSteps()-1) >= loc.stepIndex(loc.numSteps()-1))
result.stepIndices[loc.numSteps()-1]--;
return result;
}
uint qHash ( const LobAddress& key )
{
return qHash( key.toString() );
}