/*******************************************************************************
- * Copyright (c) 2011, 2012 Ericsson
+ * Copyright (c) 2011, 2013 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* Yann N. Dauphin <dhaemon@gmail.com> - Implementation for stats
* Francois Godin <copelnug@gmail.com> - Re-design for new stats structure
* Mathieu Denis <mathieu.denis@polymtl.ca> - Re-design for new stats structure (2)
+ * Alexandre Montplaisir - Move the tree structure logic into the nodes
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.viewers.statistics.model;
+import java.util.Arrays;
import java.util.Collection;
-
-import org.eclipse.linuxtools.tmf.core.util.TmfFixedArray;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* A tree where nodes can be accessed efficiently using paths.
*
* It works like file systems. Each node is identified by a key. A path is an
- * array ({@link TmfFixedArray}) of String. The elements of the array represent
- * the path from the root to this node.
+ * array of String. The elements of the array represent the path from the root
+ * to this node.
*
+ * @author Mathieu Denis
* @version 2.0
* @since 2.0
- * @author Mathieu Denis
*/
public class TmfStatisticsTreeNode {
- /**
- * Value of the node.
- */
- protected TmfStatisticsValues fValues;
+ /** Tree to which this node belongs */
+ private final TmfStatisticsTree fTree;
- /**
- * Path of the node.
- */
- protected TmfFixedArray<String> fPath;
+ /** Path of this node. The last element represents its basename. */
+ private final String[] fPath;
+
+ /** Parent node */
+ private final TmfStatisticsTreeNode fParent;
+
+ /** Children of this node, indexed by their basename. */
+ private final Map<String, TmfStatisticsTreeNode> fChildren;
+
+ /** Statistics values associated to this node. */
+ private final TmfStatisticsValues fValues;
/**
- * Corresponding StatisticsData.
+ * Return the node at the top of the branch
*/
- protected AbsTmfStatisticsTree fNodes;
+ private final TmfStatisticsTreeNode fTopNode;
/**
* Constructor.
*
+ * @param tree
+ * Owner tree of this node
+ * @param parent
+ * Parent node of this one
* @param path
* Path to the node.
- * @param nodes
- * Corresponding StatisticsData.
*/
- public TmfStatisticsTreeNode(final TmfFixedArray<String> path,
- AbsTmfStatisticsTree nodes) {
+ public TmfStatisticsTreeNode(TmfStatisticsTree tree,
+ TmfStatisticsTreeNode parent, final String... path) {
+ /*
+ * The path must not contain any null element, or else we won't be able
+ * to walk the tree.
+ */
+ for (String elem : path) {
+ if (elem == null) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ fTree = tree;
fPath = path;
- fNodes = nodes;
+ fParent = parent;
+ fChildren = new ConcurrentHashMap<>();
fValues = new TmfStatisticsValues();
+
+ /* calculating top node */
+ TmfStatisticsTreeNode topNode = this;
+ while (topNode.getParent() != null && topNode.getParent().getParent() != null) {
+ topNode = topNode.getParent();
+ }
+ fTopNode = topNode;
+ }
+
+ /**
+ * Get the name for this node. It's used as the key in the parent's node.
+ *
+ * @return Name of this node.
+ */
+ public String getName() {
+ if (fPath.length == 0) {
+ /* This means we are the root node, which has no path itself */
+ return "root"; //$NON-NLS-1$
+ }
+ return fPath[fPath.length - 1];
}
/**
* Test if a node contain the specified child.
*
- * @param key
+ * @param childName
* Name of the child.
* @return true: if child with given key is present, false: if no child
* exists with given key name
*/
- public boolean containsChild(String key) {
- if (AbsTmfStatisticsTree.ROOT.equals(fPath)) {
- return fNodes.get(new TmfFixedArray<String>(key)) != null;
- }
- return (fNodes.get(fPath.append(key)) != null);
+ public boolean containsChild(String childName) {
+ return fChildren.containsKey(childName);
}
/**
- * Get the children of this node.
+ * Retrieve the given child from this node.
*
- * @return Direct children of this node.
+ * @param childName
+ * The (base)name of the child you want
+ * @return The child object, or null if it doesn't exist
*/
- public Collection<TmfStatisticsTreeNode> getChildren() {
- return fNodes.getChildren(fPath);
+ public TmfStatisticsTreeNode getChild(String childName) {
+ return fChildren.get(childName);
}
/**
- * Gets every children of this node even if no event has been registered for a node.
+ * Get the children of this node.
*
* @return Direct children of this node.
*/
- public Collection<TmfStatisticsTreeNode> getAllChildren() {
- return fNodes.getAllChildren(fPath);
+ public Collection<TmfStatisticsTreeNode> getChildren() {
+ return fChildren.values();
}
/**
- * Get the key for this node.
+ * Add a child to this node.
*
- * @return Key associated with this node.
- */
- public String getKey() {
- return fPath.get(fPath.size() - 1);
+ * @param childName
+ * Name of the child to add
+ * @return The newly-created child
+ */
+ public TmfStatisticsTreeNode addChild(String childName) {
+ TmfStatisticsTreeNode child;
+ String[] childPath = new String[fPath.length + 1];
+ System.arraycopy(fPath, 0, childPath, 0, fPath.length);
+ childPath[fPath.length] = childName;
+
+ child = new TmfStatisticsTreeNode(this.fTree, this, childPath);
+ fChildren.put(childName, child);
+ return child;
}
/**
* @return Number of direct children of this node.
*/
public int getNbChildren() {
- return fNodes.getChildren(fPath).size();
+ return fChildren.size();
}
/**
* @return Parent node.
*/
public TmfStatisticsTreeNode getParent() {
- return fNodes.getParent(fPath);
+ return fParent;
+ }
+
+ /**
+ * Return the top node.
+ *
+ * @return Top node.
+ * @since 3.0
+ */
+ public TmfStatisticsTreeNode getTop() {
+ return fTopNode;
}
/**
*
* @return The path of the node.
*/
- public TmfFixedArray<String> getPath() {
+ public String[] getPath() {
return fPath;
}
* @return True if the node has children.
*/
public boolean hasChildren() {
- return !fNodes.getChildren(fPath).isEmpty();
+ return (fChildren.size() > 0);
}
/**
* no children.
*/
public void reset() {
- fValues = new TmfStatisticsValues();
- fNodes.reset(fPath);
+ fValues.resetTotalCount();
+ fValues.resetPartialCount();
+ fChildren.clear();
}
/**
- * Resets the global number of events. It doesn't remove any node
- * and doesn't modify the partial event count.
- *
- * Works recursively.
+ * Resets the global number of events. It doesn't remove any node and
+ * doesn't modify the partial event count. Works recursively.
*
* @since 2.0
*/
public void resetGlobalValue() {
- getValues().resetTotalCount();
- fNodes.resetGlobalValue(fPath);
+ for (TmfStatisticsTreeNode child : fChildren.values()) {
+ child.resetGlobalValue();
+ }
+ fValues.resetTotalCount();
}
/**
* Resets the number of events in the time range. It doesn't remove any node
- * and doesn't modify the global event count.
- *
- * Works recursively.
+ * and doesn't modify the global event count. Works recursively.
*
* @since 2.0
*/
public void resetTimeRangeValue() {
- getValues().resetPartialCount();
- fNodes.resetTimeRangeValue(fPath);
+ for (TmfStatisticsTreeNode child : fChildren.values()) {
+ child.resetTimeRangeValue();
+ }
+ fValues.resetPartialCount();
+ }
+
+ @Override
+ public String toString() {
+ /* Used for debugging only */
+ return "Stats node, path = " + Arrays.toString(fPath) + //$NON-NLS-1$
+ ", values = " + fValues.toString(); //$NON-NLS-1$
}
}