/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.foundation; /** * @exclude */ public abstract class Tree<T> implements ShallowClone , DeepClone, Visitable <T> { public Tree<T> _preceding; public int _size = 1; public Tree<T> _subsequent; public static final <T,V extends Tree<T>> V add(V oldTree, V newTree){ if(oldTree == null){ return newTree; } return (V)oldTree.add(newTree); } public final <V extends Tree<T>> V add(final V newNode){ return add(newNode, compare(newNode)); } /** * On adding a node to a tree, if it already exists, and if * Tree#duplicates() returns false, #isDuplicateOf() will be * called. The added node can then be asked for the node that * prevails in the tree using #duplicateOrThis(). This mechanism * allows doing find() and add() in one run. */ public <V extends Tree<T>> V add(final V newNode, final int cmp){ if(cmp < 0){ if(_subsequent == null){ _subsequent = newNode; _size ++; }else{ _subsequent = _subsequent.add(newNode); if(_preceding == null){ return (V)rotateLeft(); } return (V)balance(); } }else if(cmp > 0 || newNode.duplicates()){ if(_preceding == null){ _preceding = newNode; _size ++; }else{ _preceding = _preceding.add(newNode); if(_subsequent == null){ return (V)rotateRight(); } return (V)balance(); } }else{ return (V)newNode.onAttemptToAddDuplicate(this); } return (V)this; } /** * On adding a node to a tree, if it already exists, and if * Tree#duplicates() returns false, #onAttemptToAddDuplicate() * will be called and the existing node will be stored in * this._preceding. * This node node can then be asked for the node that prevails * in the tree on adding, using the #addedOrExisting() method. * This mechanism allows doing find() and add() in one run. */ public Tree addedOrExisting(){ if(wasAddedToTree()){ return this; } return _preceding; } public boolean wasAddedToTree(){ return _size != 0; } public final Tree balance(){ int cmp = _subsequent.nodes() - _preceding.nodes(); if(cmp < -2){ return rotateRight(); }else if(cmp > 2){ return rotateLeft(); }else{ setSizeOwnPrecedingSubsequent(); return this; } } public Tree balanceCheckNulls(){ if(_subsequent == null){ if(_preceding == null){ setSizeOwn(); return this; } return rotateRight(); }else if(_preceding == null){ return rotateLeft(); } return balance(); } public void calculateSize(){ if(_preceding == null){ if (_subsequent == null){ setSizeOwn(); }else{ setSizeOwnSubsequent(); } }else{ if(_subsequent == null){ setSizeOwnPreceding(); }else{ setSizeOwnPrecedingSubsequent(); } } } /** * returns 0, if keys are equal * uses this - other * returns positive if this is greater than a_to * returns negative if this is smaller than a_to */ public abstract int compare(Tree a_to); public static Tree deepClone(Tree a_tree, Object a_param){ if(a_tree == null){ return null; } Tree newNode = (Tree)a_tree.deepClone(a_param); newNode._size = a_tree._size; newNode._preceding = Tree.deepClone(a_tree._preceding, a_param); newNode._subsequent = Tree.deepClone(a_tree._subsequent, a_param); return newNode; } public Object deepClone(Object a_param){ return shallowClone(); } public boolean duplicates(){ return true; } public final Tree filter(final Predicate4 a_filter){ if(_preceding != null){ _preceding = _preceding.filter(a_filter); } if(_subsequent != null){ _subsequent = _subsequent.filter(a_filter); } if(! a_filter.match(this)){ return remove(); } return this; } public static final <T> Tree<T> find(Tree<T> inTree, Tree<T> template){ if(inTree == null){ return null; } return inTree.find(template); } public final Tree<T> find(final Tree<T> template){ Tree current = this; while(true){ int comparisonResult = current.compare(template); if(comparisonResult == 0){ return current; } if(comparisonResult < 0){ current = current._subsequent; } else { current = current._preceding; } if(current == null){ return null; } } } public static final Tree findGreaterOrEqual(Tree a_in, Tree a_finder){ if(a_in == null){ return null; } int cmp = a_in.compare(a_finder); if(cmp == 0){ return a_in; // the highest node in the hierarchy !!! } if(cmp > 0){ Tree node = findGreaterOrEqual(a_in._preceding, a_finder); if(node != null){ return node; } return a_in; } return findGreaterOrEqual(a_in._subsequent, a_finder); } public final static Tree findSmaller(Tree a_in, Tree a_node){ if(a_in == null){ return null; } int cmp = a_in.compare(a_node); if(cmp < 0){ Tree node = findSmaller(a_in._subsequent, a_node); if(node != null){ return node; } return a_in; } return findSmaller(a_in._preceding, a_node); } public final Tree<T> first(){ if(_preceding == null){ return this; } return _preceding.first(); } public static Tree last(Tree tree){ if(tree == null){ return null; } return tree.last(); } public final Tree last(){ if(_subsequent == null){ return this; } return _subsequent.last(); } public Tree onAttemptToAddDuplicate(Tree oldNode){ _size = 0; _preceding = oldNode; return oldNode; } /** * @return the number of nodes in this tree for balancing */ public int nodes(){ return _size; } public int ownSize(){ return 1; } public Tree remove(){ if(_subsequent != null && _preceding != null){ _subsequent = _subsequent.rotateSmallestUp(); _subsequent._preceding = _preceding; _subsequent.calculateSize(); return _subsequent; } if(_subsequent != null){ return _subsequent; } return _preceding; } public void removeChildren(){ _preceding = null; _subsequent = null; setSizeOwn(); } public Tree removeFirst(){ if(_preceding == null){ return _subsequent; } _preceding = _preceding.removeFirst(); calculateSize(); return this; } public static Tree removeLike(Tree from, Tree a_find){ if(from == null){ return null; } return from.removeLike(a_find); } public final <V extends Tree<T>> V removeLike(final V a_find){ int cmp = compare(a_find); if(cmp == 0){ return (V)remove(); } if (cmp > 0){ if(_preceding != null){ _preceding = _preceding.removeLike(a_find); } }else{ if(_subsequent != null){ _subsequent = _subsequent.removeLike(a_find); } } calculateSize(); return (V)this; } public final Tree removeNode(final Tree a_tree){ if (this == a_tree){ return remove(); } int cmp = compare(a_tree); if (cmp >= 0){ if(_preceding != null){ _preceding = _preceding.removeNode(a_tree); } } if(cmp <= 0){ if(_subsequent != null){ _subsequent = _subsequent.removeNode(a_tree); } } calculateSize(); return this; } public final Tree rotateLeft(){ Tree tree = _subsequent; _subsequent = tree._preceding; calculateSize(); tree._preceding = this; if(tree._subsequent == null){ tree.setSizeOwnPlus(this); }else{ tree.setSizeOwnPlus(this, tree._subsequent); } return tree; } public final Tree rotateRight(){ Tree tree = _preceding; _preceding = tree._subsequent; calculateSize(); tree._subsequent = this; if(tree._preceding == null){ tree.setSizeOwnPlus(this); }else{ tree.setSizeOwnPlus(this, tree._preceding); } return tree; } private final Tree rotateSmallestUp(){ if(_preceding != null){ _preceding = _preceding.rotateSmallestUp(); return rotateRight(); } return this; } public final void setSizeOwn(){ _size = ownSize(); } public final void setSizeOwnPrecedingSubsequent(){ _size = ownSize() + _preceding._size + _subsequent._size; } public final void setSizeOwnPreceding(){ _size = ownSize() + _preceding._size; } public final void setSizeOwnSubsequent(){ _size = ownSize() + _subsequent._size; } public final void setSizeOwnPlus(Tree tree){ _size = ownSize() + tree._size; } public final void setSizeOwnPlus(Tree tree1, Tree tree2){ _size = ownSize() + tree1._size + tree2._size; } public static int size(Tree a_tree){ if(a_tree == null){ return 0; } return a_tree.size(); } /** * @return the number of objects represented. */ public int size(){ return _size; } public static final void traverse(Tree tree, Visitor4 visitor){ if(tree == null){ return; } tree.traverse(visitor); } /** * Traverses a tree with a starting point node. * If there is no exact match for the starting node, the next higher will be taken. */ public static void traverse(Tree tree, Tree startingNode, CancellableVisitor4 visitor) { if(tree == null){ return; } tree.traverse(startingNode, visitor); } private boolean traverse(Tree startingNode, CancellableVisitor4 visitor) { if(startingNode != null){ int cmp = compare(startingNode); if(cmp < 0){ if(_subsequent != null){ return _subsequent.traverse(startingNode, visitor); } return true; } else if (cmp > 0){ if(_preceding != null){ if(! _preceding.traverse(startingNode, visitor)){ return false; } } } } else { if(_preceding != null){ if(! _preceding.traverse(null, visitor)){ return false; } } } if(! visitor.visit(this)){ return false; } if(_subsequent != null){ if(! _subsequent.traverse(null, visitor)){ return false; } } return true; } public final <V extends Tree<T>> void traverse(final Visitor4<V> visitor){ if(_preceding != null){ _preceding.traverse(visitor); } visitor.visit((V)this); if(_subsequent != null){ _subsequent.traverse(visitor); } } public final void traverseFromLeaves(Visitor4 a_visitor){ if(_preceding != null){ _preceding.traverseFromLeaves(a_visitor); } if(_subsequent != null){ _subsequent.traverseFromLeaves(a_visitor); } a_visitor.visit(this); } // Keep the debug method to debug the depth // public final void debugLeafDepth(int currentDepth){ // currentDepth++; // if(_preceding == null && _subsequent == null){ // System.out.println("" + currentDepth + " tree leaf depth."); // return; // } // if (_preceding != null){ // _preceding.debugLeafDepth(currentDepth); // } // if(_subsequent != null){ // _subsequent.debugLeafDepth(currentDepth); // } // } protected Tree shallowCloneInternal(Tree tree) { tree._preceding=_preceding; tree._size=_size; tree._subsequent=_subsequent; return tree; } public Object shallowClone() { throw new com.db4o.foundation.NotImplementedException(); } public abstract T key(); public Object root() { return this; } public void accept(final Visitor4<T> visitor){ traverse(new Visitor4() { public void visit(Object obj) { Tree<T> tree = (Tree)obj; visitor.visit(tree.key()); } } ); } public static int depth(Tree tree) { if(tree == null) { return 0; } return Math.max(depth(tree._preceding), depth(tree._subsequent)) + 1; } }