blob: 373ce56d514b57203f04674fed062efe3ed74349 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
#include <math.h> // isgreater, isless
#include "TTCN3.hh"
#include "EPTF_CLL_Common_Definitions.hh"
#include "EPTF_CLL_RBT_Definitions.hh"
#include "EPTF_CLL_RBT_Functions.hh"
// EPTF_RBT_MINITEMGROWBY and EPTF_RBT_GROWBYSHIFT may be specified in makefile.
// The number of new items preallocated will be (assuming itemAllocCount is the old allocation count):
// exp2(ceil(log2(itemAllocCount>>EPTF_RBT_GROWBYSHIFT))) i.e.
// (itemAllocCount>>EPTF_RBT_GROWBYSHIFT) round up to the nearest base-2 exponent if
// greater than EPTF_RBT_MINITEMGROWBY, otherwise EPTF_RBT_MINITEMGROWBY
#ifndef EPTF_RBT_MINITEMGROWBY
#define EPTF_RBT_MINITEMGROWBY 32
#endif
#ifndef EPTF_RBT_GROWBYSHIFT
#define EPTF_RBT_GROWBYSHIFT 7
#endif
#if EPTF_RBT_MINITEMGROWBY < 1
#error "EPTF_RBT_MINITEMGROWBY must be a positive integer number"
#endif
#if EPTF_RBT_GROWBYSHIFT < 1
#error "EPTF_RBT_GROWBYSHIFT must be a positive integer number"
#endif
#define FLAG_RED 1
#define FLAG_NODE 2 // node or (non-head) cluster element
#define FLAG_FREE 4 // item is in the free chain
#define FLAG_INVALID 8 // item is invalid, i.e. neither in the tree, nor in the free chain
#if (defined(EPTF_DEBUG) && !defined(EPTF_RBT_DEBUG))
#define EPTF_RBT_DEBUG
#endif
using namespace EPTF__CLL__Common__Definitions;
using namespace EPTF__CLL__RBT__Definitions;
namespace EPTF__CLL__RBT__Functions {
typedef enum {K_double=0, K_int=1, K_charstring=2} EPTF_RBT_KeyType; // currently supported key types
const char *EPTF_RBT_KeyTypeNames[] = { "float", "integer", "charstring" };
class EPTF_RBT_Base
{
protected:
EPTF_RBT_KeyType keyType;
char *name;
int itemCount; // number of used allocated items (tree node, chain item and free chain together)
int itemAllocCount; // number of allocated items
#ifdef EPTF_RBT_DEBUG
int maxItemCount;
double increaseRate;
#endif
int root; // <0 -> empty
int freeHead; // free chain works like a stack
int freeCount; // number of free items
int smallestKeyIndex; // <0 -> invalid
EPTF_RBT_Base(EPTF_RBT_KeyType p_keyType, const char *pl_name);
public:
virtual ~EPTF_RBT_Base();
inline EPTF_RBT_KeyType getKeyType() const { return keyType; }
inline const char *getName() const { return name; }
virtual void removeItemFromTree(int itemIdx) = 0;
virtual void putItemInFreeChain(int itemIdx) = 0;
virtual int getSmallest() = 0;
inline int getRoot() const { return root; }
virtual int getLeft(int itemIdx) const = 0;
virtual int getRight(int itemIdx) const = 0;
virtual int getParent(int itemIdx) const = 0;
virtual int getNextInChain(int itemIdx) const = 0;
virtual int getPrevInChain(int itemIdx) const = 0;
virtual int iterateIncremental(int itemIdx) const = 0;
virtual void sortIncremental(EPTF__RBT__ItemIdxList &items) = 0;
inline int getItemCount() const { return itemCount; } // number of nodes + chain items + free items
inline int getFreeCount() const { return freeCount; }
inline int getTreeItemCount() const { return itemCount - freeCount; } // number of nodes + chain items
virtual bool isTreeValid() = 0;
virtual void dumpToPng(const char *name) = 0;
virtual bool isItemNode(int itemIdx) const = 0;
virtual bool isItemRed(int itemIdx) const = 0;
virtual bool isItemFree(int itemIdx) const = 0;
virtual bool isItemInvalid(int itemIdx) const = 0;
};
template <class TKey, class TKeyHelper>
class EPTF_RBT
: public EPTF_RBT_Base
{
private:
// items are stored in a linear "array", so each item has a unique id, its index
// three types of items are stored in the linear "array": a node, a non-head cluster element or a free item
// a node can be the head of a cluster
// if the head of a cluster is removed, the next item has to become the node, so the parent node must point to that
// the free chain contains only cluster items, bwd of head and fwd of tail are -1
struct Item {
int flags;
TKey key;
union {
struct { // valid if flags&FLAG_NODE
int left;
int right;
int parent;
int fwd; // -1 if single element
int endOfCluster; // self if single element
} node;
struct { // valid if !(flags&FLAG_NODE) (i.e. if in cluster but not the head, which is also the node in the tree)
int startOfCluster; // Note: this is only valid if fwd < 0, i.e. if the item is the end of the chain! It is not updated for intermediate items!
int fwd; // -1 if last
int bwd;
} clusterItem;
struct { // valid if flags&FLAG_FREE
int next; // free chain works like a stack
} freeItem;
};
};
Item *items;
int findInsertionPoint(TKey key, int &insertionPoint);
void insertItemHelper(int itemIdx, TKey key);
void rotateRight(int aIdx);
void rotateLeft(int aIdx);
void fixRed(int nodeIdx);
inline void swapIdx(int &i1, int &i2);
void updateParent(int itemIdx, int newChildIdx);
void swapNodes(int itemIdx, int successorIdx);
void fixRemove(int itemIdx);
void removeNodeWithOneOrNoChild(int itemIdx);
void removeNodeWithTwoChildren(int itemIdx);
inline int findSmallestFrom(int idx) const;
inline int getNodeWithNextBiggerKey(int itemIdx) const;
int black_depth;
bool checkNode(int itemIdx, int parentIdx, int depth);
int countChainLength(int nodeIdx);
int dumpNode(FILE *fp, int nodeIdx);
int allocItem();
public:
EPTF_RBT(EPTF_RBT_KeyType p_keyType, const char *pl_name);
EPTF_RBT(const EPTF_RBT &other);
~EPTF_RBT();
int insertItem(TKey key);
int insertItem(TKey key, bool isRed, int parentItemIdx); // only for testing!!!
void removeItemFromTree(int itemIdx); // does not put it in the free chain, also use putItemInFreeChain!
void putItemInFreeChain(int itemIdx);
int getSmallest();
TKey getKey(int itemIdx);
int findByKey(TKey key);
int getLeft(int itemIdx) const;
int getRight(int itemIdx) const;
int getParent(int itemIdx) const;
int getNextInChain(int itemIdx) const;
int getPrevInChain(int itemIdx) const;
int iterateIncremental(int itemIdx) const;
void sortIncremental(EPTF__RBT__ItemIdxList &items);
bool isTreeValid();
void dumpToPng(const char *name);
bool isItemNode(int itemIdx) const;
bool isItemRed(int itemIdx) const;
bool isItemFree(int itemIdx) const;
bool isItemInvalid(int itemIdx) const;
};
#include <stdio.h>
#include <stdarg.h>
void f_EPTF_RBT_error(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
char err_str[4096];
vsprintf(err_str, msg, ap);
va_end(ap);
#ifdef EPTF_DEBUG
EPTF__CLL__Base__Functions::f__EPTF__Base__assert(CHARSTRING(err_str), BOOLEAN(FALSE));
#else
TTCN_Logger::log_str(TTCN_Logger::ERROR_UNQUALIFIED, err_str);
EPTF__CLL__Base__Functions::f__EPTF__Base__stop(FAIL);
//TTCN_error(err_str);
#endif
}
///////////////////////////////////////////////////////////////////////////////
// EPTF_RBT_Base
///////////////////////////////////////////////////////////////////////////////
EPTF_RBT_Base::EPTF_RBT_Base(EPTF_RBT_KeyType p_keyType, const char *pl_name)
: keyType(p_keyType),
name(NULL),
itemCount(0),
itemAllocCount(0),
root(-1),
freeHead(-1),
freeCount(0),
smallestKeyIndex(-1)
#ifdef EPTF_RBT_DEBUG
,maxItemCount( (int)EPTF__CLL__Common__Definitions::tsp__CLL__debug__acceptableMaxSizeOfGrowingVariables )
,increaseRate( (double)EPTF__CLL__Common__Definitions::tsp__CLL__debug__increasePercentage4AcceptableMaxSize )
#endif
{
if(pl_name) {
name = new char[strlen(pl_name) + 1];
strcpy(name, pl_name);
}
#ifdef EPTF_RBT_DEBUG //corrigate the parameters if the growth is less than 1
if( maxItemCount>=0 && increaseRate>=0 && ((double)maxItemCount)*increaseRate<1.0 )
{
if(increaseRate == 0)
{
increaseRate=0.5;
}
maxItemCount = (int)(1.0/increaseRate + 1.0);
}
#endif
}
EPTF_RBT_Base::~EPTF_RBT_Base()
{
if(name) delete []name;
}
///////////////////////////////////////////////////////////////////////////////
// EPTF_RBT
///////////////////////////////////////////////////////////////////////////////
template <class TKey, class TKeyHelper>
EPTF_RBT<TKey,TKeyHelper>::EPTF_RBT(
EPTF_RBT_KeyType p_keyType,
const char *pl_name)
: EPTF_RBT_Base(p_keyType, pl_name),
items(NULL)
{
}
template <class TKey, class TKeyHelper>
EPTF_RBT<TKey,TKeyHelper>::EPTF_RBT(const EPTF_RBT &other)
: EPTF_RBT_Base(other.keyType, other.name)
{
itemCount = other.itemCount;
itemAllocCount = other.itemAllocCount;
root = other.root;
freeHead = other.freeHead;
freeCount = other.freeCount;
smallestKeyIndex = other.smallestKeyIndex;
items = (Item*) Malloc(other.itemAllocCount * sizeof(Item));
memcpy(items, other.items, other.itemCount * sizeof(Item));
}
template <class TKey, class TKeyHelper>
EPTF_RBT<TKey,TKeyHelper>::~EPTF_RBT()
{
for(int i=0;i<itemCount;i++) {
TKeyHelper::dealloc(items[i].key);
}
if(items) Free(items);
items = NULL;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::findInsertionPoint(TKey key, int &insertionPoint)
{
insertionPoint=root;
// TODO: assert: root must be >= 0
int cmp_res;
for(;;) {
cmp_res = TKeyHelper::compare(key, items[insertionPoint].key);
if(cmp_res > 0) {
if(items[insertionPoint].node.right >= 0) {
insertionPoint = items[insertionPoint].node.right;
} else break;
} else if(cmp_res <0) {
if(items[insertionPoint].node.left >= 0) {
insertionPoint = items[insertionPoint].node.left;
} else break;
} else {
break;
}
}
return cmp_res;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::insertItemHelper(int itemIdx, TKey key)
{
Item *item = items + itemIdx;
// item->key = key;
item->key = TKeyHelper::clone(key);
if(root < 0) { // empty tree
root = itemIdx;
item->flags = FLAG_NODE; // root node is black
item->node.left = -1;
item->node.right = -1;
item->node.parent = -1;
item->node.fwd = -1;
item->node.endOfCluster = itemIdx;
} else {
int insertionPoint;
int cmp_res = findInsertionPoint(key, insertionPoint);
// note: in this context (compared to the wikipedia) node is the parent node when inserting item as the new node,
// node.parent is the grandparent of the new item, node's sibling is item's uncle
Item *node = items + insertionPoint;
if(cmp_res > 0) { // key > node->key
// add as right leaf
item->flags = FLAG_NODE | FLAG_RED;
item->node.left = -1;
item->node.right = -1;
item->node.parent = insertionPoint;
item->node.fwd = -1;
item->node.endOfCluster = itemIdx;
node->node.right = itemIdx;
if(node->flags & FLAG_RED) { // fix red violation (item and its parent, 'node' are both red)
fixRed(itemIdx);
}
// } else if(TKeyHelper::isLower(key, node->key)) {
} else if(cmp_res < 0) { // key < node->key
// add as left leaf
item->flags = FLAG_NODE | FLAG_RED;
item->node.left = -1;
item->node.right = -1;
item->node.parent = insertionPoint;
item->node.fwd = -1;
item->node.endOfCluster = itemIdx;
node->node.left = itemIdx;
if(node->flags & FLAG_RED) { // fix red violation (item and its parent, 'node' are both red)
fixRed(itemIdx);
}
} else { // key == node.key
// add as cluster item
item->flags = 0;
item->clusterItem.startOfCluster = insertionPoint;
item->clusterItem.fwd = -1;
if(node->node.fwd < 0) { // empty chain, append to node (chain head)
node->node.fwd = itemIdx;
item->clusterItem.bwd = insertionPoint;
} else { // non-empty chain, append to end of chain
items[node->node.endOfCluster].clusterItem.fwd = itemIdx;
item->clusterItem.bwd = node->node.endOfCluster;
}
node->node.endOfCluster = itemIdx;
}
}
}
/* | |
a b
/ \ / \
b x1 -> x2 a
/ \ / \
x2 x3 x3 x1 */
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::rotateRight(int aIdx)
{
Item *a = items + aIdx;
int bIdx = a->node.left;
if(bIdx < 0) f_EPTF_RBT_error("EPTF_RBT::rotateRight: node has no left child");
Item *b = items + bIdx;
if(aIdx == root) { // FIXME: use updateParent?
root = bIdx;
} else {
Item *r = items + a->node.parent;
if(r->node.left == aIdx) {
r->node.left = bIdx;
} else {
r->node.right = bIdx;
}
}
b->node.parent = a->node.parent;
a->node.parent = bIdx;
a->node.left = b->node.right;
if(b->node.right >= 0) items[b->node.right].node.parent = aIdx;
b->node.right = aIdx;
}
/* | |
a b
/ \ / \
x1 b -> a x3
/ \ / \
x2 x3 x1 x2 */
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::rotateLeft(int aIdx)
{
Item *a = items + aIdx;
int bIdx = a->node.right;
if(bIdx < 0) f_EPTF_RBT_error("EPTF_RBT::rotateLeft: node has no right child");
Item *b = items + bIdx;
if(aIdx == root) { // FIXME: use updateParent?
root = bIdx;
} else {
Item *r = items + a->node.parent;
if(r->node.left == aIdx) {
r->node.left = bIdx;
} else {
r->node.right = bIdx;
}
}
b->node.parent = a->node.parent;
a->node.parent = bIdx;
a->node.right = b->node.left;
if(b->node.left >= 0) items[b->node.left].node.parent = aIdx;
b->node.left = aIdx;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::fixRed(int nodeIdx)
{
for(;;) {
Item *node = items + nodeIdx;
int parentIdx = node->node.parent;
if(parentIdx < 0) { // nodeIdx is root
node->flags &= ~FLAG_RED;
break;
}
Item *parent = items + parentIdx;
if((parent->flags&FLAG_RED) == 0) break; // parent is black node
int grandparentIdx = parent->node.parent;
if(grandparentIdx < 0) { // parent is root
parent->flags &= ~FLAG_RED;
break;
}
Item *grandparent = items + grandparentIdx;
bool leftparent = false;
int uncleIdx = grandparent->node.left;
if(uncleIdx == parentIdx) {
uncleIdx = grandparent->node.right;
leftparent = true;
}
if(uncleIdx >= 0) {
// note: parent is red at this point (there's a return/break earlier if parent is black)
if(//(parent->flags&FLAG_RED) &&
(items[uncleIdx].flags&FLAG_RED)) {
grandparent->flags |= FLAG_RED;
parent->flags &= ~FLAG_RED;
items[uncleIdx].flags &= ~FLAG_RED;
nodeIdx = grandparentIdx;
continue;
}
}
// note: at this point both node and parent are red, but uncle is black
if(leftparent) {
if(parent->node.left == nodeIdx) { // node is left child of parent - A
// rotate parent-grandparent
rotateRight(grandparentIdx);
parent->flags &= ~FLAG_RED;
grandparent->flags |= FLAG_RED;
} else { // node is right child of parent - B
// note: the two rotation are equivalent to the first one (rotate node-parent) then calling fixRed for parent
rotateLeft(parentIdx);
rotateRight(grandparentIdx);
node->flags &= ~FLAG_RED;
grandparent->flags |= FLAG_RED;
}
} else {
if(parent->node.left == nodeIdx) { // node is left child of parent - mirror of B
rotateRight(parentIdx);
rotateLeft(grandparentIdx);
node->flags &= ~FLAG_RED;
grandparent->flags |= FLAG_RED;
} else { // node is right child of parent - mirror of A
// rotate parent-grandparent
rotateLeft(grandparentIdx);
parent->flags &= ~FLAG_RED;
grandparent->flags |= FLAG_RED;
}
}
break;
}
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::swapIdx(int &i1, int &i2)
{
int tmp = i1;
i1 = i2;
i2 = tmp;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::updateParent(int itemIdx, int newChildIdx)
{
int parentIdx = items[itemIdx].node.parent;
if(parentIdx >= 0) {
if(items[parentIdx].node.left == itemIdx) {
items[parentIdx].node.left = newChildIdx;
} else {
items[parentIdx].node.right = newChildIdx;
}
} else { // no parent - root node
#ifdef EPTF_DEBUG
if(itemIdx != root) {
f_EPTF_RBT_error("EPTF_RBT::updateParent: parent index of item is -1 but it is not the root node.");
}
#endif
root = newChildIdx;
}
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::swapNodes(int itemIdx, int successorIdx)
{
Item *item = items + itemIdx;
Item *successor = items + successorIdx;
// update parents
updateParent(itemIdx, successorIdx); // NOTE: this DOES NOT update successor->node.parent!
updateParent(successorIdx, itemIdx);
// update nodes that are swapped
swapIdx(item->node.parent, successor->node.parent);
swapIdx(item->node.left, successor->node.left);
swapIdx(item->node.right, successor->node.right);
// swap the RED flag of the nodes
int tmp = (item->flags & FLAG_RED) ^ (successor->flags & FLAG_RED);
item->flags ^= tmp;
successor->flags ^= tmp;
// if(itemIdx == tree.root) tree.root = successorIdx; // done by updateParent
// note: don't swap the chains! (item.node.fwd, successor.node.fwd)
// update parent pointer of children of the nodes being swapped
// note: left/right pointers of item and successor are already swapped
if(item->node.left >= 0) items[item->node.left].node.parent = itemIdx;
if(item->node.right >= 0) items[item->node.right].node.parent = itemIdx;
if(successor->node.left >= 0) items[successor->node.left].node.parent = successorIdx;
if(successor->node.right >= 0) items[successor->node.right].node.parent = successorIdx;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::fixRemove(int itemIdx)
{
for(;;) {
Item *item = items + itemIdx;
if(item->node.parent < 0) { // root node (case 1)
break;
} else {
int parentIdx = item->node.parent;
Item *parent = items + parentIdx;
int siblingIdx = parent->node.left;
bool siblingIsLeft = true;
if(siblingIdx == itemIdx) {
siblingIdx = parent->node.right;
siblingIsLeft = false;
}
Item *sibling = items + siblingIdx;
if(sibling->flags & FLAG_RED) { // (case 2)
// swap the RED flag of the nodes
int tmp = (sibling->flags & FLAG_RED) ^ (parent->flags & FLAG_RED);
// FLAG_RED in tmp will be 1 if FLAG_RED differs in sibling and parent
sibling->flags ^= tmp; // invert FLAG_RED if differs
parent->flags ^= tmp; // invert FLAG_RED if differs
// rotate sibling-parent
if(siblingIsLeft) {
rotateRight(parentIdx);
} else {
rotateLeft(parentIdx);
}
continue;
} else { // note: sibling is already BLACK here
// siblings left child exists and is red
bool redSL = (sibling->node.left >= 0) && (items[sibling->node.left].flags & FLAG_RED);
// siblings right child exists and is red
bool redSR = (sibling->node.right >= 0) && (items[sibling->node.right].flags & FLAG_RED);
if(!redSL && !redSR) { // both children of sibling is black (or nonexistent)
if((parent->flags & FLAG_RED) == 0) {
// parent, sibling and siblings both children are black -> repaint sibling red (case 3)
sibling->flags |= FLAG_RED;
itemIdx = parentIdx; // goto case 1 with parent
continue;
} else {
// sibling and siblings both children are black but parent is red (case 4)
// swap color of sibling and parent
sibling->flags |= FLAG_RED;
parent->flags &= ~FLAG_RED;
break;
}
} else { // at least one of the siblings child is red
if(siblingIsLeft) {
if(redSR) { // case 5
sibling->flags |= FLAG_RED;
items[sibling->node.right].flags &= ~FLAG_RED;
int tmp = sibling->node.right;
rotateLeft(siblingIdx);
// continue with case 6
siblingIdx = tmp;
sibling = items + siblingIdx;
redSL = true;//(sibling->node.left >= 0) && (tree.items[sibling->node.left].flags & FLAG_RED);
}
if(redSL) { // case 6
// sibling takes the color of parent, parent becomes red, siblings child becomes black, rotate parent
int tmp = parent->flags & FLAG_RED;
sibling->flags &= ~FLAG_RED;
sibling->flags |= tmp;
parent->flags &= ~FLAG_RED;
items[sibling->node.left].flags &= ~FLAG_RED;
rotateRight(parentIdx);
}
} else {
if(redSL) { // case 5
sibling->flags |= FLAG_RED;
items[sibling->node.left].flags &= ~FLAG_RED;
int tmp = sibling->node.left;
rotateRight(siblingIdx);
// continue with case 6
siblingIdx = tmp;
sibling = items + siblingIdx;
redSR = true;//(sibling->node.right >= 0) && (items[sibling->node.right].flags & FLAG_RED);
}
if(redSR) { // case 6
// sibling takes the color of parent, parent becomes red, siblings child becomes black, rotate parent
int tmp = parent->flags & FLAG_RED;
sibling->flags &= ~FLAG_RED;
sibling->flags |= tmp;
parent->flags &= ~FLAG_RED;
items[sibling->node.right].flags &= ~FLAG_RED;
rotateLeft(parentIdx);
}
}
break;
}
}
}
}
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::removeNodeWithOneOrNoChild(int itemIdx)
{
Item *item = items + itemIdx;
int childIdx = item->node.left;
if(childIdx < 0) childIdx = item->node.right; // can also be -1
if(childIdx >= 0) { // has child
Item *child = items + childIdx;
if(item->flags & FLAG_RED || child->flags & FLAG_RED) {
// replace item with its child and paint it black
updateParent(itemIdx, childIdx);
// updateParent(childIdx, -1); // parent of child is the node to be removed, so modifying it is not necessary
// child->node.left = item->node.left; // NOTE: this is -1
// child->node.right = item->node.right; // NOTE: this is -1
child->node.parent = item->node.parent;
child->flags &= ~FLAG_RED;
} else { // both are black nodes - invalid tree
f_EPTF_RBT_error("EPTF_RBT::removeNodeWithOneOrNoChild: removing black (non-leaf) node with *single* black (non-leaf) child - tree was invalid!");
}
} else { // no child
if(item->flags & FLAG_RED) {
// simply remove the red node
updateParent(itemIdx, -1);
} else { // black node
fixRemove(itemIdx);
updateParent(itemIdx, -1); // unlink the node from its parent
}
}
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::removeNodeWithTwoChildren(int itemIdx)
{
static int lr = 0;
lr ^= 1;
int successorIdx;
if(lr) { // choose left/right alternating each call
successorIdx = items[itemIdx].node.left;
while(items[successorIdx].node.right >= 0) successorIdx = items[successorIdx].node.right;
} else {
successorIdx = items[itemIdx].node.right;
while(items[successorIdx].node.left >= 0) successorIdx = items[successorIdx].node.left;
}
// swap the two node, then delete the item (at its new position in tree - but same index!) with removeNodeWithOneOrNoChild
swapNodes(itemIdx, successorIdx);
removeNodeWithOneOrNoChild(itemIdx);
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::findSmallestFrom(int idx) const
{
while(items[idx].node.left >= 0) {
idx = items[idx].node.left;
}
return idx;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getNodeWithNextBiggerKey(int itemIdx) const
{
if(items[itemIdx].node.right >= 0) { // has right child -> find smallest from right child
return findSmallestFrom(items[itemIdx].node.right);
} else {
int p = items[itemIdx].node.parent;
for(;;) { // find next ancestor on the right, i.e. that has bigger key (if any)
if(p < 0) { return -1; }
if(items[p].node.left == itemIdx) return p;
itemIdx = p;
p = items[p].node.parent;
}
}
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::checkNode(int itemIdx, int parentIdx, int depth)
{
if(itemIdx < 0) { // leaf
if(black_depth < 0) {
black_depth = depth;
return true;
} else if(depth != black_depth) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: depth of black nodes is unbalanced.");
return false;
}
return true;
}
if((items[itemIdx].flags & FLAG_NODE) == 0) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: item is not node.");
return false;
}
if(items[itemIdx].node.parent < 0 && root != itemIdx) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: parent of item %d is "
"less than 0 (%d), but another item (%d) is root.",
itemIdx, items[itemIdx].node.parent, root);
return false;
}
if(itemIdx == root && items[itemIdx].node.parent >= 0) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: parent of root node (%d) is greater than 0 (%d)",
itemIdx, items[itemIdx].node.parent);
return false;
}
if(items[itemIdx].node.parent != parentIdx) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: parent reference of item %d is %d, shoud be %d.",
itemIdx, items[itemIdx].node.parent, parentIdx);
return false;
}
if(items[itemIdx].node.left >= 0 &&
// (items[items[itemIdx].node.left].key > items[itemIdx].key) ){
TKeyHelper::isGreater(items[items[itemIdx].node.left].key, items[itemIdx].key) ){
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: node's left child has greater key.");
return false;
}
if(items[itemIdx].node.right >= 0 &&
// (items[items[itemIdx].node.right].key < items[itemIdx].key) ){
TKeyHelper::isLower(items[items[itemIdx].node.right].key, items[itemIdx].key) ){
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: node's right child has smaller key.");
return false;
}
if(items[itemIdx].flags & FLAG_RED) { // red node, parent must be black (both children of every red node are black)
if(items[items[itemIdx].node.parent].flags & FLAG_RED) {
TTCN_Logger::log(TTCN_DEBUG, "f_EPTF_RBT_isTreeValid: red node has red parent.");
return false;
}
} else { // black node -> increment depth
depth++;
}
if(!checkNode(items[itemIdx].node.left, itemIdx, depth)) return false;
if(!checkNode(items[itemIdx].node.right, itemIdx, depth)) return false;
return true;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::countChainLength(int nodeIdx)
{
int len = 0;
Item *item = items + nodeIdx;
for(;;) {
if(item->flags & FLAG_NODE) {
if(item->node.fwd >= 0) {
len++;
item = items + item->node.fwd;
} else {
break;
}
} else {
if(item->clusterItem.fwd >= 0) {
len++;
item = items + item->clusterItem.fwd;
} else {
break;
}
}
}
return len;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::dumpNode(FILE *fp, int nodeIdx)
{
if((items[nodeIdx].flags & FLAG_NODE) == 0) return -1;
if(items[nodeIdx].node.parent >= 0) {
fprintf(fp, "node%d->node%d\n", nodeIdx, items[nodeIdx].node.parent);
}
if(items[nodeIdx].flags & FLAG_RED) {
fprintf(fp, "node%d [label=\"%d (", nodeIdx, nodeIdx);
TKeyHelper::dumpKey(fp, items[nodeIdx].key);
fprintf(fp, ")\", shape=box, color=red, style=filled, fontcolor=black]\n");
} else {
fprintf(fp, "node%d [label=\"%d (", nodeIdx, nodeIdx);
TKeyHelper::dumpKey(fp, items[nodeIdx].key);
fprintf(fp, ")\", shape=box, color=black, style=filled, fontcolor=white]\n");
}
if(items[nodeIdx].node.left >= 0) {
if(items[nodeIdx].node.left == nodeIdx) {
TTCN_Logger::log(TTCN_ERROR, "dump_tree_node: circular reference in node %d", nodeIdx);
fprintf(fp, "node%d->node%d [color=green]\n", nodeIdx, nodeIdx);
} else {
int thatNode = dumpNode(fp, items[nodeIdx].node.left);
if(thatNode < 0) {
fprintf(fp, "linvalid%d [label=\"invalid\", shape=box, color=purple, style=filled, fontcolor=black]\n", nodeIdx);
fprintf(fp, "node%d->linvalid%d [color=green]\n", nodeIdx, nodeIdx);
} else {
fprintf(fp, "node%d->node%d [color=green]\n", nodeIdx, thatNode);
}
}
} else {
fprintf(fp, "lnull%d [label=\"null\", shape = box, fontsize=6, color=gray, fontcolor=gray, height=0.1, width=0.1]\n", nodeIdx);
fprintf(fp, "node%d->lnull%d [color=green]\n", nodeIdx, nodeIdx);
}
int clusterLen = countChainLength(nodeIdx);
if(clusterLen > 0) {
fprintf(fp, "cluster%d [label=\"cluster (%d)\", shape=box, fontsize=6, color=blue, fontcolor=blue, height=0.1, width=0.1]\n",
nodeIdx, clusterLen);
fprintf(fp, "node%d->cluster%d\n", nodeIdx, nodeIdx);
}
if(items[nodeIdx].node.right >= 0) {
if(items[nodeIdx].node.right == nodeIdx) {
TTCN_Logger::log(TTCN_ERROR, "dump_tree_node: circular reference in node %d", nodeIdx);
fprintf(fp, "node%d->node%d [color=blue]\n", nodeIdx, nodeIdx);
} else {
int thatNode = dumpNode(fp, items[nodeIdx].node.right);
if(thatNode < 0) {
fprintf(fp, "rinvalid%d [label=\"invalid\", shape=box, color=purple, style=filled, fontcolor=black]\n", nodeIdx);
fprintf(fp, "node%d->rinvalid%d [color=blue]\n", nodeIdx, nodeIdx);
} else {
fprintf(fp, "node%d->node%d [color=blue]\n", nodeIdx, thatNode);
}
}
} else {
fprintf(fp, "rnull%d [label=\"null\", shape = box, fontsize=6, color=gray, fontcolor=gray, height=0.1, width=0.1]\n", nodeIdx);
fprintf(fp, "node%d->rnull%d [color=blue]\n", nodeIdx, nodeIdx);
}
return nodeIdx;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::allocItem()
{
int itemIdx;
if(itemAllocCount > itemCount) {
// if there are any unused allocated items, use them first
itemIdx = itemCount;
itemCount++;
} else if(freeHead >= 0) {
// otherwise use the head of the free chain
itemIdx = freeHead;
items[itemIdx].flags &= ~FLAG_FREE;
freeHead = items[itemIdx].freeItem.next; // can be -1 -> chain becomes empty
freeCount--;
} else {
// if the free chain is empty, allocate more items
int growby = EPTF_RBT_MINITEMGROWBY;
int bits = 0;
int tmp = itemAllocCount >> EPTF_RBT_GROWBYSHIFT;
while(tmp) {
bits++;
tmp>>=1;
}
tmp = 1<<bits;
if(tmp > growby) growby = tmp;
// printf("itemAllocCount = %d\n",itemAllocCount);
// printf("growby = %d\n", growby);
itemAllocCount += growby;
items = (Item*) Realloc(items, itemAllocCount*sizeof(Item));
itemIdx = itemCount;
itemCount++;
}
return itemIdx;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::insertItem(TKey key)
{
int itemIdx = allocItem();
#ifdef EPTF_RBT_DEBUG
if(maxItemCount >= 0 && increaseRate >= 0 && itemCount > maxItemCount)
{
TTCN_warning("RBT: Tree: %s has exceeded the maximum item count: %d! New maxItemCount is %d.", getName(), maxItemCount, (int) (maxItemCount*(1+increaseRate)) );
maxItemCount = (int) maxItemCount*(1+increaseRate);
}
#endif
// after this, start a tree insert, if that finds a node with the same key, chain it at the end of that chain,
// otherwise insert as node and update the tree (set FLAG_NODE!)
bool treeWasEmpty = root < 0;
insertItemHelper(itemIdx, key);
if( treeWasEmpty ||
((smallestKeyIndex >= 0) &&
(items[itemIdx].flags&FLAG_NODE) &&
// (items[smallestKeyIndex].key > key))) {
TKeyHelper::isGreater(items[smallestKeyIndex].key, key))) {
smallestKeyIndex = itemIdx;
}
return itemIdx;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::insertItem(TKey key, bool isRed, int parentItemIdx) // only for testing!!!
{
int itemIdx = allocItem();
Item *item = items + itemIdx;
item->flags = FLAG_NODE;
item->key = TKeyHelper::clone(key);
item->node.left = -1;
item->node.right = -1;
item->node.parent = parentItemIdx;
item->node.fwd = -1;
item->node.endOfCluster = itemIdx;
if(parentItemIdx < 0) {
root = itemIdx;
smallestKeyIndex = itemIdx;
if(isRed) {
TTCN_Logger::log(TTCN_WARNING, "insertItem: root node cannot be red, iserting as black");
}
} else {
if(isRed) {
item->flags |= FLAG_RED;
}
Item *parent = items + parentItemIdx;
int cmp_res = TKeyHelper::compare(item->key, parent->key);
if(cmp_res < 0) {
parent->node.left = itemIdx;
} else if(cmp_res > 0) {
parent->node.right = itemIdx;
} else {
f_EPTF_RBT_error("insertItem: key of child node must not equal key of node");
}
if(TKeyHelper::isLower(item->key, items[smallestKeyIndex].key)) {
smallestKeyIndex = itemIdx;
}
}
return itemIdx;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::removeItemFromTree(int itemIdx)
{
Item *item = items + itemIdx;
if(item->flags & FLAG_NODE) {
if(item->node.fwd >= 0) {
// update end of cluster's startOfCluster to point at the new node, i.e. node.fwd
Item *end = items + item->node.endOfCluster;
end->clusterItem.startOfCluster = item->node.fwd;
if(itemIdx == smallestKeyIndex) {
smallestKeyIndex = item->node.fwd;
}
// set parent to point to next chain item
updateParent(itemIdx, item->node.fwd);
// change the next item to a node
Item *next = items + item->node.fwd;
int tmp = next->clusterItem.fwd;
next->flags = item->flags;
next->node.left = item->node.left;
next->node.right = item->node.right;
next->node.parent = item->node.parent;
next->node.fwd = tmp;
#ifdef EPTF_RBT_DEBUG
if(item->node.endOfCluster == itemIdx) { // this cannot happen, as this would mean empty chain, but item.node.fwd >= 0
f_EPTF_RBT_error("EPTF_RBT::removeItemFromTree: item->node.endOfCluster == itemIdx, but item->node.fwd >= 0");
} else {
#endif
next->node.endOfCluster = item->node.endOfCluster;
#ifdef EPTF_RBT_DEBUG
}
#endif
if(next->node.left>=0) {
items[next->node.left].node.parent = item->node.fwd;
}
if(next->node.right>=0) {
items[next->node.right].node.parent = item->node.fwd;
}
} else {
// otherwise remove node from tree and update tree
if(itemIdx == smallestKeyIndex) {
// note: smallestKeyIndex must be updated before removing item, because of tree rotations!
if(item->node.left >= 0) {
f_EPTF_RBT_error("EPTF_RBT::removeItemFromTree: item %d is smallest but has left child", itemIdx);
}
smallestKeyIndex = getNodeWithNextBiggerKey(smallestKeyIndex);
}
if(item->node.left == -1 || item->node.right == -1) {
removeNodeWithOneOrNoChild(itemIdx);
} else {
removeNodeWithTwoChildren(itemIdx);
}
}
} else {
// unchain item
#ifdef EPTF_RBT_DEBUG
if(itemIdx == smallestKeyIndex) { // this cannot happen, the smallest index should always point to a node
f_EPTF_RBT_error("EPTF_RBT::removeItemFromTree: smallestKeyIndex points to cluster element");
}
#endif
// bwd should never be <0, because that would be the chain head, i.e. the node item itself
Item *prev = items + item->clusterItem.bwd;
if(item->clusterItem.fwd < 0) { // item is end of chain
Item *node = items + item->clusterItem.startOfCluster; // startOfCluster is valid (may not be the case for intermediate items !!!!)
node->node.endOfCluster = item->clusterItem.bwd;
}
if(prev->flags & FLAG_NODE) {
prev->node.fwd = item->clusterItem.fwd;
} else {
if(item->clusterItem.fwd < 0) { // item is end of chain -> update prev's startOfCluster to point to the node
prev->clusterItem.startOfCluster = item->clusterItem.startOfCluster;
}
prev->clusterItem.fwd = item->clusterItem.fwd;
}
if(item->clusterItem.fwd >= 0) {
Item *next = items + item->clusterItem.fwd;
next->clusterItem.bwd = item->clusterItem.bwd;
}
}
item->flags = FLAG_INVALID;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::putItemInFreeChain(int itemIdx)
{
// put item in free chain - item MUST be removed from the tree previously!
Item *item = items + itemIdx;
TKeyHelper::dealloc(item->key);
item->flags = FLAG_FREE;
item->freeItem.next = freeHead;
freeHead = itemIdx;
freeCount++;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getSmallest()
{
/* if(smallestKeyIndex < 0) {
if(root < 0) { // empty tree
return -1;
}
// update smallestKeyIndex (actually, smallestKeyIndex is maintained in a way that this should never be performed)
smallestKeyIndex = findSmallestFrom(root);
}*/ // Note: if smallestKeyIndex < 0 the tree is empty
return smallestKeyIndex;
}
template <class TKey, class TKeyHelper>
TKey EPTF_RBT<TKey,TKeyHelper>::getKey(int itemIdx)
{
return items[itemIdx].key;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::findByKey(TKey key)
{
for(int i = root; i >= 0; ) {
int cmp_res = TKeyHelper::compare(key, items[i].key);
// if(key < items[i].key) {
// if(TKeyHelper::isLower(key, items[i].key)) {
if(cmp_res < 0) { // key < items[i].key
i = items[i].node.left;
// } else if(key > items[i].key) {
// } else if(TKeyHelper::isGreater(key, items[i].key)) {
} else if(cmp_res > 0) { // key > items[i].key
i = items[i].node.right;
} else {
return i;
}
}
return -1;
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getLeft(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) { return items[itemIdx].node.left; }
else { return -1; }
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getRight(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) { return items[itemIdx].node.right; }
else { return -1; }
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getParent(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) { return items[itemIdx].node.parent; }
else { return -1; }
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getNextInChain(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) { return items[itemIdx].node.fwd; }
else { return items[itemIdx].clusterItem.fwd; }
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::getPrevInChain(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) { return -1; }
else { return items[itemIdx].clusterItem.bwd; }
}
template <class TKey, class TKeyHelper>
int EPTF_RBT<TKey,TKeyHelper>::iterateIncremental(int itemIdx) const
{
if(items[itemIdx].flags & FLAG_NODE) {
if(items[itemIdx].node.fwd >= 0) return items[itemIdx].node.fwd;
return getNodeWithNextBiggerKey(itemIdx);
} else {
if(items[itemIdx].clusterItem.fwd >= 0) return items[itemIdx].clusterItem.fwd;
return getNodeWithNextBiggerKey(items[itemIdx].clusterItem.startOfCluster);
}
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::sortIncremental(EPTF__RBT__ItemIdxList &items)
{
int count = getTreeItemCount();
int idx = getSmallest();
items.set_size(count);
for(int i=0; i<count; i++) {
if(idx < 0) {
TTCN_Logger::begin_event(TTCN_ERROR);
TTCN_Logger::log_event("ERROR: sortIncremental: item count = %d, sorted items = ", count);
items.log();
TTCN_Logger::end_event();
f_EPTF_RBT_error("f_EPTF_RBT_sortIncremental: found less items than expected.");
}
items[i] = idx;
idx = iterateIncremental(idx);
}
if(idx >= 0) {
// dumpToPng("faulty_tree");
TTCN_Logger::begin_event(TTCN_ERROR);
TTCN_Logger::log_event("ERROR: sortIncremental: item count = %d, extra item found at index %d, sorted items = ", count, idx);
items.log();
TTCN_Logger::end_event();
f_EPTF_RBT_error("f_EPTF_RBT_sortIncremental: found more items than expected.");
}
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::isTreeValid()
{
if(root < 0) { return true; } // empty tree
if(items[root].flags & FLAG_RED) {
TTCN_Logger::log(TTCN_DEBUG, "EPTF_RBT::isTreeValid: root node is red.");
return false;
}
black_depth = -1;
bool ret = checkNode(root, -1, 0);
// if(ret) TTCN_Logger::log(TTCN_DEBUG, "EPTF_RBT::isTreeValid: tree is valid.");
if(root < 0) {
if(smallestKeyIndex >= 0) {
TTCN_Logger::log(TTCN_DEBUG, "EPTF_RBT::isTreeValid: smallest item index is set but the tree is empty.");
return false;
}
} else {
if(smallestKeyIndex != findSmallestFrom(root)) {
TTCN_Logger::log(TTCN_DEBUG, "EPTF_RBT::isTreeValid: smallest item index cache is invalid. Cached: %d, actual smallest item: %d.",
smallestKeyIndex, findSmallestFrom(root));
return false;
}
// check if it's realy a binary search tree
EPTF__RBT__ItemIdxList order;
sortIncremental(order);
TKey key = items[(int)order[0]].key;
for(int i=1; i<order.lengthof(); i++) {
TKey nextKey = items[(int)order[i]].key;
if(TKeyHelper::isLower(nextKey, key)) {
TTCN_Logger::log(TTCN_DEBUG, "EPTF_RBT::isTreeValid: incorrect order of sorted items, tree is not a binary search tree");
return false;
}
key = nextKey;
}
}
return ret;
}
template <class TKey, class TKeyHelper>
void EPTF_RBT<TKey,TKeyHelper>::dumpToPng(const char *name)
{
char *fn_dot = new char[strlen(name) + 5];
strcpy(fn_dot, name);
strcat(fn_dot, ".dot");
FILE *fp = fopen(fn_dot, "w");
if(!fp) {
TTCN_warning("could not open file %s for writing", fn_dot);
delete []fn_dot;
return;
}
char *fn_png = new char[strlen(name) + 5];
strcpy(fn_png, name);
strcat(fn_png, ".png");
fprintf(fp, "digraph %s {\n", name);
fprintf(fp, "rankdir=TB;\n"); // top to buttom layout, other options: BT, LR, RL
if(items == NULL || root < 0) {
fprintf(fp, "smallest [shape=box, label=\"smallest: %d\"]\n", smallestKeyIndex);
fprintf(fp, "empty [shape=box]\n");
} else {
fprintf(fp, "smallest [shape=box, label=\"smallest: %d (", smallestKeyIndex);
TKeyHelper::dumpKey(fp, items[smallestKeyIndex].key);
fprintf(fp, ")\"]\n");
dumpNode(fp, root);
}
fprintf(fp, "}\n");
fclose(fp);
const char cmd[]="dot -Tpng %s > %s";
char *tmp = new char[strlen(cmd) + strlen(fn_dot) + strlen(fn_png) + 1];
sprintf(tmp, cmd, fn_dot, fn_png);
if(-1 == system(tmp)) {
TTCN_warning("EPTF_RBT::dumpToPng: system call `%s` failed.", tmp);
}
delete []fn_dot;
delete []fn_png;
delete []tmp;
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::isItemNode(int itemIdx) const
{
return items[itemIdx].flags & FLAG_NODE;
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::isItemRed(int itemIdx) const
{
return items[itemIdx].flags & FLAG_RED;
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::isItemFree(int itemIdx) const
{
return items[itemIdx].flags & FLAG_FREE;
}
template <class TKey, class TKeyHelper>
bool EPTF_RBT<TKey,TKeyHelper>::isItemInvalid(int itemIdx) const
{
return items[itemIdx].flags & FLAG_INVALID;
}
///////////////////////////////////////////////////////////////////////////////
// implementation of TTCN-3 external functions
///////////////////////////////////////////////////////////////////////////////
static EPTF_RBT_Base **rbtree_list;
static int rbtree_count;
// Note: rbtree_deletedList works like a stack, i.e. the last deleted item will be reused the next time a tree is created
static int *rbtree_deletedList = NULL;
static int rbtree_deletedCount = 0;
static int rbtree_deletedAllocCount = 0;
void f_EPTF_RBT_pushDeletedTree(int queueId)
{
if(rbtree_deletedList == NULL) {
rbtree_deletedAllocCount = EPTF_RBT_MINITEMGROWBY;
rbtree_deletedList = (int*) Malloc(sizeof(int) * rbtree_deletedAllocCount);
} else if(rbtree_deletedCount+1 >= rbtree_deletedAllocCount) {
rbtree_deletedAllocCount += EPTF_RBT_MINITEMGROWBY;
rbtree_deletedList = (int*) Realloc(rbtree_deletedList,
sizeof(int) * rbtree_deletedAllocCount);
}
rbtree_deletedList[rbtree_deletedCount] = queueId;
rbtree_deletedCount++;
}
int f_EPTF_RBT_popDeletedTree() // returns -1 if none
{
int ret_val = -1;
if(rbtree_deletedCount > 0) {
rbtree_deletedCount--;
ret_val = rbtree_deletedList[rbtree_deletedCount];
}
return ret_val;
}
inline void f_EPTF_RBT_checkTreeId(const char *fn, int treeId)
{
if(treeId<0 || treeId>=rbtree_count) {
f_EPTF_RBT_error("%s: invalid tree %d, number of trees: %d", fn, treeId, rbtree_count);
}
if(rbtree_list[treeId] == NULL) {
f_EPTF_RBT_error("%s: invalid tree %d, tree has been deleted.", fn, treeId);
}
}
inline void f_EPTF_RBT_checkTreeType(const char *fn, int treeId, EPTF_RBT_KeyType keyType)
{
if(rbtree_list[treeId]->getKeyType() != keyType) {
if(rbtree_list[treeId]->getName() != NULL) {
f_EPTF_RBT_error("%s: invalid tree type, tree \"%s\" is %s tree", fn, rbtree_list[treeId]->getName(), EPTF_RBT_KeyTypeNames[rbtree_list[treeId]->getKeyType()]);
} else {
f_EPTF_RBT_error("%s: invalid tree type, tree is %s tree", fn, EPTF_RBT_KeyTypeNames[rbtree_list[treeId]->getKeyType()]);
}
}
}
inline void f_EPTF_RBT_checkItemIdx(const char *fn, int treeId, int itemIdx, bool checkFree=true, bool checkInvalid=true)
{
if(itemIdx<0 ||
itemIdx>=rbtree_list[treeId]->getItemCount()) {
if(rbtree_list[treeId]->getName() != NULL) {
f_EPTF_RBT_error("%s: invalid item %d, number of items in tree \"%s\": %d",
fn, itemIdx, rbtree_list[treeId]->getName(), rbtree_list[treeId]->getItemCount());
} else {
f_EPTF_RBT_error("%s: invalid item %d, number of items in tree: %d",
fn, itemIdx, rbtree_list[treeId]->getItemCount());
}
}
if(checkFree && rbtree_list[treeId]->isItemFree(itemIdx)) {
if(rbtree_list[treeId]->getName() != NULL) {
f_EPTF_RBT_error("%s: item %d in tree \"%s\" is in the free chain", fn, itemIdx, rbtree_list[treeId]->getName());
} else {
f_EPTF_RBT_error("%s: item %d is in the free chain", fn, itemIdx);
}
}
if(checkInvalid && rbtree_list[treeId]->isItemInvalid(itemIdx)) {
if(rbtree_list[treeId]->getName() != NULL) {
f_EPTF_RBT_error("%s: item %d in tree \"%s\" is invalid", fn, itemIdx, rbtree_list[treeId]->getName());
} else {
f_EPTF_RBT_error("%s: item %d is invalid", fn, itemIdx);
}
}
}
void f__EPTF__RBT__init()
{
rbtree_list = NULL;
rbtree_count = 0;
rbtree_deletedList = NULL;
rbtree_deletedCount = 0;
rbtree_deletedAllocCount = 0;
}
void f__EPTF__RBT__cleanup()
{
if(rbtree_list) {
for(int i=0; i<rbtree_count; i++) {
if(rbtree_list[i]) {
delete rbtree_list[i];
}
}
Free(rbtree_list);
}
rbtree_list = NULL;
rbtree_count = 0;
if(rbtree_deletedList) {
Free(rbtree_deletedList);
}
rbtree_deletedList = NULL;
rbtree_deletedCount = 0;
rbtree_deletedAllocCount = 0;
}
class IntKeyHelper
{
public:
static void dumpKey(FILE *fp, int k) { fprintf(fp, "%d", k); }
static bool isLower(int k1, int k2) { return k1 < k2; }
static bool isGreater(int k1, int k2) { return k1 > k2; }
inline static int compare(int k1, int k2) { // <0 -> k1<k2, ==0 -> k1==k2, >0 -> k1>k2
return k1 - k2;
}
static int clone(int src) { return src; }
static void dealloc(int &pKey) { }
};
class FloatKeyHelper
{
public:
static void dumpKey(FILE *fp, double k) { fprintf(fp, "%.6f", k); }
// static bool isLower(double k1, double k2) { return k1 < k2; }
// static bool isGreater(double k1, double k2) { return k1 > k2; }
static bool isLower(double k1, double k2) { return isless(k1, k2); }
static bool isGreater(double k1, double k2) { return isgreater(k1, k2); }
inline static int compare(double k1, double k2) { // <0 -> k1<k2, ==0 -> k1==k2, >0 -> k1>k2
if(isgreater(k1,k2))return 1;
if(isless(k1,k2))return -1;
return 0;
}
static double clone(double src) { return src; }
static void dealloc(double &pKey) { }
};
// Note: this mess is needed to keep the float version simple while still supporting charstring keys
class CharstringKeyHelper
{
public:
#ifdef EPTF_RBT_DEBUG
static unsigned long m_new;
static unsigned long m_del;
~CharstringKeyHelper() {
if(m_new != m_del) {
printf("CharstringKeyHelper: memory leak detected.\nNew calls: %lu, delete calls: %lu\n", m_new, m_del);
}
}
#endif
static void dumpKey(FILE *fp, const char *k) { fprintf(fp, "%s", k); }
static bool isLower(const char * k1, const char * k2) { return strcmp(k1, k2) < 0; }
static bool isGreater(const char * k1, const char * k2) { return strcmp(k1, k2) > 0; }
inline static int compare(const char * k1, const char * k2) { // <0 -> k1<k2, ==0 -> k1==k2, >0 -> k1>k2
return strcmp(k1, k2);
}
static const char* clone(const char* src) {
#ifdef EPTF_RBT_DEBUG
m_new++;
#endif
size_t len = strlen(src);
char *ret = new char[len+1];
memcpy(ret, src, len);
ret[len] = 0;
return ret;
}
static void dealloc(const char* &pKey) {
if(pKey) {
#ifdef EPTF_RBT_DEBUG
m_del++;
#endif
delete []pKey;
pKey = NULL;
}
}
};
#ifdef EPTF_RBT_DEBUG
unsigned long CharstringKeyHelper::m_new = 0;
unsigned long CharstringKeyHelper::m_del = 0;
CharstringKeyHelper cs_rbt_checkmemleak;
#endif
int f_EPTF_RBT_create()
{
int treeId = f_EPTF_RBT_popDeletedTree();
if(treeId < 0) {
treeId = rbtree_count;
rbtree_count++;
if(rbtree_list == NULL) rbtree_list = (EPTF_RBT_Base**) Malloc(sizeof(EPTF_RBT_Base*));
else rbtree_list = (EPTF_RBT_Base**) Realloc(rbtree_list, rbtree_count * sizeof(EPTF_RBT_Base*));
}
return treeId;
}
EPTF__RBT__TreeId f__EPTF__RBT__createIntTree(const CHARSTRING &pl__name)
{
int treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<int,IntKeyHelper>(K_int, pl__name);
return EPTF__RBT__TreeId(treeId);
}
EPTF__RBT__TreeId f__EPTF__RBT__createFloatTree(const CHARSTRING &pl__name)
{
int treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<double,FloatKeyHelper>(K_double, pl__name);
return EPTF__RBT__TreeId(treeId);
}
EPTF__RBT__TreeId f__EPTF__RBT__createCharstringTree(const CHARSTRING &pl__name)
{
int treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<const char *,CharstringKeyHelper>(K_charstring, pl__name);
return EPTF__RBT__TreeId(treeId);
}
void insertItem(int treeId, int parentItemIdx, const EPTF__RBT__TreeInitNode &node)
{
switch(node.key().get_selection()) {
case EPTF__RBT__Key::ALT_intKey: {
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_createAndInitTree", treeId, K_int);
EPTF_RBT<int,IntKeyHelper> *tree = (EPTF_RBT<int,IntKeyHelper> *)rbtree_list[treeId];
int itemIdx = tree->insertItem((int)node.key().intKey(), (bool)((boolean)node.isRed()),parentItemIdx);
if(node.leftChild().ispresent()) {
if(node.leftChild()().key().intKey() >= node.key().intKey()) {
f_EPTF_RBT_error("insertItem: key of left child node must be less than key of node");
}
insertItem(treeId, itemIdx, node.leftChild()());
}
if(node.rightChild().ispresent()) {
if(node.rightChild()().key().intKey() <= node.key().intKey()) {
f_EPTF_RBT_error("insertItem: key of right child node must be greater than key of node");
}
insertItem(treeId, itemIdx, node.rightChild()());
}
break;
}
case EPTF__RBT__Key::ALT_floatKey: {
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_createAndInitTree", treeId, K_double);
EPTF_RBT<double,FloatKeyHelper> *tree = (EPTF_RBT<double,FloatKeyHelper> *)rbtree_list[treeId];
int itemIdx = tree->insertItem((double)node.key().floatKey(), (bool)((boolean)node.isRed()),parentItemIdx);
if(node.leftChild().ispresent()) {
if(node.leftChild()().key().floatKey() >= node.key().floatKey()) {
f_EPTF_RBT_error("insertItem: key of left child node must be less than key of node");
}
insertItem(treeId, itemIdx, node.leftChild()());
}
if(node.rightChild().ispresent()) {
if(node.rightChild()().key().floatKey() <= node.key().floatKey()) {
f_EPTF_RBT_error("insertItem: key of right child node must be greater than key of node");
}
insertItem(treeId, itemIdx, node.rightChild()());
}
break;
}
case EPTF__RBT__Key::ALT_stringKey: {
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_createAndInitTree", treeId, K_charstring);
EPTF_RBT<const char *,CharstringKeyHelper> *tree = (EPTF_RBT<const char *,CharstringKeyHelper> *)rbtree_list[treeId];
int itemIdx = tree->insertItem((const char*)node.key().stringKey(), (bool)((boolean)node.isRed()),parentItemIdx);
if(node.leftChild().ispresent()) {
if(strcmp((const char*)node.leftChild()().key().stringKey(), (const char*)node.key().stringKey()) >= 0) {
f_EPTF_RBT_error("insertItem: key of left child node must be less than key of node");
}
insertItem(treeId, itemIdx, node.leftChild()());
}
if(node.rightChild().ispresent()) {
if(strcmp((const char*)node.rightChild()().key().stringKey(), (const char*)node.key().stringKey()) <= 0) {
f_EPTF_RBT_error("insertItem: key of right child node must be greater than key of node");
}
insertItem(treeId, itemIdx, node.rightChild()());
}
break;
}
default :
f_EPTF_RBT_error("insertItem: unsupported key type");
break;
}
}
// for testing
EPTF__RBT__TreeId f__EPTF__RBT__createAndInitTree(const CHARSTRING &pl__name, const EPTF__RBT__TreeInitNode &pl__rootNode)
{
int treeId = -1;
switch(pl__rootNode.key().get_selection()) {
case EPTF__RBT__Key::ALT_intKey:
treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<int,IntKeyHelper>(K_int, pl__name);
break;
case EPTF__RBT__Key::ALT_floatKey:
treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<double,FloatKeyHelper>(K_double, pl__name);
break;
case EPTF__RBT__Key::ALT_stringKey:
treeId = f_EPTF_RBT_create();
rbtree_list[treeId] = new EPTF_RBT<const char *,CharstringKeyHelper>(K_charstring, pl__name);
break;
default :
return EPTF__RBT__TreeId(-1);
break;
}
insertItem(treeId, -1, pl__rootNode);
if(! rbtree_list[treeId]->isTreeValid()) {
TTCN_Logger::begin_event(TTCN_WARNING);
TTCN_Logger::log_event_str("f_EPTF_RBT_createAndInitTree: invalid tree: ");
pl__rootNode.log();
TTCN_Logger::end_event();
TTCN_Logger::log(TTCN_WARNING, "f_EPTF_RBT_createAndInitTree: dumping tree as f_EPTF_RBT_createAndInitTree.png");
rbtree_list[treeId]->dumpToPng("f_EPTF_RBT_createAndInitTree");
delete rbtree_list[treeId];
rbtree_list[treeId] = NULL; // prevent cleanup from deleting it again;
f_EPTF_RBT_pushDeletedTree(treeId);
}
return EPTF__RBT__TreeId(treeId);
}
void f__EPTF__RBT__deleteTree(const EPTF__RBT__TreeId &pl__tree)
{
int treeId = (int)pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_deleteTree", treeId);
delete rbtree_list[treeId];
rbtree_list[treeId] = NULL; // prevent cleanup from deleting it again;
f_EPTF_RBT_pushDeletedTree(treeId);
}
CHARSTRING f__EPTF__RBT__getName(const EPTF__RBT__TreeId &pl__tree)
{
int treeId = (int)pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getName", treeId);
return rbtree_list[treeId]->getName();
}
INTEGER f__EPTF__RBT__getItemCount(const EPTF__RBT__TreeId &pl__tree)
{
int treeId = (int)pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getItemCount", treeId);
return rbtree_list[treeId]->getTreeItemCount();
}
EPTF__RBT__ItemIdx f__EPTF__RBT__insertIntItem(
const EPTF__RBT__TreeId &pl__tree,
const INTEGER &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_insertIntItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_insertIntItem", treeId, K_int);
EPTF_RBT<int,IntKeyHelper> *tree = (EPTF_RBT<int,IntKeyHelper> *)rbtree_list[treeId];
return EPTF__RBT__ItemIdx(tree->insertItem((int)pl__key));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__insertFloatItem(
const EPTF__RBT__TreeId &pl__tree,
const FLOAT &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_insertFloatItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_insertFloatItem", treeId, K_double);
EPTF_RBT<double,FloatKeyHelper> *tree = (EPTF_RBT<double,FloatKeyHelper> *)rbtree_list[treeId];
return EPTF__RBT__ItemIdx(tree->insertItem((double)pl__key));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__insertCharstringItem(
const EPTF__RBT__TreeId &pl__tree,
const CHARSTRING &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_insertCharstringtItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_insertCharstringItem", treeId, K_charstring);
EPTF_RBT<const char *,CharstringKeyHelper> *tree = (EPTF_RBT<const char *,CharstringKeyHelper> *)rbtree_list[treeId];
return EPTF__RBT__ItemIdx(tree->insertItem((const char *)pl__key));
}
void f__EPTF__RBT__removeItem(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_removeItem", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_removeItem", treeId, itemIdx);
rbtree_list[treeId]->removeItemFromTree(itemIdx);
rbtree_list[treeId]->putItemInFreeChain(itemIdx);
}
void f__EPTF__RBT__removeItemWithoutFree(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_removeItemWithoutFree", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_removeItemWithoutFree", treeId, itemIdx);
rbtree_list[treeId]->removeItemFromTree(itemIdx);
}
void f__EPTF__RBT__freeInvalidItem(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_freeInvalidItem", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_freeInvalidItem", treeId, itemIdx, true, false);
if(rbtree_list[treeId]->isItemInvalid(itemIdx)) {
rbtree_list[treeId]->putItemInFreeChain(itemIdx);
} else {
if(rbtree_list[treeId]->getName() != NULL) {
f_EPTF_RBT_error("f_EPTF_RBT_freeInvalidItem: item must be removed from tree \"%s\" first using f_EPTF_RBT_removeItemWithoutFree!", rbtree_list[treeId]->getName());
} else {
f_EPTF_RBT_error("f_EPTF_RBT_freeInvalidItem: item must be removed from tree first using f_EPTF_RBT_removeItemWithoutFree!");
}
}
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getItemWithSmallestKey(
const EPTF__RBT__TreeId &pl__tree)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getItemWithSmallestKey", treeId);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getSmallest());
}
INTEGER f__EPTF__RBT__getKeyOfIntItem(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getKeyOfIntItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_getKeyOfIntItem", treeId, K_int);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getKeyOfIntItem", treeId, itemIdx);
EPTF_RBT<int,IntKeyHelper> *tree = (EPTF_RBT<int,IntKeyHelper> *)rbtree_list[treeId];
return INTEGER(tree->getKey(itemIdx));
}
FLOAT f__EPTF__RBT__getKeyOfFloatItem(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getKeyOfFloatItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_getKeyOfFloatItem", treeId, K_double);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getKeyOfFloatItem", treeId, itemIdx);
EPTF_RBT<double,FloatKeyHelper> *tree = (EPTF_RBT<double,FloatKeyHelper> *)rbtree_list[treeId];
return FLOAT(tree->getKey(itemIdx));
}
CHARSTRING f__EPTF__RBT__getKeyOfCharstringItem(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getKeyOfCharstringItem", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_getKeyOfCharstringItem", treeId, K_charstring);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getKeyOfCharstringItem", treeId, itemIdx);
EPTF_RBT<const char *,CharstringKeyHelper> *tree = (EPTF_RBT<const char *,CharstringKeyHelper> *)rbtree_list[treeId];
return CHARSTRING(tree->getKey(itemIdx));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__findFirstItemByIntKey(
const EPTF__RBT__TreeId &pl__tree,
const INTEGER &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_findFirstItemByIntKey", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_findFirstItemByIntKey", treeId, K_int);
EPTF_RBT<int,IntKeyHelper> *tree = (EPTF_RBT<int,IntKeyHelper> *)rbtree_list[treeId];
return INTEGER(tree->findByKey((int)pl__key));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__findFirstItemByFloatKey(
const EPTF__RBT__TreeId &pl__tree,
const FLOAT &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_findFirstItemByFloatKey", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_findFirstItemByFloatKey", treeId, K_double);
EPTF_RBT<double,FloatKeyHelper> *tree = (EPTF_RBT<double,FloatKeyHelper> *)rbtree_list[treeId];
return INTEGER(tree->findByKey((double)pl__key));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__findFirstItemByCharstringKey(
const EPTF__RBT__TreeId &pl__tree,
const CHARSTRING &pl__key)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_findFirstItemByCharstringKey", treeId);
f_EPTF_RBT_checkTreeType("f_EPTF_RBT_findFirstItemByCharstringKey", treeId, K_charstring);
EPTF_RBT<const char *,CharstringKeyHelper> *tree = (EPTF_RBT<const char *,CharstringKeyHelper> *)rbtree_list[treeId];
return INTEGER(tree->findByKey((const char *)pl__key));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getRoot(
const EPTF__RBT__TreeId &pl__tree)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getRoot", treeId);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getRoot());
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getLeft(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getLeft", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getLeft", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getLeft(itemIdx));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getRight(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getRight", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getRight", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getRight(itemIdx));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getParent(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getParent", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getParent", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getParent(itemIdx));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getNextInChain(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getNextInChain", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getNextInChain", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getNextInChain(itemIdx));
}
EPTF__RBT__ItemIdx f__EPTF__RBT__getPrevInChain(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getPrevInChain", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getPrevInChain", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->getPrevInChain(itemIdx));
}
// gets either the next element in chain or (if none) the first element with the next bigger key
EPTF__RBT__ItemIdx f__EPTF__RBT__iterateIncremental(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_iterateIncremental", treeId);
int itemIdx = pl__item;
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_iterateIncremental", treeId, itemIdx);
return EPTF__RBT__ItemIdx(rbtree_list[treeId]->iterateIncremental(itemIdx));
}
void f__EPTF__RBT__sortIncremental(
const EPTF__RBT__TreeId &pl__tree,
EPTF__RBT__ItemIdxList &pl__itemsSorted)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_sortIcremental", treeId);
rbtree_list[treeId]->sortIncremental(pl__itemsSorted);
}
BOOLEAN f__EPTF__RBT__isItemValid(
const EPTF__RBT__TreeId &pl__tree,
const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
int itemIdx = pl__item;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_isItemValid", treeId);
if(itemIdx<0 ||
itemIdx>=rbtree_list[treeId]->getItemCount()) {
return BOOLEAN(FALSE);
}
if(rbtree_list[treeId]->isItemFree(itemIdx)) {
return BOOLEAN(FALSE);
}
if(rbtree_list[treeId]->isItemInvalid(itemIdx)) {
return BOOLEAN(FALSE);
}
return BOOLEAN(TRUE);
}
BOOLEAN f__EPTF__RBT__isTreeValid(const INTEGER &pl__tree)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_isTreeValid", treeId);
return BOOLEAN(rbtree_list[treeId]->isTreeValid());
}
EPTF__RBT__ItemType f__EPTF__RBT__getItemType(const EPTF__RBT__TreeId &pl__tree, const EPTF__RBT__ItemIdx &pl__item)
{
int treeId = pl__tree;
int itemIdx = pl__item;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_getItemType", treeId);
f_EPTF_RBT_checkItemIdx("f_EPTF_RBT_getItemType", treeId, itemIdx, false, true);
if(rbtree_list[treeId]->isItemFree(itemIdx)) {
return EPTF__RBT__ItemType(EPTF__RBT__ItemType::FreeItem);
} else if(rbtree_list[treeId]->isItemNode(itemIdx)) {
if(rbtree_list[treeId]->isItemRed(itemIdx)) {
return EPTF__RBT__ItemType(EPTF__RBT__ItemType::RedNode);
} else {
return EPTF__RBT__ItemType(EPTF__RBT__ItemType::BlackNode);
}
} else {
return EPTF__RBT__ItemType(EPTF__RBT__ItemType::ChainItem);
}
}
void f__EPTF__RBT__cloneTree(const INTEGER &pl__src, const INTEGER &pl__dst)
{
int src = (int)pl__src;
int dst = (int)pl__dst;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_cloneTree", src);
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_cloneTree", dst);
delete rbtree_list[dst];
switch(rbtree_list[src]->getKeyType()) {
case K_int:
rbtree_list[dst] = new EPTF_RBT<int,IntKeyHelper>(*((EPTF_RBT<int,IntKeyHelper>*)rbtree_list[src]));
break;
case K_double:
rbtree_list[dst] = new EPTF_RBT<double,FloatKeyHelper>(*((EPTF_RBT<double,FloatKeyHelper>*)rbtree_list[src]));
break;
case K_charstring:
rbtree_list[dst] = new EPTF_RBT<const char *,CharstringKeyHelper>(*((EPTF_RBT<const char *,CharstringKeyHelper>*)rbtree_list[src]));
break;
default:
f_EPTF_RBT_error("f_EPTF_RBT_cloneTree: unhandled key type");
}
}
void f__EPTF__RBT__dumpToPng(
const EPTF__RBT__TreeId &pl__tree,
const CHARSTRING &pl__name)
{
int treeId = pl__tree;
f_EPTF_RBT_checkTreeId("f_EPTF_RBT_dumpToPng", treeId);
rbtree_list[treeId]->dumpToPng(pl__name);
}
} // namespace EPTF__CLL__RBT__Functions