/** * Replication Benchmarker * https://github.com/score-team/replication-benchmarker/ * Copyright (C) 2013 LORIA / Inria / SCORE Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 collect; import crdt.tree.TreeOperation; import java.io.Serializable; import java.util.*; /** * * @author score */ public class HashTree<T> extends Observable implements Tree<T>, Serializable { private NodeImpl<T> root; public HashTree() { root = createRoot(); } @Override public NodeImpl<T> getRoot() { return root; } @Override public NodeImpl<T> getNode(List<T> path) { NodeImpl<T> n = root; for (T t : path) { n = n.getChild(t); if (n == null) { return null; } } return n; } @Override public UnorderedNode<T> add(Node<T> father, T t) { if (father == null) { father = root; } NodeImpl<T> here = ((NodeImpl<T>) father).getChild(t); if (here != null) { return here; } if ((countObservers() > 0) && connected(father)) { setChanged(); notifyObservers(new TreeOperation<T>(father, t)); } return createNode(father, t); } @Override public NodeImpl<T> createOrphan(T t) { return createNode(null, t); } @Override public Iterator<? extends UnorderedNode<T>> getBFSIterator(Node<T> n) { if (n == null) { n = root; } // } else if (!contains(n)) { // throw new NoSuchElementException("Node not in tree"); // } return new BFSIterator((NodeImpl<T>) n); } @Override public Iterator<? extends UnorderedNode<T>> getDFSIterator(Node<T> n) { if (n == null) { n = root; } else if (!contains(n)) { throw new NoSuchElementException("Node not in tree"); } return new DFSIterator((NodeImpl<T>) n); } @Override public void remove(Node<T> n) { if (n == null || n == root) { throw new UnsupportedOperationException("Cannot remove root"); } NodeImpl<T> ni = (NodeImpl<T>)n; if (ni.getFather() != null) { NodeImpl<T> father = (NodeImpl<T>) ni.getFather(); // father.getChildren().remove(n.getValue()); if ((countObservers() > 0) && connected(father)) { setChanged(); notifyObservers(new TreeOperation<T>(TreeOperation.OpType.del, father, n.getValue())); } ni.setFather(null); } } @Override public boolean contains(Node<T> n) { if (n.getFather()==null){ return n==this.getRoot(); } return /*n.getFather().isChildren(n) &&*/ contains(n.getFather()); /* optimisation deleted du noeud détruit l'adresse du père*/ } @Override public void clear() { root.getChildren().clear(); this.root = createRoot(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof HashTree)) { return false; } return this.root.sameTree(((HashTree<T>) obj).root); } @Override public int hashCode() { int hash = 7; hash = 89 * hash + (this.root != null ? this.root.hashCode() : 0); return hash; } @Override public void move(Node<T> father, Node<T> node) { NodeImpl n=(NodeImpl) node; boolean move = false; Node f = null; if ((countObservers() > 0) && connected(node)) { move = true; f = n.getFather(); } n.setFather((NodeImpl)father); if ((countObservers() > 0) && connected(father)) { if (move) { // Move setChanged(); notifyObservers(new TreeOperation<T>(f, father, node.getValue())); } else { // Add subtree Iterator<? extends Node<T>> it = getBFSIterator(node); while (it.hasNext()) { Node<T> e = it.next(); setChanged(); notifyObservers(new TreeOperation<T>(e.getFather(), e.getValue())); } } } else if (move) { // Del setChanged(); notifyObservers(new TreeOperation<T>(f, node.getValue())); } } protected NodeImpl<T> createNode(Node<T> father, T t) { return new NodeImpl<T>((NodeImpl<T>)father, t); } protected NodeImpl<T> createRoot() { return new NodeImpl<T>(); } private boolean connected(Node<T> father) { while (father != root && father != null) { father = father.getFather(); } return (father == root); } class DFSIterator<T> implements Iterator { Stack<Iterator<? extends Node<T>>> pile; Node<T> next; DFSIterator(NodeImpl<T> node) { pile = new Stack<Iterator<? extends Node<T>>>(); next = node; } @Override public boolean hasNext() { return next != null; } @Override public Node<T> next() { Node<T> ret; if (next == null) { throw new NoSuchElementException(); } //Iterator <?extends Node<T>> it=next.iterator(); pile.push(next.iterator()); ret = next; while (!pile.empty() && !pile.peek().hasNext()) { pile.pop(); } next = pile.empty() ? null : pile.peek().next(); return ret; } @Override public void remove() { throw new UnsupportedOperationException("Remove is not supported yet."); } } class BFSIterator<T> implements Iterator { LinkedList<Iterator<? extends Node<T>>> file; Node<T> next; BFSIterator(NodeImpl<T> node) { file = new LinkedList<Iterator<? extends Node<T>>>(); next = node; } @Override public boolean hasNext() { return next != null; } @Override public Node<T> next() { Node<T> ret; if (next == null) { throw new NoSuchElementException(); } //Iterator <?extends Node<T>> it=next.iterator(); file.addFirst(next.iterator()); ret = next; while (!file.isEmpty() && !file.peekLast().hasNext()) { file.removeLast(); } next = file.isEmpty() ? null : file.peekLast().next(); return ret; } @Override public void remove() { throw new UnsupportedOperationException("Remove is not supported yet."); } } @Override public String toString() { return "HashTree{" + "root=" + root + '}'; } }