blob: bf7b117ae99373e8a5e74cf2241a4d5bd1ae1bdc [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/*
* XSEC
*
* XSECXPathNodeList := A structure to hold node lists from XPath
* evaluations
*
* $Id$
*
*/
// XSEC
#include <xsec/utils/XSECXPathNodeList.hpp>
#include <xsec/framework/XSECError.hpp>
#include <string.h>
XERCES_CPP_NAMESPACE_USE
// --------------------------------------------------------------------------------
// Constructors and Destructors.
// --------------------------------------------------------------------------------
XSECXPathNodeList::XSECXPathNodeList(unsigned int initialSize) {
m_num = 0;
mp_tree = NULL;
}
XSECXPathNodeList::XSECXPathNodeList(const XSECXPathNodeList &other) {
m_num = other.m_num;
mp_tree = copy_tree(other.mp_tree);
mp_current = NULL;
}
XSECXPathNodeList::~XSECXPathNodeList() {
// Delete all the elements in the node list
delete_tree(mp_tree);
}
XSECXPathNodeList & XSECXPathNodeList::operator= (const XSECXPathNodeList & toCopy) {
// For now simply delete the old list and set with the new
// Large overhead as we call other functions, but simplest way to
// implement for now
mp_tree = copy_tree(toCopy.mp_tree);
m_num = toCopy.m_num;
mp_current = NULL;
return *this;
}
// --------------------------------------------------------------------------------
// Utility Functions.
// --------------------------------------------------------------------------------
XSECXPathNodeList::btn * XSECXPathNodeList::findNodeIndex(const DOMNode *n) const {
btn * t = mp_tree;
while (t != NULL && t->v != n) {
if (n > t->v)
t = t->r;
else
t = t->l;
}
return t;
}
void XSECXPathNodeList::delete_tree(btn * t) {
if (t == NULL)
return;
btn * parent, * n;
n = t;
while (n != NULL) {
if (n->l)
n = n->l;
else if (n->r)
n = n->r;
else {
parent = n->p;
if (parent != NULL) {
if (parent->l == n)
parent->l = NULL;
else
parent->r = NULL;
}
// Delete this node
delete n;
n = parent;
}
}
}
XSECXPathNodeList::btn * XSECXPathNodeList::copy_tree(btn * t) const {
if (t == NULL)
return NULL;
btn * n, *c, *cp, *ret;
c = cp = NULL;
n = t;
bool create = true;
ret = NULL;
while (n != NULL) {
if (create) {
XSECnew(c, btn);
c->l = NULL;
c->r = NULL;
c->v = n->v;
// R we at top?
if (ret == NULL) {
ret = c;
c->p = NULL;
cp = NULL;
}
else {
c->p = cp;
if (cp != NULL) {
if (n->p->l == n)
cp->l = c;
else
cp->r = c;
}
}
}
// Go down!
if (c->l == NULL && n->l != NULL) {
cp = c;
n = n->l;
create = true;
}
else if (c->r == NULL && n->r != NULL) {
cp = c;
n = n->r;
create = true;
}
else {
// Go Back Up!
n = n->p;
c = cp;
if (cp != NULL)
cp = cp->p;
create = false;
}
}
return ret;
}
// --------------------------------------------------------------------------------
// Adding and Deleting Nodes.
// --------------------------------------------------------------------------------
long XSECXPathNodeList::balance_count(btn * t) const {
if (t == NULL)
return 0;
long r = (t->r == NULL ? 0 : t->r->h);
long l = (t->l == NULL ? 0 : t->l->h);
return r - l;
}
long XSECXPathNodeList::calc_height(btn * t) {
if (t == NULL)
return 0;
if (t->l == NULL) {
if (t->r == NULL)
return 1;
return t->r->h + 1;
}
else {
if (t->r == NULL)
return t->l->h + 1;
}
return ((t->l->h > t->r->h ? t->l->h : t->r->h) + 1);
}
void XSECXPathNodeList::rotate_right(btn * t) {
// Rotate me right!
btn * lc = t->l;
// First - are we at the root?
if (t == mp_tree) {
lc->p = NULL;
mp_tree = lc;
}
else {
if (t->p->l == t) {
t->p->l = lc;
}
else {
t->p->r = lc;
}
lc->p = t->p;
}
// Do the rotate
t->l = lc->r;
if (t->l)
t->l->p = t;
lc->r = t;
t->p = lc;
// Recalculate heights
lc = t;
while (lc != NULL) {
lc->h = calc_height(lc);
lc = lc->p;
}
}
void XSECXPathNodeList::rotate_left(btn * t) {
// Rotate me left!
btn * rc = t->r;
// First - are we at the root?
if (t == mp_tree) {
rc->p = NULL;
mp_tree = rc;
}
else {
if (t->p->r == t) {
t->p->r = rc;
}
else {
t->p->l = rc;
}
rc->p = t->p;
}
// Do the rotate
t->r = rc->l;
if (t->r)
t->r->p = t;
rc->l = t;
t->p = rc;
// Recalculate heights
rc = t;
while (rc != NULL) {
rc->h = calc_height(rc);
rc = rc->p;
}
}
void XSECXPathNodeList::addNode(const DOMNode *n) {
btn * v;
if (m_num == 0) {
XSECnew(mp_tree, btn);
mp_tree->l = mp_tree->r = NULL;
mp_tree->v = n;
mp_tree->p = NULL;
mp_tree->h = 1;
m_num = 1;
return;
}
// Find the node
btn * t = mp_tree;
btn * last = NULL;
while (t != NULL && t->v != n) {
last = t;
if (n > t->v)
t = t->r;
else
t = t->l;
}
if (t != NULL)
// Node already exists in tree!
return;
// Work out the insertion.
XSECnew(v, btn);
v->v = n;
v->r = v->l = NULL;
v->h = 1;
v->p = last;
// Determine on which leg to place the new value
if (n > last->v)
last->r = v;
else
last->l = v;
// Recalculate heights
t = last;
long newh;
while (t != NULL) {
newh = calc_height(t);
if (newh > t->h) {
t->h = newh;
t = t->p;
}
else
// If the height is the same here, then nothing will have changed above
t = NULL;
}
// Rebalance!
t = last;
while (t != NULL) {
long bal = balance_count(t);
long balrc = balance_count(t->r);
long ballc = balance_count(t->l);
// Case 1 - Balance is OK
if (bal <= 1 && bal >= -1) {
// Do nothing!
}
// Case 2a - Balance is -2 and LC = -1
else if (bal == -2 && ballc == -1) {
// Rotate current node right
rotate_right(t);
}
// Or balance is +2 and RC = +1
else if (bal == 2 && balrc == 1) {
// Rotate current node left
rotate_left(t);
}
// Case 2b = Balance is -2 and LC = +1
else if (bal == -2 && ballc == 1) {
// Double Right rotation
rotate_left(t->l);
rotate_right(t);
}
else {
rotate_right(t->r);
rotate_left(t);
}
t = t->p;
}
}
void XSECXPathNodeList::removeNode(const DOMNode *n) {
btn * t, * last;
last = NULL;
btn * i = findNodeIndex(n);
if (i == NULL)
// Not found!
return;
// Delete from tree
if (i == mp_tree) {
// Bugger - we are at the top of the tree
// OK - No children?
if (i->l == NULL && i->r == NULL) {
// WooHoo! Easy!
delete mp_tree;
mp_tree = NULL;
}
// One Child?
if (i->l != NULL && i->r == NULL) {
// WooHoo! Easy!
mp_tree = i->l;
mp_tree->p = NULL;
delete i;
}
if (i->r != NULL && i->l == NULL) {
// WooHoo! Easy!
mp_tree = i->r;
mp_tree->p = NULL;
delete i;
}
// Oh dear = we have two children and now some heartache
if (i->r->l == NULL && i->r->r == NULL) {
// No subtree on right hand side.
mp_tree = mp_tree->l;
mp_tree->p = NULL;
t = mp_tree->r;
last = mp_tree;
while (t != NULL) {
last = t;
if (i->r->v < t->v)
t = t->l;
else
t = t->r;
}
if (i->r->v < last->v) {
last->l = i->r;
i->r->p = last;
}
else {
last->r = i->r;
i->r->p = last;
}
}
else {
// Need to find the "in-order" successor
t = i->r;
while (t != NULL) {
last = t;
t=t->l;
}
if (last == i->r) {
// can't have been a left hand leg on the next node!)
last->l = i->l;
if (last->l != NULL)
last->l->p = last;
mp_tree = last;
last->p = NULL;
delete i;
}
else {
// OK - Last is now the next biggest node, and it doesn;t
// have anything on it's left (otherwise there would be something smaller)
last->p->l = last->r;
last->r->p = last->p;
last->l = i->l;
last->r = i->r;
if (last->r != NULL)
last->r->p = last;
if (last->l != NULL)
last->l->p = last;
mp_tree = last;
last->p = NULL;
delete i;
}
}
}
else {
/* i != mp_tree */
// OK - No children?
if (i->l == NULL && i->r == NULL) {
// WooHoo! Easy!
if (i->p->l == i)
i->p->l = NULL;
else
i->p->r = NULL;
delete i;
}
// One Child?
if (i->l != NULL && i->r == NULL) {
// WooHoo! Easy!
if (i->p->l == i) {
i->p->l = i->l;
i->l->p = i->p;
}
else {
i->p->r = i->l;
i->r->p = i->p;
}
delete i;
}
if (i->r != NULL && i->l == NULL) {
// WooHoo! Easy!
if (i->p->l == i) {
i->p->l = i->r;
i->r->p = i->p;
}
else {
i->p->r = i->r;
i->r->p = i->p;
}
delete i;
}
// Oh dear = we have two children and now some heartache
if (i->r->l == NULL && i->r->r == NULL) {
// No subtree on right hand side.
if (i->p->l == i) {
// Was left hand child
i->p->l = i->l;
i->l->p = i->p;
t = i->l;
// Find insertion point for dangling node
while (t != NULL) {
last = t;
t = t->r;
}
last->r = i->r;
i->r->p = last;
}
else {
// Was right hand child
i->p->r = i->l;
i->l->p = i->p;
t = i->l;
// Find insertion point for dangling node
while (t != NULL) {
last = t;
t = t->r;
}
last->r = i->r;
i->r->p = last;
}
}
else {
// Subtree - so need to find the "in-order" successor
t = i->r;
while (t != NULL) {
last = t;
t=t->l;
}
// OK - Last is now the next biggest node, and it doesn;t
// have anything on it's left (otherwise there would be something smaller)
last->p->l = last->r;
last->r->p = last->p;
last->l = i->l;
last->r = i->r;
if (last->r != NULL)
last->r->p = last;
if (last->l != NULL)
last->l->p = last;
mp_tree = last;
last->p = NULL;
delete i;
}
}
m_num--;
}
void XSECXPathNodeList::clear() {
m_num = 0;
delete_tree(mp_tree);
mp_tree = NULL;
}
// --------------------------------------------------------------------------------
// Information functions.
// --------------------------------------------------------------------------------
bool XSECXPathNodeList::hasNode(const DOMNode *n) const {
btn * i = findNodeIndex(n);
return (i != NULL);
}
const DOMNode *XSECXPathNodeList::getFirstNode(void) const {
if (mp_tree == NULL)
return NULL;
// Find the smallest node
mp_current = mp_tree;
while (mp_current->l != NULL)
mp_current = mp_current->l;
return mp_current->v;
}
const DOMNode *XSECXPathNodeList::getNextNode(void) const {
if (mp_current == NULL)
return NULL;
btn * t = mp_current;
if (t->r != NULL) {
// Find next biggest node
t = t->r;
while (t->l != NULL)
t = t->l;
mp_current = t;
}
else {
// Go backwards!
t = mp_current->p;
while (t != NULL && t->r == mp_current) {
mp_current = t;
t = t->p;
}
if (t == NULL) {
mp_current = NULL;
return NULL;
}
mp_current = t;
}
return t->v;
}
// --------------------------------------------------------------------------------
// Intersect with another list
// --------------------------------------------------------------------------------
void XSECXPathNodeList::intersect(const XSECXPathNodeList &toIntersect) {
// Create a new list
XSECXPathNodeList ret;
const DOMNode * n = getFirstNode();
while (n != NULL) {
if (toIntersect.hasNode(n))
ret.addNode(n);
n = getNextNode();
}
// Swap lists
btn * t = mp_tree;
mp_tree = ret.mp_tree;
ret.mp_tree = t;
m_num = ret.m_num;
return;
}